@ai-matrx/vault 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -101,10 +101,10 @@ var init_keepass_xml_worker_client = __esm({
101
101
  });
102
102
 
103
103
  // src/VaultApp.tsx
104
- import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as useState40 } from "react";
105
- import { DropdownMenu as DropdownMenu6, DropdownMenuContent as DropdownMenuContent6, DropdownMenuItem as DropdownMenuItem5, DropdownMenuTrigger as DropdownMenuTrigger6, LookScope } from "@ai-matrx/design-system";
106
- import { Button as Button33, SearchField as SearchField4, Select as Select11 } from "@ai-matrx/design-system/controls";
107
- import { confirm as confirm13 } from "@ai-matrx/kit/confirm-opener";
104
+ import { useCallback as useCallback5, useEffect as useEffect23, useMemo as useMemo6, useRef as useRef19, useState as useState41 } from "react";
105
+ import { DropdownMenu as DropdownMenu6, DropdownMenuContent as DropdownMenuContent6, DropdownMenuItem as DropdownMenuItem6, DropdownMenuTrigger as DropdownMenuTrigger6, LookScope } from "@ai-matrx/design-system";
106
+ import { Button as Button34, SearchField as SearchField4, Select as Select12 } from "@ai-matrx/design-system/controls";
107
+ import { confirm as confirm14 } from "@ai-matrx/kit/confirm-opener";
108
108
 
109
109
  // src/notice.tsx
110
110
  import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
@@ -638,12 +638,12 @@ var ROW_GRID = {
638
638
  roomy: "grid-cols-[9rem_minmax(0,1fr)_auto] gap-x-3 px-4",
639
639
  viewport: "grid-cols-[5.75rem_minmax(0,1fr)_auto] gap-x-2 px-3 sm:grid-cols-[9rem_minmax(0,1fr)_auto] sm:gap-x-3 sm:px-4"
640
640
  };
641
- function VaultRow({ label, hint, children, actions, top = false, className }) {
641
+ function VaultRow({ label, hint: hint2, children, actions, top = false, className }) {
642
642
  const room = useContext4(Room);
643
643
  return /* @__PURE__ */ jsxs4("div", { className: cn2("grid min-h-11 py-1", ROW_GRID[room ?? "viewport"], top ? "items-start" : "items-center", className), children: [
644
644
  /* @__PURE__ */ jsxs4("div", { className: cn2("flex min-w-0 flex-col text-xs leading-tight text-muted-foreground", top && "pt-2.5"), children: [
645
645
  /* @__PURE__ */ jsx4("span", { className: room === "roomy" ? "truncate" : room === "compact" ? "line-clamp-2 break-words" : "line-clamp-2 break-words sm:truncate", children: label }),
646
- hint ? /* @__PURE__ */ jsx4("span", { className: "line-clamp-2 break-words text-xs text-disabled-foreground", children: hint }) : null
646
+ hint2 ? /* @__PURE__ */ jsx4("span", { className: "line-clamp-2 break-words text-xs text-disabled-foreground", children: hint2 }) : null
647
647
  ] }),
648
648
  /* @__PURE__ */ jsx4("div", { className: cn2("min-w-0 text-sm", top && "py-1.5"), children }),
649
649
  /* @__PURE__ */ jsx4("div", { className: cn2("flex items-center gap-0.5", top && "pt-1"), children: actions })
@@ -753,14 +753,14 @@ function TurnOnButton({ label, onTurnOn }) {
753
753
  }
754
754
  );
755
755
  }
756
- function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
756
+ function PlainRow({ label, value, hint: hint2, openUrl, extra, multiline = false }) {
757
757
  const copyValue2 = useCopy();
758
758
  const isUrl = /^https?:\/\//i.test(value);
759
759
  return /* @__PURE__ */ jsx5(
760
760
  VaultRow,
761
761
  {
762
762
  label,
763
- hint,
763
+ hint: hint2,
764
764
  top: multiline,
765
765
  actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
766
766
  extra,
@@ -790,13 +790,13 @@ function PlainRow({ label, value, hint, openUrl, extra, multiline = false }) {
790
790
  function AddRow({ label, onAdd, children = "Add" }) {
791
791
  return /* @__PURE__ */ jsx5(VaultRow, { label, children: onAdd ? /* @__PURE__ */ jsx5("button", { type: "button", className: "text-sm text-muted-foreground hover:text-primary", onClick: onAdd, children }) : /* @__PURE__ */ jsx5("span", { className: "text-disabled-foreground", children: "\u2014" }) });
792
792
  }
793
- function EditRow({ label, hint, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
793
+ function EditRow({ label, hint: hint2, value, onChange, placeholder, secret = false, multiline = false, onRemove, removeLabel, actions, autoFocus, onBlur, inputMode }) {
794
794
  const [shown, setShown] = useState5(false);
795
795
  return /* @__PURE__ */ jsx5(
796
796
  VaultRow,
797
797
  {
798
798
  label,
799
- hint,
799
+ hint: hint2,
800
800
  top: multiline,
801
801
  actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
802
802
  secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((s) => !s) }) : null,
@@ -807,7 +807,7 @@ function EditRow({ label, hint, value, onChange, placeholder, secret = false, mu
807
807
  }
808
808
  );
809
809
  }
810
- function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
810
+ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove, extra, onPasteValue }) {
811
811
  const [shown, setShown] = useState5(false);
812
812
  return /* @__PURE__ */ jsx5(
813
813
  VaultRow,
@@ -815,9 +815,25 @@ function CustomEditRow({ label, value, onLabel, onValue, secret, onRemove }) {
815
815
  label: /* @__PURE__ */ jsx5(Field2, { className: "w-full", value: label, onChange: (e) => onLabel(e.target.value), placeholder: "Name", "aria-label": "Field name" }),
816
816
  actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
817
817
  secret && value ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: shown ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": shown ? "Hide" : "Show", onClick: () => setShown((x) => !x) }) : null,
818
+ extra,
818
819
  /* @__PURE__ */ jsx5(Button2, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx5(XGlyph, {}), "aria-label": "Remove field", onClick: onRemove })
819
820
  ] }),
820
- children: /* @__PURE__ */ jsx5(Field2, { className: "w-full", value, onChange: (e) => onValue(e.target.value), type: secret && !shown ? "password" : "text", placeholder: secret ? "Secret value" : "Value", autoComplete: "off", spellCheck: false, "aria-label": "Field value" })
821
+ children: /* @__PURE__ */ jsx5(
822
+ Field2,
823
+ {
824
+ className: "w-full",
825
+ value,
826
+ onChange: (e) => onValue(e.target.value),
827
+ onPaste: onPasteValue ? (e) => {
828
+ if (onPasteValue(e.clipboardData.getData("text"))) e.preventDefault();
829
+ } : void 0,
830
+ type: secret && !shown ? "password" : "text",
831
+ placeholder: secret ? "Secret value" : "Value",
832
+ autoComplete: "off",
833
+ spellCheck: false,
834
+ "aria-label": label ? `${label} value` : "Field value"
835
+ }
836
+ )
821
837
  }
822
838
  );
823
839
  }
@@ -831,7 +847,7 @@ import { formatRelativeTime } from "@ai-matrx/kit/format";
831
847
 
832
848
  // src/model.ts
833
849
  var DEFAULT_LOCATION = { vault: "all", view: "all", q: "", sort: "name", itemId: null, mode: "view", kind: null, url: "", panel: null };
834
- var SORTS = ["name", "website", "updated", "created"];
850
+ var SORTS = ["name", "name-desc", "website", "updated", "created", "viewed"];
835
851
  function locationFromParams(params, itemId = params.get("item")) {
836
852
  const sort = params.get("sort");
837
853
  const mode = params.get("mode");
@@ -871,9 +887,11 @@ function inView(item, view) {
871
887
  if (view.startsWith("tag:")) return item.tags.includes(view.slice(4));
872
888
  return true;
873
889
  }
890
+ var AUTHENTICATOR_WORDS = ["authenticator", "2fa", "two-factor", "two factor", "totp", "one-time password", "verification code", "2-step"];
874
891
  function matchesQuery(item, query) {
875
892
  const q = query.trim().toLowerCase();
876
893
  if (!q) return true;
894
+ if (item.authenticator && AUTHENTICATOR_WORDS.some((w) => w === q || q.length >= 3 && w.startsWith(q))) return true;
877
895
  return [item.name, item.definitionLabel, ...item.tags, ...item.loginUrls, ...item.custom.map((c) => `${c.label} ${c.value}`)].some((h) => h.toLowerCase().includes(q));
878
896
  }
879
897
  var HIDDEN_ITEM_TAG = "matrx:hidden";
@@ -899,10 +917,15 @@ function siteDomainOf(host) {
899
917
  const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
900
918
  return labels.slice(-keep).join(".");
901
919
  }
902
- function sortItems(items, sort) {
920
+ function sortItems(items, sort, recents) {
903
921
  const out = [...items];
904
- const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
922
+ const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base", numeric: true });
905
923
  if (sort === "name") return out.sort(byName);
924
+ if (sort === "name-desc") return out.sort((a, b) => byName(b, a));
925
+ if (sort === "viewed") {
926
+ const at = new Map((recents ?? []).map((id, i) => [id, i]));
927
+ return out.sort((a, b) => (at.get(a.id) ?? Infinity) - (at.get(b.id) ?? Infinity) || byName(a, b));
928
+ }
906
929
  if (sort === "website")
907
930
  return out.sort((a, b) => {
908
931
  const x = loginSiteOf(a), y = loginSiteOf(b);
@@ -1499,9 +1522,23 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
1499
1522
  // src/authenticator/AuthenticatorView.tsx
1500
1523
  import { useEffect as useEffect11, useState as useState13 } from "react";
1501
1524
  import { Button as Button9 } from "@ai-matrx/design-system/controls";
1502
- import { cn as cn6, DropdownMenu as DropdownMenu2, DropdownMenuContent as DropdownMenuContent2, DropdownMenuItem as DropdownMenuItem2, DropdownMenuSeparator as DropdownMenuSeparator2, DropdownMenuTrigger as DropdownMenuTrigger2, TextInputDialog } from "@ai-matrx/design-system";
1525
+ import { cn as cn7, DropdownMenu as DropdownMenu2, DropdownMenuContent as DropdownMenuContent2, DropdownMenuItem as DropdownMenuItem2, DropdownMenuSeparator as DropdownMenuSeparator2, DropdownMenuTrigger as DropdownMenuTrigger2, TextInputDialog } from "@ai-matrx/design-system";
1503
1526
  import { CopyIcon as CopyIcon4 } from "@ai-matrx/design-system/icons";
1504
1527
 
1528
+ // src/ItemIcon.tsx
1529
+ import { cn as cn5 } from "@ai-matrx/design-system";
1530
+ import { jsx as jsx8 } from "react/jsx-runtime";
1531
+ function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
1532
+ const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
1533
+ const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
1534
+ const initial = siteDomainOf(site).charAt(0).toUpperCase();
1535
+ if (initial && /[A-Z0-9]/.test(initial)) {
1536
+ return /* @__PURE__ */ jsx8("span", { "aria-hidden": true, className: cn5("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
1537
+ }
1538
+ const Glyph = definitionGlyph(definitionKey, family);
1539
+ return /* @__PURE__ */ jsx8("span", { "aria-hidden": true, className: cn5("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ jsx8(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
1540
+ }
1541
+
1505
1542
  // src/authenticator/AddOtpPanel.tsx
1506
1543
  import { useState as useState12 } from "react";
1507
1544
  import { Button as Button8, Field as Field4, Select as Select2 } from "@ai-matrx/design-system/controls";
@@ -1509,7 +1546,7 @@ import { Button as Button8, Field as Field4, Select as Select2 } from "@ai-matrx
1509
1546
  // src/authenticator/CodeParts.tsx
1510
1547
  import { useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
1511
1548
  import { Button as Button5 } from "@ai-matrx/design-system/controls";
1512
- import { cn as cn5 } from "@ai-matrx/design-system";
1549
+ import { cn as cn6 } from "@ai-matrx/design-system";
1513
1550
  import { CopyIcon as CopyIcon3 } from "@ai-matrx/design-system/icons";
1514
1551
  import { groupCode as groupCode2 } from "@ai-matrx/kit/format";
1515
1552
 
@@ -1612,16 +1649,16 @@ function matchIssuerToSite(issuer, candidates, siteOf) {
1612
1649
  }
1613
1650
 
1614
1651
  // src/authenticator/CodeParts.tsx
1615
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1652
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1616
1653
  function CountdownRing({ remaining, period, loading = false, className }) {
1617
1654
  const r = 9.5;
1618
1655
  const c = 2 * Math.PI * r;
1619
1656
  const p = loading ? 0 : Math.max(0, Math.min(1, remaining / period));
1620
1657
  const urgent = !loading && remaining <= 5;
1621
- return /* @__PURE__ */ jsxs8("span", { className: cn5("relative inline-flex size-6 shrink-0 items-center justify-center", className), role: "img", "aria-label": loading ? "Getting code" : `${remaining} seconds left`, children: [
1658
+ return /* @__PURE__ */ jsxs8("span", { className: cn6("relative inline-flex size-6 shrink-0 items-center justify-center", className), role: "img", "aria-label": loading ? "Getting code" : `${remaining} seconds left`, children: [
1622
1659
  /* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 24 24", className: "absolute inset-0 size-full -rotate-90", "aria-hidden": true, children: [
1623
- /* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r, fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "text-muted" }),
1624
- /* @__PURE__ */ jsx8(
1660
+ /* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r, fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "text-muted" }),
1661
+ /* @__PURE__ */ jsx9(
1625
1662
  "circle",
1626
1663
  {
1627
1664
  cx: "12",
@@ -1638,7 +1675,7 @@ function CountdownRing({ remaining, period, loading = false, className }) {
1638
1675
  }
1639
1676
  )
1640
1677
  ] }),
1641
- /* @__PURE__ */ jsx8("span", { className: cn5("text-[10px] font-semibold leading-none tabular-nums", urgent ? "text-destructive" : "text-muted-foreground"), children: loading ? "" : remaining })
1678
+ /* @__PURE__ */ jsx9("span", { className: cn6("text-[10px] font-semibold leading-none tabular-nums", urgent ? "text-destructive" : "text-muted-foreground"), children: loading ? "" : remaining })
1642
1679
  ] });
1643
1680
  }
1644
1681
  function useCopied() {
@@ -1668,17 +1705,17 @@ function CodeButton({ live, digits, size = "md", label }) {
1668
1705
  onClick: () => live.code && void copy(live.code),
1669
1706
  "aria-label": live.code ? `Copy ${label} code` : `Getting ${label} code`,
1670
1707
  title: live.code ? "Copy" : void 0,
1671
- className: cn5("group -mx-1.5 inline-flex max-w-full items-center gap-2.5 rounded-md px-1.5 py-1 text-left transition-colors hover:bg-accent focus-visible:bg-accent focus-visible:outline-none", size === "lg" && "gap-3"),
1708
+ className: cn6("group -mx-1.5 inline-flex max-w-full items-center gap-2.5 rounded-md px-1.5 py-1 text-left transition-colors hover:bg-accent focus-visible:bg-accent focus-visible:outline-none", size === "lg" && "gap-3"),
1672
1709
  children: [
1673
- /* @__PURE__ */ jsx8("span", { className: cn5("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
1674
- copied ? /* @__PURE__ */ jsx8("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ jsx8(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ jsx8(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1710
+ /* @__PURE__ */ jsx9("span", { className: cn6("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
1711
+ copied ? /* @__PURE__ */ jsx9("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ jsx9(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ jsx9(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1675
1712
  ]
1676
1713
  }
1677
1714
  );
1678
1715
  }
1679
1716
  function CopyCodeButton({ live, label }) {
1680
1717
  const { copied, copy } = useCopied();
1681
- return /* @__PURE__ */ jsx8(Button5, { variant: "quiet", icon: copied ? /* @__PURE__ */ jsx8(CheckGlyph, {}) : /* @__PURE__ */ jsx8(CopyIcon3, {}), ...copied ? { glyphTone: "success" } : {}, "aria-label": `Copy ${label} code`, disabled: !live.code, onClick: () => live.code && void copy(live.code) });
1718
+ return /* @__PURE__ */ jsx9(Button5, { variant: "quiet", icon: copied ? /* @__PURE__ */ jsx9(CheckGlyph, {}) : /* @__PURE__ */ jsx9(CopyIcon3, {}), ...copied ? { glyphTone: "success" } : {}, "aria-label": `Copy ${label} code`, disabled: !live.code, onClick: () => live.code && void copy(live.code) });
1682
1719
  }
1683
1720
 
1684
1721
  // src/authenticator/live-code.ts
@@ -1770,42 +1807,23 @@ import { useEffect as useEffect10, useRef as useRef8, useState as useState10 } f
1770
1807
  import { Button as Button6, Field as Field3 } from "@ai-matrx/design-system/controls";
1771
1808
 
1772
1809
  // src/authenticator/qr.ts
1773
- function detectorCtor() {
1774
- const c = globalThis.BarcodeDetector;
1775
- return typeof c === "function" ? c : null;
1776
- }
1777
- var support = null;
1810
+ import { decodeQrFromElement, decodeQrFromImageFile } from "@ai-matrx/capture/qr";
1778
1811
  function canDecodeQrLocally() {
1779
- if (!support) {
1780
- const C = detectorCtor();
1781
- support = !C ? Promise.resolve(false) : C.getSupportedFormats ? C.getSupportedFormats().then((f) => f.includes("qr_code"), () => false) : Promise.resolve(true);
1812
+ if (typeof document === "undefined") return Promise.resolve(false);
1813
+ try {
1814
+ return Promise.resolve(Boolean(document.createElement("canvas").getContext("2d")));
1815
+ } catch {
1816
+ return Promise.resolve(false);
1782
1817
  }
1783
- return support;
1784
1818
  }
1785
1819
  function hasCamera() {
1786
1820
  return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
1787
1821
  }
1788
- var detector = null;
1789
- function qrDetector() {
1790
- const C = detectorCtor();
1791
- if (!C) return null;
1792
- detector ??= new C({ formats: ["qr_code"] });
1793
- return detector;
1794
- }
1795
1822
  async function decodeQr(source) {
1796
- const d = qrDetector();
1797
- if (!d) return null;
1798
- const found = await d.detect(source);
1799
- return found.find((b) => b.rawValue)?.rawValue ?? null;
1823
+ return decodeQrFromElement(source);
1800
1824
  }
1801
1825
  async function decodeQrFile(file) {
1802
- if (!await canDecodeQrLocally()) return null;
1803
- const bitmap = await createImageBitmap(file);
1804
- try {
1805
- return await decodeQr(bitmap);
1806
- } finally {
1807
- bitmap.close();
1808
- }
1826
+ return decodeQrFromImageFile(file);
1809
1827
  }
1810
1828
  function imageFrom(data) {
1811
1829
  if (!data) return null;
@@ -1820,7 +1838,7 @@ function imageFrom(data) {
1820
1838
  }
1821
1839
 
1822
1840
  // src/authenticator/Setup.tsx
1823
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1841
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1824
1842
  function useCanScan() {
1825
1843
  const [ok, setOk] = useState10(false);
1826
1844
  useEffect10(() => {
@@ -1886,15 +1904,15 @@ function QrScanPanel({ open, onResult, onClose }) {
1886
1904
  stop();
1887
1905
  };
1888
1906
  }, [open]);
1889
- return /* @__PURE__ */ jsxs9(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ jsx9(Button6, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
1907
+ return /* @__PURE__ */ jsxs9(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ jsx10(Button6, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
1890
1908
  /* @__PURE__ */ jsxs9("div", { className: "relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl bg-muted", children: [
1891
- /* @__PURE__ */ jsx9("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
1892
- error ? /* @__PURE__ */ jsx9("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ jsx9("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1909
+ /* @__PURE__ */ jsx10("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
1910
+ error ? /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ jsx10("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1893
1911
  ] }),
1894
- /* @__PURE__ */ jsx9("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
1912
+ /* @__PURE__ */ jsx10("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
1895
1913
  ] });
1896
1914
  }
1897
- function OtpSetupRow({ value, onChange, label = "One-time password", placeholder = "Setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status }) {
1915
+ function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status }) {
1898
1916
  const file = useRef8(null);
1899
1917
  const canScan = useCanScan();
1900
1918
  const [scanning, setScanning] = useState10(false);
@@ -1927,9 +1945,9 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
1927
1945
  setReading(false);
1928
1946
  }
1929
1947
  };
1930
- const end = status ? /* @__PURE__ */ jsx9("span", { className: "max-w-48 truncate text-xs text-muted-foreground", children: status }) : reading ? /* @__PURE__ */ jsx9("span", { className: "text-xs text-muted-foreground", children: "Reading\u2026" }) : imageError || error ? /* @__PURE__ */ jsx9("span", { className: "max-w-56 truncate text-xs text-destructive", title: imageError ?? error ?? void 0, role: "alert", children: imageError ?? error }) : parsed ? /* @__PURE__ */ jsxs9("span", { className: "flex max-w-56 items-center gap-1 text-xs text-success", children: [
1931
- /* @__PURE__ */ jsx9(CheckGlyph, { className: "size-3.5 shrink-0" }),
1932
- /* @__PURE__ */ jsx9("span", { className: "truncate", children: describeEnrollment(parsed) })
1948
+ const end = status ? /* @__PURE__ */ jsx10("span", { className: "max-w-48 truncate text-xs text-muted-foreground", children: status }) : reading ? /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: "Reading\u2026" }) : imageError || error ? /* @__PURE__ */ jsx10("span", { className: "max-w-56 truncate text-xs text-destructive", title: imageError ?? error ?? void 0, role: "alert", children: imageError ?? error }) : parsed ? /* @__PURE__ */ jsxs9("span", { className: "flex max-w-56 items-center gap-1 text-xs text-success", children: [
1949
+ /* @__PURE__ */ jsx10(CheckGlyph, { className: "size-3.5 shrink-0" }),
1950
+ /* @__PURE__ */ jsx10("span", { className: "truncate", children: describeEnrollment(parsed) })
1933
1951
  ] }) : null;
1934
1952
  return /* @__PURE__ */ jsxs9(
1935
1953
  "div",
@@ -1954,11 +1972,11 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
1954
1972
  {
1955
1973
  label,
1956
1974
  actions: /* @__PURE__ */ jsxs9(Fragment5, { children: [
1957
- /* @__PURE__ */ jsx9(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx9(QrGlyph, {}), "aria-label": "Choose QR image", title: "Choose or drop a QR image", disabled: disabled || reading, onClick: () => file.current?.click() }),
1958
- canScan ? /* @__PURE__ */ jsx9(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx9(CameraGlyph, {}), "aria-label": "Scan with camera", title: "Scan with camera", disabled, onClick: () => setScanning(true) }) : null
1975
+ /* @__PURE__ */ jsx10(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx10(QrGlyph, {}), "aria-label": "Choose QR image", title: "Choose or drop a QR image", disabled: disabled || reading, onClick: () => file.current?.click() }),
1976
+ canScan ? /* @__PURE__ */ jsx10(Button6, { variant: "quiet", icon: /* @__PURE__ */ jsx10(CameraGlyph, {}), "aria-label": "Scan QR code with camera", title: "Scan the site's QR code with the camera", disabled, onClick: () => setScanning(true), children: "Scan" }) : null
1959
1977
  ] }),
1960
1978
  children: [
1961
- /* @__PURE__ */ jsx9(
1979
+ /* @__PURE__ */ jsx10(
1962
1980
  Field3,
1963
1981
  {
1964
1982
  className: "w-full",
@@ -1981,7 +1999,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
1981
1999
  end
1982
2000
  }
1983
2001
  ),
1984
- /* @__PURE__ */ jsx9(
2002
+ /* @__PURE__ */ jsx10(
1985
2003
  "input",
1986
2004
  {
1987
2005
  ref: file,
@@ -1998,7 +2016,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
1998
2016
  ]
1999
2017
  }
2000
2018
  ),
2001
- canScan ? /* @__PURE__ */ jsx9(
2019
+ canScan ? /* @__PURE__ */ jsx10(
2002
2020
  QrScanPanel,
2003
2021
  {
2004
2022
  open: scanning,
@@ -2029,7 +2047,7 @@ function mfaMethodOf(item) {
2029
2047
  }
2030
2048
 
2031
2049
  // src/authenticator/TotpRows.tsx
2032
- import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2050
+ import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2033
2051
  function otpActionError(e, what) {
2034
2052
  const status = e?.status;
2035
2053
  if (status === 404) return "There is no one-time password here.";
@@ -2067,7 +2085,7 @@ function useOtpActions(port, item, onChanged) {
2067
2085
  }),
2068
2086
  remove: async () => {
2069
2087
  const ok = await confirm2({
2070
- title: `Remove the one-time password for ${item.name}?`,
2088
+ title: `Remove the authenticator for ${item.name}?`,
2071
2089
  description: "Codes stop here. Two-factor stays on at the site, and your phone app and backup codes still work.",
2072
2090
  confirmLabel: "Remove",
2073
2091
  variant: "destructive"
@@ -2087,37 +2105,37 @@ function TotpRow({ port, item, onChanged }) {
2087
2105
  const canManage = item.capabilities.canManage || item.capabilities.canEdit;
2088
2106
  if (a.removed || !item.authenticator) return null;
2089
2107
  const menu = canManage ? /* @__PURE__ */ jsxs10(DropdownMenu, { children: [
2090
- /* @__PURE__ */ jsx10(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx10(MoreGlyph, {}), "aria-label": "One-time password options", disabled: a.busy }) }),
2108
+ /* @__PURE__ */ jsx11(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx11(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx11(MoreGlyph, {}), "aria-label": "Authenticator options", disabled: a.busy }) }),
2091
2109
  /* @__PURE__ */ jsxs10(DropdownMenuContent, { align: "end", className: "min-w-44", children: [
2092
2110
  /* @__PURE__ */ jsxs10(DropdownMenuItem, { onSelect: () => void a.setEnabled(!a.enabled), children: [
2093
- /* @__PURE__ */ jsx10(PowerGlyph, { className: "size-4" }),
2111
+ /* @__PURE__ */ jsx11(PowerGlyph, { className: "size-4" }),
2094
2112
  a.enabled ? "Turn off" : "Turn on"
2095
2113
  ] }),
2096
- /* @__PURE__ */ jsx10(DropdownMenuSeparator, {}),
2114
+ /* @__PURE__ */ jsx11(DropdownMenuSeparator, {}),
2097
2115
  /* @__PURE__ */ jsxs10(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
2098
- /* @__PURE__ */ jsx10(TrashGlyph, { className: "size-4" }),
2116
+ /* @__PURE__ */ jsx11(TrashGlyph, { className: "size-4" }),
2099
2117
  "Remove"
2100
2118
  ] })
2101
2119
  ] })
2102
2120
  ] }) : null;
2103
- return /* @__PURE__ */ jsx10(
2121
+ return /* @__PURE__ */ jsx11(
2104
2122
  VaultRow,
2105
2123
  {
2106
- label: "One-time password",
2124
+ label: "Authenticator",
2107
2125
  actions: /* @__PURE__ */ jsxs10(Fragment6, { children: [
2108
- a.enabled ? /* @__PURE__ */ jsx10(CopyCodeButton, { live, label: item.name }) : null,
2126
+ a.enabled ? /* @__PURE__ */ jsx11(CopyCodeButton, { live, label: item.name }) : null,
2109
2127
  menu
2110
2128
  ] }),
2111
2129
  children: a.error ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
2112
- /* @__PURE__ */ jsx10("span", { className: "truncate text-sm text-destructive", role: "alert", children: a.error }),
2113
- /* @__PURE__ */ jsx10(Button7, { variant: "quiet", onClick: a.clearError, children: "Dismiss" })
2130
+ /* @__PURE__ */ jsx11("span", { className: "truncate text-sm text-destructive", role: "alert", children: a.error }),
2131
+ /* @__PURE__ */ jsx11(Button7, { variant: "quiet", onClick: a.clearError, children: "Dismiss" })
2114
2132
  ] }) : !a.enabled ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
2115
- /* @__PURE__ */ jsx10("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
2116
- canManage ? /* @__PURE__ */ jsx10(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx10(PowerGlyph, {}), disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
2133
+ /* @__PURE__ */ jsx11("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
2134
+ canManage ? /* @__PURE__ */ jsx11(Button7, { variant: "quiet", icon: /* @__PURE__ */ jsx11(PowerGlyph, {}), disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
2117
2135
  ] }) : live.error ? /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2", children: [
2118
- /* @__PURE__ */ jsx10("span", { className: "truncate text-sm text-destructive", title: live.error, children: live.error }),
2119
- /* @__PURE__ */ jsx10(Button7, { variant: "quiet", onClick: live.retry, children: "Retry" })
2120
- ] }) : /* @__PURE__ */ jsx10(CodeButton, { live, digits: item.authenticator.digits, label: item.name })
2136
+ /* @__PURE__ */ jsx11("span", { className: "truncate text-sm text-destructive", title: live.error, children: live.error }),
2137
+ /* @__PURE__ */ jsx11(Button7, { variant: "quiet", onClick: live.retry, children: "Retry" })
2138
+ ] }) : /* @__PURE__ */ jsx11(CodeButton, { live, digits: item.authenticator.digits, label: item.name })
2121
2139
  }
2122
2140
  );
2123
2141
  }
@@ -2135,7 +2153,7 @@ function TotpEditRow({ value, onChange, hasExisting, item, port, onEnrolled, onR
2135
2153
  setStatus(wasCancelled(e) ? null : otpActionError(e, "read that image"));
2136
2154
  }
2137
2155
  } : void 0;
2138
- return /* @__PURE__ */ jsx10(
2156
+ return /* @__PURE__ */ jsx11(
2139
2157
  OtpSetupRow,
2140
2158
  {
2141
2159
  value,
@@ -2160,7 +2178,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
2160
2178
  const [busy, setBusy] = useState11(false);
2161
2179
  const [error, setError] = useState11(null);
2162
2180
  const canEdit = item.capabilities.canEdit || item.capabilities.canManage;
2163
- return /* @__PURE__ */ jsx10(VaultRow, { label: "Two-factor", hint: error ? /* @__PURE__ */ jsx10("span", { className: "text-destructive", children: error }) : void 0, children: /* @__PURE__ */ jsx10(
2181
+ return /* @__PURE__ */ jsx11(VaultRow, { label: "Two-factor", hint: error ? /* @__PURE__ */ jsx11("span", { className: "text-destructive", children: error }) : void 0, children: /* @__PURE__ */ jsx11(
2164
2182
  Select,
2165
2183
  {
2166
2184
  value: value ?? "none",
@@ -2187,7 +2205,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
2187
2205
  }
2188
2206
 
2189
2207
  // src/authenticator/AddOtpPanel.tsx
2190
- import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2208
+ import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2191
2209
  var NEW = "__new__";
2192
2210
  var LOGIN_KEYS = ["website_login", "username_password"];
2193
2211
  function normalizeWebsite(raw) {
@@ -2263,23 +2281,23 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2263
2281
  setBusy(false);
2264
2282
  }
2265
2283
  };
2266
- if (saved) return /* @__PURE__ */ jsx11(AddedPanel, { port, item: saved, onClose, onDone: () => onDone(saved.id) });
2284
+ if (saved) return /* @__PURE__ */ jsx12(AddedPanel, { port, item: saved, onClose, onDone: () => onDone(saved.id) });
2267
2285
  return /* @__PURE__ */ jsxs11(
2268
2286
  Panel,
2269
2287
  {
2270
- title: "Add one-time password",
2288
+ title: "Add authenticator",
2271
2289
  size: "md",
2272
2290
  onClose,
2273
2291
  footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
2274
- /* @__PURE__ */ jsx11(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
2275
- /* @__PURE__ */ jsx11(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
2292
+ /* @__PURE__ */ jsx12(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
2293
+ /* @__PURE__ */ jsx12(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
2276
2294
  ] }),
2277
2295
  children: [
2278
2296
  /* @__PURE__ */ jsxs11(VaultSection, { children: [
2279
- /* @__PURE__ */ jsx11(
2297
+ /* @__PURE__ */ jsx12(
2280
2298
  OtpSetupRow,
2281
2299
  {
2282
- label: "Setup code",
2300
+ label: "Setup key",
2283
2301
  value: input,
2284
2302
  autoFocus: true,
2285
2303
  disabled: busy,
@@ -2297,7 +2315,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2297
2315
  status: image ? `QR image ready \xB7 ${image.name}` : null
2298
2316
  }
2299
2317
  ),
2300
- /* @__PURE__ */ jsx11(VaultRow, { label: "Add to", children: /* @__PURE__ */ jsx11(
2318
+ itemId ? null : /* @__PURE__ */ jsx12(VaultRow, { label: "Add to", children: /* @__PURE__ */ jsx12(
2301
2319
  Select2,
2302
2320
  {
2303
2321
  value: target,
@@ -2311,7 +2329,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2311
2329
  }
2312
2330
  ) }),
2313
2331
  isNew ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
2314
- /* @__PURE__ */ jsx11(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx11(
2332
+ /* @__PURE__ */ jsx12(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx12(
2315
2333
  Field4,
2316
2334
  {
2317
2335
  className: "w-full",
@@ -2325,24 +2343,27 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2325
2343
  "aria-label": "Name"
2326
2344
  }
2327
2345
  ) }),
2328
- /* @__PURE__ */ jsx11(VaultRow, { label: "Website", hint: websiteBad ? /* @__PURE__ */ jsx11("span", { className: "text-destructive", children: "Not a web address" }) : void 0, children: /* @__PURE__ */ jsx11(Field4, { className: "w-full", type: "url", value: website, disabled: busy || created !== null, onChange: (e) => setWebsite(e.target.value), placeholder: "example.com", "aria-label": "Website", "aria-invalid": websiteBad || void 0 }) })
2346
+ /* @__PURE__ */ jsx12(VaultRow, { label: "Website", hint: websiteBad ? /* @__PURE__ */ jsx12("span", { className: "text-destructive", children: "Not a web address" }) : void 0, children: /* @__PURE__ */ jsx12(Field4, { className: "w-full", type: "url", value: website, disabled: busy || created !== null, onChange: (e) => setWebsite(e.target.value), placeholder: "example.com", "aria-label": "Website", "aria-invalid": websiteBad || void 0 }) })
2329
2347
  ] }) : null
2330
2348
  ] }),
2331
- error ? /* @__PURE__ */ jsx11("p", { className: "px-1 text-sm text-destructive", role: "alert", children: error }) : null
2349
+ error ? /* @__PURE__ */ jsx12("p", { className: "px-1 text-sm text-destructive", role: "alert", children: error }) : null
2332
2350
  ]
2333
2351
  }
2334
2352
  );
2335
2353
  }
2354
+ function FirstCodePanel(props) {
2355
+ return /* @__PURE__ */ jsx12(AddedPanel, { ...props });
2356
+ }
2336
2357
  function AddedPanel({ port, item, onClose, onDone }) {
2337
2358
  const live = useLiveCode(port, item, true);
2338
- return /* @__PURE__ */ jsx11(Panel, { title: item.name, size: "sm", onClose, footer: /* @__PURE__ */ jsx11(Button8, { variant: "primary", onClick: onDone, children: "Done" }), children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 py-4", children: [
2339
- live.error ? /* @__PURE__ */ jsx11("span", { className: "text-sm text-destructive", children: live.error }) : /* @__PURE__ */ jsx11(CodeButton, { live, digits: item.authenticator?.digits ?? 6, size: "lg", label: item.name }),
2340
- /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground", children: "Enter this code on the site to finish." })
2359
+ return /* @__PURE__ */ jsx12(Panel, { title: item.name, size: "sm", onClose, footer: /* @__PURE__ */ jsx12(Button8, { variant: "primary", onClick: onDone, children: "Done" }), children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 py-4", children: [
2360
+ live.error ? /* @__PURE__ */ jsx12("span", { className: "text-sm text-destructive", children: live.error }) : /* @__PURE__ */ jsx12(CodeButton, { live, digits: item.authenticator?.digits ?? 6, size: "lg", label: item.name }),
2361
+ /* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground", children: "Enter this code on the site to finish." })
2341
2362
  ] }) });
2342
2363
  }
2343
2364
 
2344
2365
  // src/authenticator/AuthenticatorView.tsx
2345
- import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2366
+ import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2346
2367
  function matchesEntry(entry, q) {
2347
2368
  if (!entry || !q) return false;
2348
2369
  return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
@@ -2360,7 +2381,7 @@ function otpGroups(items, entries, query, hidden = /* @__PURE__ */ new Set()) {
2360
2381
  const rank = (k) => k === "me" ? 0 : k === "shared" ? 2 : 1;
2361
2382
  return [...groups.entries()].sort(([a, x], [b, y]) => rank(a) - rank(b) || x.label.localeCompare(y.label)).map(([key, g]) => ({ key, ...g }));
2362
2383
  }
2363
- function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged, header }) {
2384
+ function AuthenticatorView({ port, host, items, definitions, query, onOpen, onChanged, header }) {
2364
2385
  const [entries, setEntries] = useState13(/* @__PURE__ */ new Map());
2365
2386
  const [hidden, setHidden] = useState13(/* @__PURE__ */ new Set());
2366
2387
  const [adding, setAdding] = useState13(false);
@@ -2380,20 +2401,20 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2380
2401
  const groups = otpGroups(items, entries, query, hidden);
2381
2402
  const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
2382
2403
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
2383
- return /* @__PURE__ */ jsxs12("section", { "aria-label": "One-time passwords", className: "flex h-full min-h-0 flex-col bg-background", children: [
2384
- header ? /* @__PURE__ */ jsx12("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
2404
+ return /* @__PURE__ */ jsxs12("section", { "aria-label": "Authenticator", className: "flex h-full min-h-0 flex-col bg-background", children: [
2405
+ header ? /* @__PURE__ */ jsx13("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
2385
2406
  /* @__PURE__ */ jsxs12("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
2386
2407
  /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-baseline gap-2", children: [
2387
- /* @__PURE__ */ jsx12("h2", { className: "truncate text-sm font-semibold text-foreground", children: "One-time passwords" }),
2388
- total > 0 ? /* @__PURE__ */ jsx12("span", { className: "text-xs tabular-nums text-muted-foreground", children: total }) : null
2408
+ /* @__PURE__ */ jsx13("h2", { className: "truncate text-sm font-semibold text-foreground", children: "Authenticator" }),
2409
+ total > 0 ? /* @__PURE__ */ jsx13("span", { className: "text-xs tabular-nums text-muted-foreground", children: total }) : null
2389
2410
  ] }),
2390
- total > 0 ? /* @__PURE__ */ jsx12(Button9, { variant: "outline", icon: /* @__PURE__ */ jsx12(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
2411
+ total > 0 ? /* @__PURE__ */ jsx13(Button9, { variant: "outline", icon: /* @__PURE__ */ jsx13(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add" }) : null
2391
2412
  ] }),
2392
2413
  total === 0 ? /* @__PURE__ */ jsxs12("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 px-6 pb-12 text-center", children: [
2393
- /* @__PURE__ */ jsx12("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx12(ShieldGlyph, { className: "size-6" }) }),
2394
- /* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: "No one-time passwords yet" }),
2395
- /* @__PURE__ */ jsx12(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx12(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add one-time password" })
2396
- ] }) : groups.length === 0 ? /* @__PURE__ */ jsx12("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ jsx12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ jsx12(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ jsx12(
2414
+ /* @__PURE__ */ jsx13("span", { className: "flex size-12 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx13(ShieldGlyph, { className: "size-6" }) }),
2415
+ /* @__PURE__ */ jsx13("p", { className: "text-sm font-medium text-foreground", children: "No authenticator codes yet" }),
2416
+ /* @__PURE__ */ jsx13(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx13(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add authenticator" })
2417
+ ] }) : groups.length === 0 ? /* @__PURE__ */ jsx13("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "Nothing matches." }) : /* @__PURE__ */ jsx13("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pb-6 pt-1 sm:px-4", children: /* @__PURE__ */ jsx13("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: groups.map((g) => /* @__PURE__ */ jsx13(VaultSection, { title: g.label, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ jsx13(
2397
2418
  OtpListRow,
2398
2419
  {
2399
2420
  port,
@@ -2401,6 +2422,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2401
2422
  family: familyOf2(item.definitionKey),
2402
2423
  entry: entries.get(item.id),
2403
2424
  onOpen: () => onOpen(item.id),
2425
+ ...host.openItemInNewTab ? { onOpenInNewTab: () => host.openItemInNewTab?.(item.id) } : {},
2404
2426
  onRename: () => {
2405
2427
  setRenameError(null);
2406
2428
  setRenaming(item);
@@ -2413,7 +2435,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2413
2435
  },
2414
2436
  item.id
2415
2437
  )) }, g.key)) }) }),
2416
- adding ? /* @__PURE__ */ jsx12(
2438
+ adding ? /* @__PURE__ */ jsx13(
2417
2439
  AddOtpPanel,
2418
2440
  {
2419
2441
  port,
@@ -2427,7 +2449,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2427
2449
  }
2428
2450
  }
2429
2451
  ) : null,
2430
- /* @__PURE__ */ jsx12(
2452
+ /* @__PURE__ */ jsx13(
2431
2453
  TextInputDialog,
2432
2454
  {
2433
2455
  open: renaming !== null,
@@ -2435,7 +2457,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2435
2457
  if (!o && !renameBusy) setRenaming(null);
2436
2458
  },
2437
2459
  title: "Rename login",
2438
- ...renameError ? { description: /* @__PURE__ */ jsx12("span", { className: "text-destructive", children: renameError }) } : {},
2460
+ ...renameError ? { description: /* @__PURE__ */ jsx13("span", { className: "text-destructive", children: renameError }) } : {},
2439
2461
  placeholder: "Login name",
2440
2462
  defaultValue: renaming?.name ?? "",
2441
2463
  confirmLabel: "Rename",
@@ -2458,50 +2480,53 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2458
2480
  )
2459
2481
  ] });
2460
2482
  }
2461
- function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, onRemoved }) {
2483
+ function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRename, onChanged, onRemoved }) {
2462
2484
  const a = useOtpActions(port, item, (next) => next && next.authenticator === null ? onRemoved() : onChanged());
2463
2485
  const live = useLiveCode(port, item, a.enabled && !a.removed);
2464
2486
  const { copy } = useCopied();
2465
- const Icon = definitionGlyph(item.definitionKey, family);
2466
2487
  const canManage = item.capabilities.canManage || item.capabilities.canEdit;
2467
2488
  if (a.removed) return null;
2468
2489
  const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
2469
2490
  return /* @__PURE__ */ jsxs12("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
2470
- /* @__PURE__ */ jsx12("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: cn6("flex size-8 items-center justify-center rounded-lg bg-muted", a.enabled ? "text-foreground" : "text-disabled-foreground"), children: /* @__PURE__ */ jsx12(Icon, { className: "size-4" }) }),
2491
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: onOpen, "aria-label": `Open ${item.name}`, tabIndex: -1, className: "flex size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsx13(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item) || (entry?.issuer ?? "") }) }),
2471
2492
  /* @__PURE__ */ jsxs12("button", { type: "button", onClick: onOpen, className: "flex min-w-0 flex-col items-start rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
2472
- /* @__PURE__ */ jsx12("span", { className: cn6("max-w-full truncate text-sm font-medium", a.enabled ? "text-foreground" : "text-muted-foreground"), children: item.name }),
2473
- sub ? /* @__PURE__ */ jsx12("span", { className: cn6("max-w-full truncate text-xs", a.error ? "text-destructive" : "text-muted-foreground"), title: sub, children: sub }) : null
2493
+ /* @__PURE__ */ jsx13("span", { className: cn7("max-w-full truncate text-sm font-medium", a.enabled ? "text-foreground" : "text-muted-foreground"), children: item.name }),
2494
+ sub ? /* @__PURE__ */ jsx13("span", { className: cn7("max-w-full truncate text-xs", a.error ? "text-destructive" : "text-muted-foreground"), title: sub, children: sub }) : null
2474
2495
  ] }),
2475
- /* @__PURE__ */ jsx12("div", { className: "flex min-w-0 justify-end", children: !a.enabled ? /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5", children: [
2476
- /* @__PURE__ */ jsx12("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
2477
- canManage ? /* @__PURE__ */ jsx12(Button9, { variant: "quiet", disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
2496
+ /* @__PURE__ */ jsx13("div", { className: "flex min-w-0 justify-end", children: !a.enabled ? /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5", children: [
2497
+ /* @__PURE__ */ jsx13("span", { className: "text-sm text-disabled-foreground", children: "Off" }),
2498
+ canManage ? /* @__PURE__ */ jsx13(Button9, { variant: "quiet", disabled: a.busy, onClick: () => void a.setEnabled(true), children: "Turn on" }) : null
2478
2499
  ] }) : live.error ? /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5", children: [
2479
- /* @__PURE__ */ jsx12("span", { className: "max-w-40 truncate text-xs text-destructive", title: live.error, children: live.error }),
2480
- /* @__PURE__ */ jsx12(Button9, { variant: "quiet", onClick: live.retry, children: "Retry" })
2481
- ] }) : /* @__PURE__ */ jsx12(CodeButton, { live, digits: item.authenticator?.digits ?? 6, label: item.name }) }),
2500
+ /* @__PURE__ */ jsx13("span", { className: "max-w-40 truncate text-xs text-destructive", title: live.error, children: live.error }),
2501
+ /* @__PURE__ */ jsx13(Button9, { variant: "quiet", onClick: live.retry, children: "Retry" })
2502
+ ] }) : /* @__PURE__ */ jsx13(CodeButton, { live, digits: item.authenticator?.digits ?? 6, label: item.name }) }),
2482
2503
  /* @__PURE__ */ jsxs12(DropdownMenu2, { children: [
2483
- /* @__PURE__ */ jsx12(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx12(Button9, { variant: "quiet", icon: /* @__PURE__ */ jsx12(MoreGlyph, {}), "aria-label": `${item.name} options`, disabled: a.busy }) }),
2504
+ /* @__PURE__ */ jsx13(DropdownMenuTrigger2, { asChild: true, children: /* @__PURE__ */ jsx13(Button9, { variant: "quiet", icon: /* @__PURE__ */ jsx13(MoreGlyph, {}), "aria-label": `${item.name} options`, disabled: a.busy }) }),
2484
2505
  /* @__PURE__ */ jsxs12(DropdownMenuContent2, { align: "end", className: "min-w-44", children: [
2485
2506
  /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onOpen, children: [
2486
- /* @__PURE__ */ jsx12(ExternalGlyph, { className: "size-4" }),
2507
+ /* @__PURE__ */ jsx13(ExternalGlyph, { className: "size-4" }),
2487
2508
  "Open login"
2488
2509
  ] }),
2510
+ onOpenInNewTab ? /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onOpenInNewTab, children: [
2511
+ /* @__PURE__ */ jsx13(ExternalGlyph, { className: "size-4" }),
2512
+ "Open in new tab"
2513
+ ] }) : null,
2489
2514
  live.code ? /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: () => live.code && void copy(live.code), children: [
2490
- /* @__PURE__ */ jsx12(CopyIcon4, { className: "size-4" }),
2515
+ /* @__PURE__ */ jsx13(CopyIcon4, { className: "size-4" }),
2491
2516
  "Copy code"
2492
2517
  ] }) : null,
2493
2518
  canManage ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
2494
2519
  /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onRename, children: [
2495
- /* @__PURE__ */ jsx12(PencilGlyph, { className: "size-4" }),
2520
+ /* @__PURE__ */ jsx13(PencilGlyph, { className: "size-4" }),
2496
2521
  "Rename"
2497
2522
  ] }),
2498
2523
  /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: () => void a.setEnabled(!a.enabled), children: [
2499
- /* @__PURE__ */ jsx12(PowerGlyph, { className: "size-4" }),
2524
+ /* @__PURE__ */ jsx13(PowerGlyph, { className: "size-4" }),
2500
2525
  a.enabled ? "Turn off" : "Turn on"
2501
2526
  ] }),
2502
- /* @__PURE__ */ jsx12(DropdownMenuSeparator2, {}),
2527
+ /* @__PURE__ */ jsx13(DropdownMenuSeparator2, {}),
2503
2528
  /* @__PURE__ */ jsxs12(DropdownMenuItem2, { className: "text-destructive focus:text-destructive", onSelect: () => void a.remove(), children: [
2504
- /* @__PURE__ */ jsx12(TrashGlyph, { className: "size-4" }),
2529
+ /* @__PURE__ */ jsx13(TrashGlyph, { className: "size-4" }),
2505
2530
  "Remove"
2506
2531
  ] })
2507
2532
  ] }) : null
@@ -2592,9 +2617,21 @@ function withoutCode(codes, index) {
2592
2617
  const left = codes.filter((_, i) => i !== index);
2593
2618
  return left.length ? left.join("\n") : null;
2594
2619
  }
2620
+ function parseEnvAssignment(text) {
2621
+ const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/s.exec(text.trim());
2622
+ if (!m || /\n/.test(m[2] ?? "")) return null;
2623
+ let value = (m[2] ?? "").trim();
2624
+ const q = value[0];
2625
+ if ((q === '"' || q === "'") && value.length >= 2 && value.endsWith(q)) value = value.slice(1, -1);
2626
+ return value ? { key: m[1] ?? "", value } : null;
2627
+ }
2628
+ function labelFromEnvKey(key) {
2629
+ const words = key.toLowerCase().split(/[_\s]+/).filter(Boolean).join(" ");
2630
+ return words ? words.charAt(0).toUpperCase() + words.slice(1) : key;
2631
+ }
2595
2632
 
2596
2633
  // src/fields/SettingsPanels.tsx
2597
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
2634
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2598
2635
  var say = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
2599
2636
  function useSaver(onChanged) {
2600
2637
  const [busy, setBusy] = useState14(null);
@@ -2616,14 +2653,14 @@ function useSaver(onChanged) {
2616
2653
  return { busy, error, setError, save };
2617
2654
  }
2618
2655
  function Problem({ children }) {
2619
- return /* @__PURE__ */ jsx13("p", { role: "alert", className: "px-1 text-sm text-destructive", children });
2656
+ return /* @__PURE__ */ jsx14("p", { role: "alert", className: "px-1 text-sm text-destructive", children });
2620
2657
  }
2621
- var quietHint = (text, tone = "muted") => /* @__PURE__ */ jsx13("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
2658
+ var quietHint = (text, tone = "muted") => /* @__PURE__ */ jsx14("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
2622
2659
  function FieldSettingsPanel(props) {
2623
2660
  const field = props.item.fields.find((f) => f.id === props.arg);
2624
2661
  if (!field)
2625
- return /* @__PURE__ */ jsx13(Panel, { title: "Field settings", size: "md", onClose: props.onClose, footer: /* @__PURE__ */ jsx13(Button10, { variant: "primary", onClick: props.onClose, children: "Done" }), children: /* @__PURE__ */ jsx13(Empty, { children: "This field is no longer on the item." }) });
2626
- return /* @__PURE__ */ jsx13(FieldSettings, { ...props, field }, field.id);
2662
+ return /* @__PURE__ */ jsx14(Panel, { title: "Field settings", size: "md", onClose: props.onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: props.onClose, children: "Done" }), children: /* @__PURE__ */ jsx14(Empty, { children: "This field is no longer on the item." }) });
2663
+ return /* @__PURE__ */ jsx14(FieldSettings, { ...props, field }, field.id);
2627
2664
  }
2628
2665
  function FieldSettings({ item, port, field, onClose, onChanged }) {
2629
2666
  const { busy, error, setError, save } = useSaver((next) => onChanged(next));
@@ -2662,9 +2699,9 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
2662
2699
  };
2663
2700
  const handling = HANDLING_WORDS[field.handling];
2664
2701
  const locked = !canEdit || busy !== null;
2665
- return /* @__PURE__ */ jsxs13(Panel, { title: `${field.label} settings`, size: "md", onClose, footer: /* @__PURE__ */ jsx13(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
2666
- !canEdit ? /* @__PURE__ */ jsx13("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
2667
- /* @__PURE__ */ jsx13(VaultSection, { title: "Who can see it", children: /* @__PURE__ */ jsx13(VaultRow, { label: "Value", hint: quietHint(handling.hint), children: field.handling === "sealed" ? /* @__PURE__ */ jsx13(Badge3, { icon: /* @__PURE__ */ jsx13(LockGlyph, {}), children: "Sealed for good" }) : /* @__PURE__ */ jsx13(
2702
+ return /* @__PURE__ */ jsxs13(Panel, { title: `${field.label} settings`, size: "md", onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
2703
+ !canEdit ? /* @__PURE__ */ jsx14("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
2704
+ /* @__PURE__ */ jsx14(VaultSection, { title: "Who can see it", children: /* @__PURE__ */ jsx14(VaultRow, { label: "Value", hint: quietHint(handling.hint), children: field.handling === "sealed" ? /* @__PURE__ */ jsx14(Badge3, { icon: /* @__PURE__ */ jsx14(LockGlyph, {}), children: "Sealed for good" }) : /* @__PURE__ */ jsx14(
2668
2705
  SegmentedControl,
2669
2706
  {
2670
2707
  "aria-label": "Who can see it",
@@ -2674,7 +2711,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
2674
2711
  }
2675
2712
  ) }) }),
2676
2713
  /* @__PURE__ */ jsxs13(VaultSection, { title: "Automation", children: [
2677
- /* @__PURE__ */ jsx13(VaultRow, { label: "Env key", hint: envProblem ? quietHint(envProblem, "destructive") : quietHint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx13(
2714
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Env key", hint: envProblem ? quietHint(envProblem, "destructive") : quietHint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx14(
2678
2715
  Field5,
2679
2716
  {
2680
2717
  ref: envRef,
@@ -2694,10 +2731,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
2694
2731
  }
2695
2732
  }
2696
2733
  ) }),
2697
- /* @__PURE__ */ jsx13(VaultRow, { label: "Use in sandbox", hint: blocker && !field.injectIntoSandbox ? quietHint(blocker) : quietHint("Sandboxes get it as an env variable"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Use in sandbox", checked: field.injectIntoSandbox, disabled: locked, onCheckedChange: (v) => void setSandbox(v) }) })
2734
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Use in sandbox", hint: blocker && !field.injectIntoSandbox ? quietHint(blocker) : quietHint("Sandboxes get it as an env variable"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Use in sandbox", checked: field.injectIntoSandbox, disabled: locked, onCheckedChange: (v) => void setSandbox(v) }) })
2698
2735
  ] }),
2699
2736
  /* @__PURE__ */ jsxs13(VaultSection, { title: "Field", children: [
2700
- /* @__PURE__ */ jsx13(VaultRow, { label: "Description", children: /* @__PURE__ */ jsx13(
2737
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Description", children: /* @__PURE__ */ jsx14(
2701
2738
  Field5,
2702
2739
  {
2703
2740
  className: "w-full",
@@ -2713,10 +2750,10 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
2713
2750
  }
2714
2751
  }
2715
2752
  ) }),
2716
- /* @__PURE__ */ jsx13(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
2717
- /* @__PURE__ */ jsx13(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
2753
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Editable", hint: quietHint(field.editable ? "The value can be changed" : "The value is locked"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Editable", checked: field.editable, disabled: locked, onCheckedChange: (v) => void update("editable", { editable: v }) }) }),
2754
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Turned on", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Turned on", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: v }) }) })
2718
2755
  ] }),
2719
- error ? /* @__PURE__ */ jsx13(Problem, { children: error }) : null
2756
+ error ? /* @__PURE__ */ jsx14(Problem, { children: error }) : null
2720
2757
  ] });
2721
2758
  }
2722
2759
  function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
@@ -2743,10 +2780,10 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
2743
2780
  });
2744
2781
  };
2745
2782
  const fillHint = !hasWebsite ? "Add a website first" : item.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically";
2746
- return /* @__PURE__ */ jsxs13(Panel, { title: "Item settings", size: "md", onClose, footer: /* @__PURE__ */ jsx13(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
2747
- !canEdit ? /* @__PURE__ */ jsx13("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
2783
+ return /* @__PURE__ */ jsxs13(Panel, { title: "Item settings", size: "md", onClose, footer: /* @__PURE__ */ jsx14(Button10, { variant: "primary", onClick: onClose, children: "Done" }), children: [
2784
+ !canEdit ? /* @__PURE__ */ jsx14("p", { className: "px-1 text-sm text-muted-foreground", children: "View only: you can\u2019t change these settings." }) : null,
2748
2785
  /* @__PURE__ */ jsxs13(VaultSection, { title: "In the browser", children: [
2749
- /* @__PURE__ */ jsx13(VaultRow, { label: "Website matching", hint: quietHint(MATCH_WORDS[item.uriMatchMode].hint), children: /* @__PURE__ */ jsx13(
2786
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Website matching", hint: quietHint(MATCH_WORDS[item.uriMatchMode].hint), children: /* @__PURE__ */ jsx14(
2750
2787
  Select3,
2751
2788
  {
2752
2789
  "aria-label": "Website matching",
@@ -2756,45 +2793,45 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
2756
2793
  onValueChange: (m) => void save("match", () => port.fields.updateItem(item, { uriMatchMode: m }))
2757
2794
  }
2758
2795
  ) }),
2759
- /* @__PURE__ */ jsx13(VaultRow, { label: "Fill in browser", hint: quietHint(fillHint), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Fill in browser", checked: hasWebsite && item.browserFillEnabled, disabled: locked || !hasWebsite, onCheckedChange: (v) => void save("fill", () => port.fields.updateItem(item, { browserFillEnabled: v })) }) }),
2760
- promotable.map((f) => /* @__PURE__ */ jsx13(
2796
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Fill in browser", hint: quietHint(fillHint), children: /* @__PURE__ */ jsx14(Switch, { "aria-label": "Fill in browser", checked: hasWebsite && item.browserFillEnabled, disabled: locked || !hasWebsite, onCheckedChange: (v) => void save("fill", () => port.fields.updateItem(item, { browserFillEnabled: v })) }) }),
2797
+ promotable.map((f) => /* @__PURE__ */ jsx14(
2761
2798
  VaultRow,
2762
2799
  {
2763
2800
  label: f.label,
2764
2801
  hint: quietHint("Encrypted, so the browser can\u2019t match it"),
2765
- actions: /* @__PURE__ */ jsx13(Button10, { variant: "outline", icon: /* @__PURE__ */ jsx13(GlobeIcon2, {}), disabled: locked, onClick: () => void promote(f), children: "Use as website" }),
2766
- children: /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: "Not a website yet" })
2802
+ actions: /* @__PURE__ */ jsx14(Button10, { variant: "outline", icon: /* @__PURE__ */ jsx14(GlobeIcon2, {}), disabled: locked, onClick: () => void promote(f), children: "Use as website" }),
2803
+ children: /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Not a website yet" })
2767
2804
  },
2768
2805
  f.id
2769
2806
  ))
2770
2807
  ] }),
2771
2808
  /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1.5", children: [
2772
- /* @__PURE__ */ jsx13(DisclosureHeader, { open: advanced, title: "Advanced", meta: item.fields.length ? `${item.fields.length} fields` : void 0, onClick: () => setAdvanced((a) => !a) }),
2773
- advanced ? /* @__PURE__ */ jsx13(VaultSection, { children: item.fields.length === 0 ? /* @__PURE__ */ jsx13(Empty, { children: "No encrypted fields." }) : item.fields.map((f) => /* @__PURE__ */ jsx13(
2809
+ /* @__PURE__ */ jsx14(DisclosureHeader, { open: advanced, title: "Advanced", meta: item.fields.length ? `${item.fields.length} fields` : void 0, onClick: () => setAdvanced((a) => !a) }),
2810
+ advanced ? /* @__PURE__ */ jsx14(VaultSection, { children: item.fields.length === 0 ? /* @__PURE__ */ jsx14(Empty, { children: "No encrypted fields." }) : item.fields.map((f) => /* @__PURE__ */ jsx14(
2774
2811
  VaultRow,
2775
2812
  {
2776
2813
  label: f.label,
2777
- actions: /* @__PURE__ */ jsx13(Button10, { variant: "quiet", icon: /* @__PURE__ */ jsx13(SlidersGlyph, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }),
2814
+ actions: /* @__PURE__ */ jsx14(Button10, { variant: "quiet", icon: /* @__PURE__ */ jsx14(SlidersGlyph, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }),
2778
2815
  children: /* @__PURE__ */ jsxs13("span", { className: "block truncate", children: [
2779
- /* @__PURE__ */ jsx13("span", { className: f.handling === "sealed" ? "text-foreground" : "text-muted-foreground", children: HANDLING_WORDS[f.handling].label }),
2816
+ /* @__PURE__ */ jsx14("span", { className: f.handling === "sealed" ? "text-foreground" : "text-muted-foreground", children: HANDLING_WORDS[f.handling].label }),
2780
2817
  f.envKey ? /* @__PURE__ */ jsxs13("span", { className: "font-mono text-muted-foreground", children: [
2781
2818
  " \xB7 ",
2782
2819
  f.envKey
2783
2820
  ] }) : null,
2784
- f.injectIntoSandbox ? /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
2785
- !f.active ? /* @__PURE__ */ jsx13("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
2821
+ f.injectIntoSandbox ? /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
2822
+ !f.active ? /* @__PURE__ */ jsx14("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
2786
2823
  ] })
2787
2824
  },
2788
2825
  f.id
2789
2826
  )) }) : null
2790
2827
  ] }),
2791
- error ? /* @__PURE__ */ jsx13(Problem, { children: error }) : null
2828
+ error ? /* @__PURE__ */ jsx14(Problem, { children: error }) : null
2792
2829
  ] });
2793
2830
  }
2794
2831
 
2795
2832
  // src/generator/PasswordGenerator.tsx
2796
2833
  import { createContext as createContext5, useContext as useContext5, useEffect as useEffect12, useRef as useRef10, useState as useState15 } from "react";
2797
- import { Popover, PopoverContent, PopoverTrigger, cn as cn7 } from "@ai-matrx/design-system";
2834
+ import { Popover, PopoverContent, PopoverTrigger, cn as cn8 } from "@ai-matrx/design-system";
2798
2835
  import { Button as Button11, NumberStepper, SegmentedControl as SegmentedControl2, Select as Select4, Switch as Switch2 } from "@ai-matrx/design-system/controls";
2799
2836
  import { CopyIcon as CopyIcon5 } from "@ai-matrx/design-system/icons";
2800
2837
 
@@ -2854,10 +2891,10 @@ function strengthOf(bits) {
2854
2891
  }
2855
2892
 
2856
2893
  // src/generator/PasswordGenerator.tsx
2857
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2894
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2858
2895
  var LimitsCtx = createContext5(null);
2859
2896
  function GeneratorLimitsProvider({ resolve: resolve2, children }) {
2860
- return /* @__PURE__ */ jsx14(LimitsCtx.Provider, { value: resolve2 ?? null, children });
2897
+ return /* @__PURE__ */ jsx15(LimitsCtx.Provider, { value: resolve2 ?? null, children });
2861
2898
  }
2862
2899
  function useGeneratorLimitsSource() {
2863
2900
  return useContext5(LimitsCtx);
@@ -2918,11 +2955,11 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2918
2955
  useEffect12(() => () => {
2919
2956
  if (expiry.current) clearTimeout(expiry.current);
2920
2957
  }, []);
2921
- if (limits.state === "loading") return /* @__PURE__ */ jsx14("p", { className: "px-1 py-3 text-sm text-muted-foreground", "aria-live": "polite", children: "Reading limits\u2026" });
2958
+ if (limits.state === "loading") return /* @__PURE__ */ jsx15("p", { className: "px-1 py-3 text-sm text-muted-foreground", "aria-live": "polite", children: "Reading limits\u2026" });
2922
2959
  if (limits.state === "unavailable")
2923
2960
  return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-2 px-1 py-2", children: [
2924
- /* @__PURE__ */ jsx14("p", { role: "alert", className: "text-sm text-destructive", children: limits.message }),
2925
- /* @__PURE__ */ jsx14(Button11, { variant: "outline", icon: /* @__PURE__ */ jsx14(RefreshGlyph, {}), onClick: () => setRound((n) => n + 1), children: "Try again" })
2961
+ /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-sm text-destructive", children: limits.message }),
2962
+ /* @__PURE__ */ jsx15(Button11, { variant: "outline", icon: /* @__PURE__ */ jsx15(RefreshGlyph, {}), onClick: () => setRound((n) => n + 1), children: "Try again" })
2926
2963
  ] });
2927
2964
  const ceilings = limits.limits;
2928
2965
  const change = (next) => make(next, ceilings);
@@ -2940,7 +2977,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2940
2977
  onUse(value);
2941
2978
  };
2942
2979
  return /* @__PURE__ */ jsxs14("div", { className: "flex w-full flex-col gap-3", "aria-label": "Password generator", children: [
2943
- /* @__PURE__ */ jsx14(
2980
+ /* @__PURE__ */ jsx15(
2944
2981
  SegmentedControl2,
2945
2982
  {
2946
2983
  fill: true,
@@ -2952,13 +2989,13 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2952
2989
  ),
2953
2990
  /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1 rounded-lg bg-muted px-3 py-2", children: [
2954
2991
  /* @__PURE__ */ jsxs14("div", { className: "flex min-h-7 items-start gap-1", children: [
2955
- /* @__PURE__ */ jsx14("code", { className: cn7("min-w-0 flex-1 break-all py-1 font-mono text-sm", candidate ? "text-foreground" : "text-muted-foreground"), "data-testid": "generated-value", children: candidate ? revealed ? candidate.value : MASK3 : "\u2014" }),
2956
- /* @__PURE__ */ jsx14(Button11, { variant: "quiet", icon: revealed ? /* @__PURE__ */ jsx14(EyeOffGlyph, {}) : /* @__PURE__ */ jsx14(EyeGlyph, {}), "aria-label": revealed ? "Hide" : "Reveal", disabled: !candidate, onClick: () => setRevealed((r) => !r) }),
2957
- /* @__PURE__ */ jsx14(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx14(CopyIcon5, {}), "aria-label": "Copy", disabled: !candidate, onClick: () => void copy() }),
2958
- /* @__PURE__ */ jsx14(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx14(RefreshGlyph, {}), "aria-label": "Generate another", onClick: () => change(settings) })
2992
+ /* @__PURE__ */ jsx15("code", { className: cn8("min-w-0 flex-1 break-all py-1 font-mono text-sm", candidate ? "text-foreground" : "text-muted-foreground"), "data-testid": "generated-value", children: candidate ? revealed ? candidate.value : MASK3 : "\u2014" }),
2993
+ /* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: revealed ? /* @__PURE__ */ jsx15(EyeOffGlyph, {}) : /* @__PURE__ */ jsx15(EyeGlyph, {}), "aria-label": revealed ? "Hide" : "Reveal", disabled: !candidate, onClick: () => setRevealed((r) => !r) }),
2994
+ /* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(CopyIcon5, {}), "aria-label": "Copy", disabled: !candidate, onClick: () => void copy() }),
2995
+ /* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(RefreshGlyph, {}), "aria-label": "Generate another", onClick: () => change(settings) })
2959
2996
  ] }),
2960
2997
  strength && candidate ? /* @__PURE__ */ jsxs14("p", { className: "text-xs", children: [
2961
- /* @__PURE__ */ jsx14("span", { className: cn7(strength.tone === "success" && "text-success", strength.tone === "primary" && "text-primary", strength.tone === "warning" && "text-warning"), children: strength.label }),
2998
+ /* @__PURE__ */ jsx15("span", { className: cn8(strength.tone === "success" && "text-success", strength.tone === "primary" && "text-primary", strength.tone === "warning" && "text-warning"), children: strength.label }),
2962
2999
  /* @__PURE__ */ jsxs14("span", { className: "text-muted-foreground", children: [
2963
3000
  " \xB7 ",
2964
3001
  Math.floor(candidate.bits),
@@ -2967,7 +3004,7 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2967
3004
  ] }) : null
2968
3005
  ] }),
2969
3006
  settings.kind === "password" ? /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-0.5", children: [
2970
- /* @__PURE__ */ jsx14(OptionLine, { label: "Length", children: /* @__PURE__ */ jsx14(NumberStepper, { value: settings.password.length, min: minPasswordLength(settings.password), max: ceilings.maxPasswordLength, fallback: 24, onChange: (length) => setPassword({ length }) }) }),
3007
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Length", children: /* @__PURE__ */ jsx15(NumberStepper, { value: settings.password.length, min: minPasswordLength(settings.password), max: ceilings.maxPasswordLength, fallback: 24, onChange: (length) => setPassword({ length }) }) }),
2971
3008
  [
2972
3009
  ["lowercase", "Lowercase"],
2973
3010
  ["uppercase", "Uppercase"],
@@ -2976,26 +3013,26 @@ function PasswordGenerator({ limits: source, onUse, useLabel = "Use" }) {
2976
3013
  ].map(([key, label]) => {
2977
3014
  const on = settings.password[key];
2978
3015
  const last = on && minPasswordLength(settings.password) === 1;
2979
- return /* @__PURE__ */ jsx14(OptionLine, { label, children: /* @__PURE__ */ jsx14(Switch2, { "aria-label": label, checked: on, disabled: last, onCheckedChange: (v) => setPassword({ [key]: v }) }) }, key);
3016
+ return /* @__PURE__ */ jsx15(OptionLine, { label, children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": label, checked: on, disabled: last, onCheckedChange: (v) => setPassword({ [key]: v }) }) }, key);
2980
3017
  }),
2981
- /* @__PURE__ */ jsx14(OptionLine, { label: "Avoid look-alikes", hint: "No 0/O, 1/l/I", children: /* @__PURE__ */ jsx14(Switch2, { "aria-label": "Avoid look-alikes", checked: settings.password.excludeAmbiguous, onCheckedChange: (v) => setPassword({ excludeAmbiguous: v }) }) })
3018
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Avoid look-alikes", hint: "No 0/O, 1/l/I", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Avoid look-alikes", checked: settings.password.excludeAmbiguous, onCheckedChange: (v) => setPassword({ excludeAmbiguous: v }) }) })
2982
3019
  ] }) : /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-0.5", children: [
2983
- /* @__PURE__ */ jsx14(OptionLine, { label: "Words", children: /* @__PURE__ */ jsx14(NumberStepper, { value: settings.passphrase.wordCount, min: MIN_PASSPHRASE_WORDS, max: ceilings.maxPassphraseWords, fallback: MIN_PASSPHRASE_WORDS, onChange: (wordCount) => change({ ...settings, passphrase: { ...settings.passphrase, wordCount } }) }) }),
2984
- /* @__PURE__ */ jsx14(OptionLine, { label: "Separator", children: /* @__PURE__ */ jsx14(Select4, { "aria-label": "Separator", variant: "inline", align: "end", value: settings.passphrase.separator, options: SEPARATORS, onValueChange: (separator) => change({ ...settings, passphrase: { ...settings.passphrase, separator } }) }) }),
2985
- /* @__PURE__ */ jsx14(OptionLine, { label: "Capitalize", children: /* @__PURE__ */ jsx14(Switch2, { "aria-label": "Capitalize", checked: settings.passphrase.capitalize, onCheckedChange: (capitalize) => change({ ...settings, passphrase: { ...settings.passphrase, capitalize } }) }) }),
2986
- /* @__PURE__ */ jsx14(OptionLine, { label: "Add a digit", children: /* @__PURE__ */ jsx14(Switch2, { "aria-label": "Add a digit", checked: settings.passphrase.appendDigit, onCheckedChange: (appendDigit) => change({ ...settings, passphrase: { ...settings.passphrase, appendDigit } }) }) })
3020
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Words", children: /* @__PURE__ */ jsx15(NumberStepper, { value: settings.passphrase.wordCount, min: MIN_PASSPHRASE_WORDS, max: ceilings.maxPassphraseWords, fallback: MIN_PASSPHRASE_WORDS, onChange: (wordCount) => change({ ...settings, passphrase: { ...settings.passphrase, wordCount } }) }) }),
3021
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Separator", children: /* @__PURE__ */ jsx15(Select4, { "aria-label": "Separator", variant: "inline", align: "end", value: settings.passphrase.separator, options: SEPARATORS, onValueChange: (separator) => change({ ...settings, passphrase: { ...settings.passphrase, separator } }) }) }),
3022
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Capitalize", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Capitalize", checked: settings.passphrase.capitalize, onCheckedChange: (capitalize) => change({ ...settings, passphrase: { ...settings.passphrase, capitalize } }) }) }),
3023
+ /* @__PURE__ */ jsx15(OptionLine, { label: "Add a digit", children: /* @__PURE__ */ jsx15(Switch2, { "aria-label": "Add a digit", checked: settings.passphrase.appendDigit, onCheckedChange: (appendDigit) => change({ ...settings, passphrase: { ...settings.passphrase, appendDigit } }) }) })
2987
3024
  ] }),
2988
- note ? /* @__PURE__ */ jsx14("p", { "aria-live": "polite", className: cn7("text-xs", note.tone === "destructive" ? "text-destructive" : note.tone === "success" ? "text-success" : "text-muted-foreground"), children: note.text }) : null,
2989
- /* @__PURE__ */ jsx14(Button11, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
3025
+ note ? /* @__PURE__ */ jsx15("p", { "aria-live": "polite", className: cn8("text-xs", note.tone === "destructive" ? "text-destructive" : note.tone === "success" ? "text-success" : "text-muted-foreground"), children: note.text }) : null,
3026
+ /* @__PURE__ */ jsx15(Button11, { variant: "primary", disabled: !candidate, onClick: use, children: useLabel })
2990
3027
  ] });
2991
3028
  }
2992
- function OptionLine({ label, hint, children }) {
3029
+ function OptionLine({ label, hint: hint2, children }) {
2993
3030
  return /* @__PURE__ */ jsxs14("div", { className: "flex min-h-9 items-center justify-between gap-3", children: [
2994
3031
  /* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 flex-col", children: [
2995
- /* @__PURE__ */ jsx14("span", { className: "truncate text-sm text-foreground", children: label }),
2996
- hint ? /* @__PURE__ */ jsx14("span", { className: "truncate text-xs text-muted-foreground", children: hint }) : null
3032
+ /* @__PURE__ */ jsx15("span", { className: "truncate text-sm text-foreground", children: label }),
3033
+ hint2 ? /* @__PURE__ */ jsx15("span", { className: "truncate text-xs text-muted-foreground", children: hint2 }) : null
2997
3034
  ] }),
2998
- /* @__PURE__ */ jsx14("div", { className: "flex shrink-0 items-center", children })
3035
+ /* @__PURE__ */ jsx15("div", { className: "flex shrink-0 items-center", children })
2999
3036
  ] });
3000
3037
  }
3001
3038
  function GenerateButton({ onUse, label, limits, disabled }) {
@@ -3005,8 +3042,8 @@ function GenerateButton({ onUse, label, limits, disabled }) {
3005
3042
  if (!source) return null;
3006
3043
  const name = label ?? "Generate password";
3007
3044
  return /* @__PURE__ */ jsxs14(Popover, { open, onOpenChange: setOpen, children: [
3008
- /* @__PURE__ */ jsx14(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx14(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx14(KeyGlyph, {}), "aria-label": name, title: name, disabled }) }),
3009
- /* @__PURE__ */ jsx14(PopoverContent, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx14(
3045
+ /* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(Button11, { variant: "quiet", icon: /* @__PURE__ */ jsx15(KeyGlyph, {}), "aria-label": name, title: name, disabled }) }),
3046
+ /* @__PURE__ */ jsx15(PopoverContent, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx15(
3010
3047
  PasswordGenerator,
3011
3048
  {
3012
3049
  limits: source,
@@ -3178,13 +3215,13 @@ function startNewRestoreRun(preview) {
3178
3215
  import { useState as useState16 } from "react";
3179
3216
  import { Checkbox } from "@ai-matrx/design-system";
3180
3217
  import { Badge as Badge4, Button as Button12, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
3181
- import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
3218
+ import { Fragment as Fragment9, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3182
3219
  function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
3183
3220
  return /* @__PURE__ */ jsxs15("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
3184
- /* @__PURE__ */ jsx15(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
3185
- /* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: title }),
3186
- detail ? /* @__PURE__ */ jsx15("span", { className: "hidden min-w-0 max-w-[45%] truncate text-xs text-muted-foreground sm:block", children: detail }) : null,
3187
- badge ? /* @__PURE__ */ jsx15(Badge4, { tone: tone ?? "neutral", children: badge }) : null
3221
+ /* @__PURE__ */ jsx16(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
3222
+ /* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: title }),
3223
+ detail ? /* @__PURE__ */ jsx16("span", { className: "hidden min-w-0 max-w-[45%] truncate text-xs text-muted-foreground sm:block", children: detail }) : null,
3224
+ badge ? /* @__PURE__ */ jsx16(Badge4, { tone: tone ?? "neutral", children: badge }) : null
3188
3225
  ] });
3189
3226
  }
3190
3227
  function Windowed({ items, size = 150, render }) {
@@ -3192,7 +3229,7 @@ function Windowed({ items, size = 150, render }) {
3192
3229
  const shown = all ? items : items.slice(0, size);
3193
3230
  return /* @__PURE__ */ jsxs15(Fragment9, { children: [
3194
3231
  shown.map(render),
3195
- items.length > shown.length ? /* @__PURE__ */ jsx15("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
3232
+ items.length > shown.length ? /* @__PURE__ */ jsx16("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
3196
3233
  "Show all ",
3197
3234
  items.length
3198
3235
  ] }) }) : null
@@ -3201,17 +3238,17 @@ function Windowed({ items, size = 150, render }) {
3201
3238
  function More({ title = "More", children }) {
3202
3239
  const [open, setOpen] = useState16(false);
3203
3240
  return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-2", children: [
3204
- /* @__PURE__ */ jsx15(DisclosureHeader2, { open, title, onClick: () => setOpen((o) => !o) }),
3241
+ /* @__PURE__ */ jsx16(DisclosureHeader2, { open, title, onClick: () => setOpen((o) => !o) }),
3205
3242
  open ? children : null
3206
3243
  ] });
3207
3244
  }
3208
3245
  function ErrorLine({ message: message2 }) {
3209
- return message2 ? /* @__PURE__ */ jsx15("p", { role: "alert", className: "px-1 text-sm text-destructive", children: message2 }) : null;
3246
+ return message2 ? /* @__PURE__ */ jsx16("p", { role: "alert", className: "px-1 text-sm text-destructive", children: message2 }) : null;
3210
3247
  }
3211
3248
  var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
3212
3249
 
3213
3250
  // src/io/BackupPanel.tsx
3214
- import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
3251
+ import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3215
3252
  var RECORD_STATUS = {
3216
3253
  created: "Restored",
3217
3254
  replayed: "Already restored",
@@ -3224,16 +3261,16 @@ function omissionText(o) {
3224
3261
  }
3225
3262
  function Summary({ value }) {
3226
3263
  return /* @__PURE__ */ jsxs16(VaultSection, { children: [
3227
- /* @__PURE__ */ jsx16(VaultRow, { label: "Credentials", children: value.record_count }),
3228
- /* @__PURE__ */ jsx16(VaultRow, { label: "Protected fields", children: value.field_count }),
3229
- /* @__PURE__ */ jsx16(VaultRow, { label: "Files", children: value.attachment_count > 0 ? `${value.attachment_count} \xB7 ${formatFileSize(value.attachment_bytes)}` : "0" })
3264
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Credentials", children: value.record_count }),
3265
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Protected fields", children: value.field_count }),
3266
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Files", children: value.attachment_count > 0 ? `${value.attachment_count} \xB7 ${formatFileSize(value.attachment_bytes)}` : "0" })
3230
3267
  ] });
3231
3268
  }
3232
3269
  function Omissions({ omissions, accepted, onAccepted, verb }) {
3233
3270
  if (omissions.length === 0) return null;
3234
3271
  return /* @__PURE__ */ jsxs16(VaultSection, { title: "Left out", children: [
3235
- omissions.map((o, i) => /* @__PURE__ */ jsx16(VaultRow, { label: o.component.replaceAll("_", " "), children: /* @__PURE__ */ jsx16("span", { className: "block truncate text-muted-foreground", title: omissionText(o), children: omissionText(o) }) }, `${o.component}-${o.source_item_id ?? i}`)),
3236
- /* @__PURE__ */ jsx16(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ jsx16(Switch3, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
3272
+ omissions.map((o, i) => /* @__PURE__ */ jsx17(VaultRow, { label: o.component.replaceAll("_", " "), children: /* @__PURE__ */ jsx17("span", { className: "block truncate text-muted-foreground", title: omissionText(o), children: omissionText(o) }) }, `${o.component}-${o.source_item_id ?? i}`)),
3273
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Accept", hint: `${verb} without these`, children: /* @__PURE__ */ jsx17(Switch3, { checked: accepted, onCheckedChange: onAccepted, "aria-label": `${verb} without these` }) })
3237
3274
  ] });
3238
3275
  }
3239
3276
  function BackupPanel({ port, items, onClose, onChanged }) {
@@ -3340,20 +3377,20 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3340
3377
  const mismatch = repeat !== "" && repeat !== passphrase;
3341
3378
  const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
3342
3379
  const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3343
- /* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
3344
- backup ? /* @__PURE__ */ jsx16(Button13, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
3380
+ /* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
3381
+ backup ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !passphrase || passphrase !== repeat || backup.omissions.length > 0 && !accepted, onClick: () => void downloadBackup(), children: "Encrypt and download" }) : /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void reviewBackup(), children: [
3345
3382
  "Review ",
3346
3383
  selected.size
3347
3384
  ] })
3348
3385
  ] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
3349
- /* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
3350
- result ? retryable ? /* @__PURE__ */ jsx16(Button13, { variant: "primary", disabled: busy, onClick: () => void restore(), children: "Try again" }) : /* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => void again(), children: "Restore again" }) : restorePreview ? /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || restorePreview.omissions.length > 0 && !accepted, onClick: () => void restore(), children: [
3386
+ /* @__PURE__ */ jsx17(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
3387
+ result ? retryable ? /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy, onClick: () => void restore(), children: "Try again" }) : /* @__PURE__ */ jsx17(Button13, { variant: "outline", disabled: busy, onClick: () => void again(), children: "Restore again" }) : restorePreview ? /* @__PURE__ */ jsxs16(Button13, { variant: "primary", disabled: busy || restorePreview.omissions.length > 0 && !accepted, onClick: () => void restore(), children: [
3351
3388
  "Restore ",
3352
3389
  restorePreview.record_count
3353
- ] }) : /* @__PURE__ */ jsx16(Button13, { variant: "primary", disabled: busy || !file || !passphrase, onClick: () => void reviewRestore(), children: "Review" })
3390
+ ] }) : /* @__PURE__ */ jsx17(Button13, { variant: "primary", disabled: busy || !file || !passphrase, onClick: () => void reviewRestore(), children: "Review" })
3354
3391
  ] });
3355
3392
  return /* @__PURE__ */ jsxs16(Panel, { title: "Backup", size: "lg", onClose, footer, children: [
3356
- /* @__PURE__ */ jsx16(
3393
+ /* @__PURE__ */ jsx17(
3357
3394
  SegmentedControl3,
3358
3395
  {
3359
3396
  value: mode,
@@ -3367,35 +3404,35 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3367
3404
  }
3368
3405
  ),
3369
3406
  mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3370
- /* @__PURE__ */ jsx16(
3407
+ /* @__PURE__ */ jsx17(
3371
3408
  VaultSection,
3372
3409
  {
3373
3410
  title: `${selected.size} of ${plural(items.length, "credential")}`,
3374
3411
  actions: /* @__PURE__ */ jsxs16(Fragment10, { children: [
3375
- /* @__PURE__ */ jsx16(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
3412
+ /* @__PURE__ */ jsx17(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
3376
3413
  setBackup(null);
3377
3414
  setSelected(new Set(items.map((i) => i.id)));
3378
3415
  }, children: "All" }),
3379
- /* @__PURE__ */ jsx16(Button13, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
3416
+ /* @__PURE__ */ jsx17(Button13, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
3380
3417
  setBackup(null);
3381
3418
  setSelected(/* @__PURE__ */ new Set());
3382
3419
  }, children: "None" })
3383
3420
  ] }),
3384
- children: items.length === 0 ? /* @__PURE__ */ jsx16(Empty, { children: "Nothing to back up yet." }) : /* @__PURE__ */ jsx16(Windowed, { items, render: (i) => /* @__PURE__ */ jsx16(PickLine, { title: i.name, detail: i.definitionLabel, checked: selected.has(i.id), disabled: busy, onChange: (on) => pick(i.id, on) }, i.id) })
3421
+ children: items.length === 0 ? /* @__PURE__ */ jsx17(Empty, { children: "Nothing to back up yet." }) : /* @__PURE__ */ jsx17(Windowed, { items, render: (i) => /* @__PURE__ */ jsx17(PickLine, { title: i.name, detail: i.definitionLabel, checked: selected.has(i.id), disabled: busy, onChange: (on) => pick(i.id, on) }, i.id) })
3385
3422
  }
3386
3423
  ),
3387
3424
  backup ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3388
- /* @__PURE__ */ jsx16(Summary, { value: backup }),
3389
- /* @__PURE__ */ jsx16(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
3425
+ /* @__PURE__ */ jsx17(Summary, { value: backup }),
3426
+ /* @__PURE__ */ jsx17(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
3390
3427
  /* @__PURE__ */ jsxs16(VaultSection, { children: [
3391
- /* @__PURE__ */ jsx16(VaultRow, { label: "Passphrase", hint: "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx16(Field6, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) }),
3392
- /* @__PURE__ */ jsx16(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ jsx16(Field6, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
3428
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", hint: "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) }),
3429
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Repeat", ...mismatch ? { hint: "Doesn't match" } : {}, children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: repeat, autoComplete: "new-password", "aria-label": "Repeat the passphrase", onChange: (e) => setRepeat(e.target.value) }) })
3393
3430
  ] })
3394
3431
  ] }) : null
3395
- ] }) : /* @__PURE__ */ jsx16(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
3432
+ ] }) : /* @__PURE__ */ jsx17(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
3396
3433
  /* @__PURE__ */ jsxs16(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
3397
- /* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
3398
- /* @__PURE__ */ jsx16(
3434
+ /* @__PURE__ */ jsx17(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
3435
+ /* @__PURE__ */ jsx17(
3399
3436
  "input",
3400
3437
  {
3401
3438
  ref: fileInput,
@@ -3409,16 +3446,16 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3409
3446
  }
3410
3447
  )
3411
3448
  ] }),
3412
- /* @__PURE__ */ jsx16(VaultRow, { label: "Passphrase", children: /* @__PURE__ */ jsx16(Field6, { type: "password", value: passphrase, autoComplete: "current-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) })
3449
+ /* @__PURE__ */ jsx17(VaultRow, { label: "Passphrase", children: /* @__PURE__ */ jsx17(Field6, { type: "password", value: passphrase, autoComplete: "current-password", "aria-label": "Backup passphrase", onChange: (e) => setPassphrase(e.target.value) }) })
3413
3450
  ] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
3414
- /* @__PURE__ */ jsx16(Summary, { value: restorePreview }),
3415
- !result ? /* @__PURE__ */ jsx16(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
3416
- !result ? /* @__PURE__ */ jsx16("p", { className: "px-1 text-xs text-muted-foreground", children: "Restored items start disabled and restricted." }) : /* @__PURE__ */ jsx16(VaultSection, { title: `${result.created} restored \xB7 ${result.replayed} already \xB7 ${result.refused} refused \xB7 ${result.retryable_failure} to retry`, children: result.results.map((r) => /* @__PURE__ */ jsx16(VaultRow, { label: names.get(r.source_item_id) ?? "Credential", children: /* @__PURE__ */ jsxs16("span", { className: r.status === "refused" || r.status === "retryable_failure" ? "text-destructive" : "text-foreground", children: [
3451
+ /* @__PURE__ */ jsx17(Summary, { value: restorePreview }),
3452
+ !result ? /* @__PURE__ */ jsx17(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
3453
+ !result ? /* @__PURE__ */ jsx17("p", { className: "px-1 text-xs text-muted-foreground", children: "Restored items start disabled and restricted." }) : /* @__PURE__ */ jsx17(VaultSection, { title: `${result.created} restored \xB7 ${result.replayed} already \xB7 ${result.refused} refused \xB7 ${result.retryable_failure} to retry`, children: result.results.map((r) => /* @__PURE__ */ jsx17(VaultRow, { label: names.get(r.source_item_id) ?? "Credential", children: /* @__PURE__ */ jsxs16("span", { className: r.status === "refused" || r.status === "retryable_failure" ? "text-destructive" : "text-foreground", children: [
3417
3454
  RECORD_STATUS[r.status],
3418
3455
  r.reason === "alias_conflict" ? " \xB7 name in use" : ""
3419
3456
  ] }) }, r.source_item_id)) })
3420
3457
  ] }) }),
3421
- /* @__PURE__ */ jsx16(ErrorLine, { message: error })
3458
+ /* @__PURE__ */ jsx17(ErrorLine, { message: error })
3422
3459
  ] });
3423
3460
  }
3424
3461
 
@@ -3427,7 +3464,7 @@ import { useMemo, useState as useState18 } from "react";
3427
3464
  import { Button as Button14, Select as Select5 } from "@ai-matrx/design-system/controls";
3428
3465
  import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
3429
3466
  import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
3430
- import { Fragment as Fragment11, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
3467
+ import { Fragment as Fragment11, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3431
3468
  var FORMATS = [
3432
3469
  { value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
3433
3470
  { value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
@@ -3508,8 +3545,8 @@ function ExportPanel({ port, items, onClose }) {
3508
3545
  size: "lg",
3509
3546
  onClose,
3510
3547
  footer: /* @__PURE__ */ jsxs17(Fragment11, { children: [
3511
- /* @__PURE__ */ jsx17(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
3512
- preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx17(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
3548
+ /* @__PURE__ */ jsx18(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
3549
+ preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx18(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
3513
3550
  "Download ",
3514
3551
  eligible
3515
3552
  ] }) : /* @__PURE__ */ jsxs17(Button14, { variant: "primary", disabled: busy || selected.size === 0, onClick: () => void review(), children: [
@@ -3518,7 +3555,7 @@ function ExportPanel({ port, items, onClose }) {
3518
3555
  ] })
3519
3556
  ] }),
3520
3557
  children: [
3521
- /* @__PURE__ */ jsx17(VaultSection, { children: /* @__PURE__ */ jsx17(VaultRow, { label: "Format", hint: format?.hint, children: /* @__PURE__ */ jsx17(
3558
+ /* @__PURE__ */ jsx18(VaultSection, { children: /* @__PURE__ */ jsx18(VaultRow, { label: "Format", hint: format?.hint, children: /* @__PURE__ */ jsx18(
3522
3559
  Select5,
3523
3560
  {
3524
3561
  value: profile,
@@ -3530,21 +3567,21 @@ function ExportPanel({ port, items, onClose }) {
3530
3567
  }
3531
3568
  }
3532
3569
  ) }) }),
3533
- /* @__PURE__ */ jsx17(
3570
+ /* @__PURE__ */ jsx18(
3534
3571
  VaultSection,
3535
3572
  {
3536
3573
  title: `${selected.size} of ${plural(logins.length, "login")}`,
3537
3574
  actions: /* @__PURE__ */ jsxs17(Fragment11, { children: [
3538
- /* @__PURE__ */ jsx17(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
3575
+ /* @__PURE__ */ jsx18(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
3539
3576
  changed();
3540
3577
  setSelected(new Set(logins.map((l) => l.id)));
3541
3578
  }, children: "All" }),
3542
- /* @__PURE__ */ jsx17(Button14, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
3579
+ /* @__PURE__ */ jsx18(Button14, { variant: "quiet", disabled: busy || selected.size === 0, onClick: () => {
3543
3580
  changed();
3544
3581
  setSelected(/* @__PURE__ */ new Set());
3545
3582
  }, children: "None" })
3546
3583
  ] }),
3547
- children: logins.length === 0 ? /* @__PURE__ */ jsx17(Empty, { children: "No website logins to export." }) : /* @__PURE__ */ jsx17(
3584
+ children: logins.length === 0 ? /* @__PURE__ */ jsx18(Empty, { children: "No website logins to export." }) : /* @__PURE__ */ jsx18(
3548
3585
  Windowed,
3549
3586
  {
3550
3587
  items: logins,
@@ -3552,7 +3589,7 @@ function ExportPanel({ port, items, onClose }) {
3552
3589
  const p = reasons.get(item.id);
3553
3590
  const left = p && !p.eligible;
3554
3591
  const omitted = p ? omissionText2(p.omissions) : "";
3555
- return /* @__PURE__ */ jsx17(
3592
+ return /* @__PURE__ */ jsx18(
3556
3593
  PickLine,
3557
3594
  {
3558
3595
  title: item.name,
@@ -3570,7 +3607,7 @@ function ExportPanel({ port, items, onClose }) {
3570
3607
  )
3571
3608
  }
3572
3609
  ),
3573
- /* @__PURE__ */ jsx17(ErrorLine, { message: error })
3610
+ /* @__PURE__ */ jsx18(ErrorLine, { message: error })
3574
3611
  ]
3575
3612
  }
3576
3613
  );
@@ -4416,7 +4453,7 @@ async function parseImportFile(source, file, limits, signal) {
4416
4453
  }
4417
4454
 
4418
4455
  // src/io/ImportPanel.tsx
4419
- import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
4456
+ import { Fragment as Fragment12, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
4420
4457
  var ROLE_OPTIONS = [
4421
4458
  { value: "keep", label: "Keep encrypted" },
4422
4459
  { value: "title", label: "Name" },
@@ -4592,25 +4629,25 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4592
4629
  const stage = done ? "done" : draft ? "review" : "choose";
4593
4630
  const busy = running !== null || reading;
4594
4631
  const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4595
- /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
4596
- source === "env" ? /* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
4632
+ /* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
4633
+ source === "env" ? /* @__PURE__ */ jsx19(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx19(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
4597
4634
  ] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4598
- running ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
4599
- /* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: busy || chosen === 0 || ambiguous === true || needsApproval, onClick: start, children: running ? `Importing ${running.done} of ${running.total}` : `Import ${chosen}` })
4635
+ running ? /* @__PURE__ */ jsx19(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
4636
+ /* @__PURE__ */ jsx19(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx19(ImportGlyph, { className: "size-4" }), disabled: busy || chosen === 0 || ambiguous === true || needsApproval, onClick: start, children: running ? `Importing ${running.done} of ${running.total}` : `Import ${chosen}` })
4600
4637
  ] }) : /* @__PURE__ */ jsxs18(Fragment12, { children: [
4601
- done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", disabled: busy, onClick: retry, children: running ? `Importing ${running.done} of ${running.total}` : `Try ${done.failed.length + done.untried.length} again` }) : null,
4602
- /* @__PURE__ */ jsx18(Button15, { variant: "primary", onClick: onClose, children: "Done" })
4638
+ done && done.failed.length + done.untried.length > 0 ? /* @__PURE__ */ jsx19(Button15, { variant: "outline", disabled: busy, onClick: retry, children: running ? `Importing ${running.done} of ${running.total}` : `Try ${done.failed.length + done.untried.length} again` }) : null,
4639
+ /* @__PURE__ */ jsx19(Button15, { variant: "primary", onClick: onClose, children: "Done" })
4603
4640
  ] });
4604
4641
  return /* @__PURE__ */ jsxs18(Panel, { title: "Import", size: "xl", onClose, footer, children: [
4605
4642
  stage === "choose" ? /* @__PURE__ */ jsxs18(VaultSection, { children: [
4606
- /* @__PURE__ */ jsx18(VaultRow, { label: "Source", actions: help && host.openUrl ? /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: () => host.openUrl?.(help), children: "How to export" }) : void 0, children: /* @__PURE__ */ jsx18(Select6, { value: source, options: SOURCE_OPTIONS, "aria-label": "Source", onValueChange: (s) => {
4643
+ /* @__PURE__ */ jsx19(VaultRow, { label: "Source", actions: help && host.openUrl ? /* @__PURE__ */ jsx19(Button15, { variant: "quiet", onClick: () => host.openUrl?.(help), children: "How to export" }) : void 0, children: /* @__PURE__ */ jsx19(Select6, { value: source, options: SOURCE_OPTIONS, "aria-label": "Source", onValueChange: (s) => {
4607
4644
  setSource(s);
4608
4645
  setError(null);
4609
4646
  } }) }),
4610
- source === "env" ? /* @__PURE__ */ jsx18(VaultRow, { label: ".env text", hint: "Same key updates in place", top: true, children: /* @__PURE__ */ jsx18(Textarea2, { mono: true, rows: 7, value: envText, autoComplete: "off", spellCheck: false, "aria-label": ".env text", placeholder: "OPENAI_API_KEY=sk-...\nDATABASE_URL=postgres://...", onChange: (e) => setEnvText(e.target.value) }) }) : null,
4647
+ source === "env" ? /* @__PURE__ */ jsx19(VaultRow, { label: ".env text", hint: "Same key updates in place", top: true, children: /* @__PURE__ */ jsx19(Textarea2, { mono: true, rows: 7, value: envText, autoComplete: "off", spellCheck: false, "aria-label": ".env text", placeholder: "OPENAI_API_KEY=sk-...\nDATABASE_URL=postgres://...", onChange: (e) => setEnvText(e.target.value) }) }) : null,
4611
4648
  /* @__PURE__ */ jsxs18(VaultRow, { label: "File", hint: fileName ?? void 0, children: [
4612
- /* @__PURE__ */ jsx18(Button15, { variant: "outline", disabled: reading, onClick: () => fileInput.current?.click(), children: reading ? "Reading\u2026" : source === "env" ? "Load a file" : "Choose a file" }),
4613
- /* @__PURE__ */ jsx18(
4649
+ /* @__PURE__ */ jsx19(Button15, { variant: "outline", disabled: reading, onClick: () => fileInput.current?.click(), children: reading ? "Reading\u2026" : source === "env" ? "Load a file" : "Choose a file" }),
4650
+ /* @__PURE__ */ jsx19(
4614
4651
  "input",
4615
4652
  {
4616
4653
  ref: fileInput,
@@ -4625,44 +4662,44 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4625
4662
  }
4626
4663
  )
4627
4664
  ] }),
4628
- source === "env" ? /* @__PURE__ */ jsx18(VaultRow, { label: "Sandboxes", hint: "Pass these values to agent sandboxes", children: /* @__PURE__ */ jsx18(Switch4, { checked: injectSandbox, onCheckedChange: setInjectSandbox, "aria-label": "Use in sandboxes" }) }) : null
4665
+ source === "env" ? /* @__PURE__ */ jsx19(VaultRow, { label: "Sandboxes", hint: "Pass these values to agent sandboxes", children: /* @__PURE__ */ jsx19(Switch4, { checked: injectSandbox, onCheckedChange: setInjectSandbox, "aria-label": "Use in sandboxes" }) }) : null
4629
4666
  ] }) : null,
4630
4667
  stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4631
- organizations.length > 0 ? /* @__PURE__ */ jsx18(VaultSection, { children: /* @__PURE__ */ jsx18(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx18(Select6, { value: destination, options: destinationOptions, "aria-label": "Save to", onValueChange: (v) => draft.kind === "file" ? restart({ destination: v }) : setDestination(v) }) }) }) : null,
4632
- /* @__PURE__ */ jsx18(
4668
+ organizations.length > 0 ? /* @__PURE__ */ jsx19(VaultSection, { children: /* @__PURE__ */ jsx19(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx19(Select6, { value: destination, options: destinationOptions, "aria-label": "Save to", onValueChange: (v) => draft.kind === "file" ? restart({ destination: v }) : setDestination(v) }) }) }) : null,
4669
+ /* @__PURE__ */ jsx19(
4633
4670
  VaultSection,
4634
4671
  {
4635
4672
  title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
4636
4673
  actions: /* @__PURE__ */ jsxs18(Fragment12, { children: [
4637
- /* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(draft.kind === "env" ? new Set(envKeys.map((e) => e.key + e.text)) : defaultSelection(lines)), children: "Reset" }),
4638
- /* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
4674
+ /* @__PURE__ */ jsx19(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(draft.kind === "env" ? new Set(envKeys.map((e) => e.key + e.text)) : defaultSelection(lines)), children: "Reset" }),
4675
+ /* @__PURE__ */ jsx19(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
4639
4676
  ] }),
4640
- children: draft.kind === "env" ? /* @__PURE__ */ jsx18(
4677
+ children: draft.kind === "env" ? /* @__PURE__ */ jsx19(
4641
4678
  Windowed,
4642
4679
  {
4643
4680
  items: envKeys,
4644
4681
  render: (e) => {
4645
4682
  const id = e.key + e.text;
4646
- return /* @__PURE__ */ jsx18(PickLine, { title: e.key, detail: "Value hidden", checked: selected.has(id), disabled: busy, onChange: (on) => toggle(setSelected, id, on) }, id);
4683
+ return /* @__PURE__ */ jsx19(PickLine, { title: e.key, detail: "Value hidden", checked: selected.has(id), disabled: busy, onChange: (on) => toggle(setSelected, id, on) }, id);
4647
4684
  }
4648
4685
  }
4649
- ) : lines.length === 0 ? /* @__PURE__ */ jsx18(Empty, { children: "Nothing to import in this file." }) : /* @__PURE__ */ jsx18(
4686
+ ) : lines.length === 0 ? /* @__PURE__ */ jsx19(Empty, { children: "Nothing to import in this file." }) : /* @__PURE__ */ jsx19(
4650
4687
  Windowed,
4651
4688
  {
4652
4689
  items: lines,
4653
4690
  render: (l) => {
4654
4691
  const badge = STATE_BADGE[l.state];
4655
- return /* @__PURE__ */ jsx18(PickLine, { title: l.title, detail: l.reason ?? l.detail, checked: selected.has(l.key), disabled: busy || !selectable(l), badge: badge?.text, tone: badge?.tone, onChange: (on) => toggle(setSelected, l.key, on) }, l.key);
4692
+ return /* @__PURE__ */ jsx19(PickLine, { title: l.title, detail: l.reason ?? l.detail, checked: selected.has(l.key), disabled: busy || !selectable(l), badge: badge?.text, tone: badge?.tone, onChange: (on) => toggle(setSelected, l.key, on) }, l.key);
4656
4693
  }
4657
4694
  }
4658
4695
  )
4659
4696
  }
4660
4697
  ),
4661
- draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */ jsx18(VaultSection, { children: /* @__PURE__ */ jsx18(VaultRow, { label: "Visible details", hint: "Approve saving websites and public keys in the clear", children: /* @__PURE__ */ jsx18(Switch4, { checked: approvedVisible, disabled: busy, onCheckedChange: setApprovedVisible, "aria-label": "Approve visible details" }) }) }) : null,
4662
- draft.kind === "file" ? /* @__PURE__ */ jsx18(Notices, { draft }) : null,
4663
- draft.kind === "file" ? /* @__PURE__ */ jsx18(More, { children: /* @__PURE__ */ jsxs18(VaultSection, { children: [
4664
- /* @__PURE__ */ jsx18(VaultRow, { label: "Browser fill", hint: "Needs username, password and an https address", children: /* @__PURE__ */ jsx18(Switch4, { checked: browserFill, disabled: busy, onCheckedChange: (on) => restart({ browserFill: on }), "aria-label": "Browser fill" }) }),
4665
- draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */ jsx18(VaultRow, { label: header || `Column ${index + 1}`, children: /* @__PURE__ */ jsx18(
4698
+ draft.kind === "file" && draft.parsed.kind === "structured" ? /* @__PURE__ */ jsx19(VaultSection, { children: /* @__PURE__ */ jsx19(VaultRow, { label: "Visible details", hint: "Approve saving websites and public keys in the clear", children: /* @__PURE__ */ jsx19(Switch4, { checked: approvedVisible, disabled: busy, onCheckedChange: setApprovedVisible, "aria-label": "Approve visible details" }) }) }) : null,
4699
+ draft.kind === "file" ? /* @__PURE__ */ jsx19(Notices, { draft }) : null,
4700
+ draft.kind === "file" ? /* @__PURE__ */ jsx19(More, { children: /* @__PURE__ */ jsxs18(VaultSection, { children: [
4701
+ /* @__PURE__ */ jsx19(VaultRow, { label: "Browser fill", hint: "Needs username, password and an https address", children: /* @__PURE__ */ jsx19(Switch4, { checked: browserFill, disabled: busy, onCheckedChange: (on) => restart({ browserFill: on }), "aria-label": "Browser fill" }) }),
4702
+ draft.parsed.kind === "csv" ? draft.parsed.preview.headers.map((header, index) => /* @__PURE__ */ jsx19(VaultRow, { label: header || `Column ${index + 1}`, children: /* @__PURE__ */ jsx19(
4666
4703
  Select6,
4667
4704
  {
4668
4705
  value: draft.mapping[index] ?? "keep",
@@ -4672,20 +4709,20 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4672
4709
  }
4673
4710
  ) }, `${header}-${index}`)) : null
4674
4711
  ] }) }) : null,
4675
- ambiguous ? /* @__PURE__ */ jsx18(ErrorLine, { message: "Each of name, username, password, notes and one-time password can be used by one column." }) : null
4712
+ ambiguous ? /* @__PURE__ */ jsx19(ErrorLine, { message: "Each of name, username, password, notes and one-time password can be used by one column." }) : null
4676
4713
  ] }) : null,
4677
4714
  stage === "done" && done ? /* @__PURE__ */ jsxs18(VaultSection, { title: "Result", children: [
4678
- /* @__PURE__ */ jsx18(VaultRow, { label: "Created", children: /* @__PURE__ */ jsx18("span", { className: "text-foreground", children: done.created.length }) }),
4679
- /* @__PURE__ */ jsx18(VaultRow, { label: "Skipped", children: /* @__PURE__ */ jsx18("span", { className: "text-foreground", children: done.skipped }) }),
4680
- /* @__PURE__ */ jsx18(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx18("span", { className: done.failed.length > 0 ? "text-destructive" : "text-foreground", children: done.failed.length }) }),
4681
- done.untried.length > 0 ? /* @__PURE__ */ jsx18(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx18("span", { className: "text-foreground", children: done.untried.length }) }) : null,
4682
- done.withOtp > 0 ? /* @__PURE__ */ jsx18(VaultRow, { label: "Codes", children: /* @__PURE__ */ jsxs18("span", { className: "text-muted-foreground", children: [
4715
+ /* @__PURE__ */ jsx19(VaultRow, { label: "Created", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.created.length }) }),
4716
+ /* @__PURE__ */ jsx19(VaultRow, { label: "Skipped", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.skipped }) }),
4717
+ /* @__PURE__ */ jsx19(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx19("span", { className: done.failed.length > 0 ? "text-destructive" : "text-foreground", children: done.failed.length }) }),
4718
+ done.untried.length > 0 ? /* @__PURE__ */ jsx19(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx19("span", { className: "text-foreground", children: done.untried.length }) }) : null,
4719
+ done.withOtp > 0 ? /* @__PURE__ */ jsx19(VaultRow, { label: "Codes", children: /* @__PURE__ */ jsxs18("span", { className: "text-muted-foreground", children: [
4683
4720
  plural(done.withOtp, "login"),
4684
4721
  " still need the one-time password added."
4685
4722
  ] }) }) : null,
4686
- done.failed.map((f) => /* @__PURE__ */ jsx18(VaultRow, { label: f.title, children: /* @__PURE__ */ jsx18("span", { className: "block truncate text-destructive", title: f.reason, children: f.reason }) }, f.key))
4723
+ done.failed.map((f) => /* @__PURE__ */ jsx19(VaultRow, { label: f.title, children: /* @__PURE__ */ jsx19("span", { className: "block truncate text-destructive", title: f.reason, children: f.reason }) }, f.key))
4687
4724
  ] }) : null,
4688
- /* @__PURE__ */ jsx18(ErrorLine, { message: error })
4725
+ /* @__PURE__ */ jsx19(ErrorLine, { message: error })
4689
4726
  ] });
4690
4727
  }
4691
4728
  function toggle(set, key, on) {
@@ -4712,35 +4749,22 @@ function Notices({ draft }) {
4712
4749
  }
4713
4750
  }
4714
4751
  if (notes.length === 0) return null;
4715
- return /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-0.5 px-1 text-xs text-muted-foreground", children: notes.map((n) => /* @__PURE__ */ jsx18("span", { children: n }, n)) });
4752
+ return /* @__PURE__ */ jsx19("div", { className: "flex flex-col gap-0.5 px-1 text-xs text-muted-foreground", children: notes.map((n) => /* @__PURE__ */ jsx19("span", { children: n }, n)) });
4716
4753
  }
4717
4754
 
4718
4755
  // src/ItemList.tsx
4719
- import { useEffect as useEffect17, useRef as useRef15, useState as useState27 } from "react";
4720
- import { DropdownMenu as DropdownMenu4, DropdownMenuContent as DropdownMenuContent4, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger as DropdownMenuTrigger4 } from "@ai-matrx/design-system";
4756
+ import { useEffect as useEffect17, useRef as useRef15, useState as useState28 } from "react";
4757
+ import { DropdownMenu as DropdownMenu4, DropdownMenuContent as DropdownMenuContent4, DropdownMenuItem as DropdownMenuItem4, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator as DropdownMenuSeparator4, DropdownMenuTrigger as DropdownMenuTrigger4 } from "@ai-matrx/design-system";
4721
4758
  import { cn as cn13 } from "@ai-matrx/design-system";
4722
- import { Button as Button22, SearchField } from "@ai-matrx/design-system/controls";
4723
-
4724
- // src/ItemIcon.tsx
4725
- import { cn as cn8 } from "@ai-matrx/design-system";
4726
- import { jsx as jsx19 } from "react/jsx-runtime";
4727
- function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
4728
- const box = size === "lg" ? "size-10 rounded-xl text-base" : size === "md" ? "size-8 rounded-lg text-sm" : "size-6 rounded-md text-xs";
4729
- const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
4730
- const initial = siteDomainOf(site).charAt(0).toUpperCase();
4731
- if (initial && /[A-Z0-9]/.test(initial)) {
4732
- return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
4733
- }
4734
- const Glyph = definitionGlyph(definitionKey, family);
4735
- return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center", box, tone), children: /* @__PURE__ */ jsx19(Glyph, { className: size === "lg" ? "size-5" : "size-4" }) });
4736
- }
4759
+ import { Button as Button23, SearchField } from "@ai-matrx/design-system/controls";
4760
+ import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
4737
4761
 
4738
4762
  // src/ItemPane.tsx
4739
- import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState26 } from "react";
4763
+ import { useEffect as useEffect16, useMemo as useMemo3, useRef as useRef14, useState as useState27 } from "react";
4740
4764
  import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
4741
4765
  import { cn as cn12 } from "@ai-matrx/design-system";
4742
- import { Badge as Badge7, Button as Button21, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch5 } from "@ai-matrx/design-system/controls";
4743
- import { confirm as confirm9 } from "@ai-matrx/kit/confirm-opener";
4766
+ import { Badge as Badge7, Button as Button22, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch6 } from "@ai-matrx/design-system/controls";
4767
+ import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
4744
4768
 
4745
4769
  // src/activity/FilesSection.tsx
4746
4770
  import { formatFileSize as formatFileSize2 } from "@ai-matrx/kit/format";
@@ -4761,12 +4785,13 @@ var PROTECTION = [
4761
4785
  function FilesSection({ item, port, editing, onChanged }) {
4762
4786
  const confirmed = useConfirmed();
4763
4787
  const canEdit = editing && item.capabilities.canEdit;
4788
+ const canAdd = item.capabilities.canEdit;
4764
4789
  const [busy, setBusy] = useState20(null);
4765
4790
  const [error, setError] = useState20(null);
4766
4791
  const [pending, setPending] = useState20(null);
4767
4792
  const [dragging, setDragging] = useState20(false);
4768
4793
  const picker = useRef13(null);
4769
- if (!canEdit && item.attachments.length === 0) return null;
4794
+ if (!canAdd && item.attachments.length === 0) return null;
4770
4795
  async function run(key, work, fallback) {
4771
4796
  setBusy(key);
4772
4797
  setError(null);
@@ -4788,7 +4813,7 @@ function FilesSection({ item, port, editing, onChanged }) {
4788
4813
  setPending(file);
4789
4814
  }
4790
4815
  function drop(e) {
4791
- if (!canEdit) return;
4816
+ if (!canAdd) return;
4792
4817
  e.preventDefault();
4793
4818
  setDragging(false);
4794
4819
  choose(e.dataTransfer.files[0]);
@@ -4801,22 +4826,23 @@ function FilesSection({ item, port, editing, onChanged }) {
4801
4826
  "div",
4802
4827
  {
4803
4828
  className: cn9("rounded-xl", dragging && "outline outline-2 outline-primary"),
4804
- onDragOver: canEdit ? (e) => {
4829
+ onDragOver: canAdd ? (e) => {
4805
4830
  e.preventDefault();
4806
4831
  setDragging(true);
4807
4832
  } : void 0,
4808
- onDragLeave: canEdit ? () => setDragging(false) : void 0,
4809
- onDrop: canEdit ? drop : void 0,
4833
+ onDragLeave: canAdd ? () => setDragging(false) : void 0,
4834
+ onDrop: canAdd ? drop : void 0,
4810
4835
  children: /* @__PURE__ */ jsxs19(
4811
4836
  VaultSection,
4812
4837
  {
4813
- title: "Files",
4814
- actions: canEdit ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PlusGlyph, {}), disabled: busy !== null, onClick: () => picker.current?.click(), children: "Add file" }) : void 0,
4838
+ title: editing || item.attachments.length > 0 || pending ? "Files" : void 0,
4839
+ actions: canAdd && (editing || item.attachments.length > 0) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PlusGlyph, {}), disabled: busy !== null, onClick: () => picker.current?.click(), children: "Add file" }) : void 0,
4815
4840
  children: [
4816
- canEdit ? /* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, onChange: (e) => {
4841
+ canAdd ? /* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
4817
4842
  choose(e.target.files?.[0]);
4818
4843
  e.target.value = "";
4819
4844
  } }) : null,
4845
+ !editing && canAdd && item.attachments.length === 0 && !pending ? /* @__PURE__ */ jsx20(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
4820
4846
  item.attachments.map(
4821
4847
  (a) => canEdit ? /* @__PURE__ */ jsx20(EditableFile, { port, item, file: a, busy, run, onDownload: () => void download(a), onTooBig: () => setError(TOO_BIG) }, a.id) : /* @__PURE__ */ jsx20(
4822
4848
  VaultRow,
@@ -4829,7 +4855,7 @@ function FilesSection({ item, port, editing, onChanged }) {
4829
4855
  a.id
4830
4856
  )
4831
4857
  ),
4832
- canEdit && pending ? /* @__PURE__ */ jsx20(NewFile, { file: pending, busy: busy === "add", onCancel: () => setPending(null), onAdd: async (details) => {
4858
+ canAdd && pending ? /* @__PURE__ */ jsx20(NewFile, { file: pending, busy: busy === "add", onCancel: () => setPending(null), onAdd: async (details) => {
4833
4859
  if (await run("add", () => port.activity.addFile(item, pending, details), "The file could not be added.")) setPending(null);
4834
4860
  } }) : null,
4835
4861
  canEdit && item.attachments.length === 0 && !pending ? /* @__PURE__ */ jsx20("div", { className: "px-4 py-3 text-sm text-muted-foreground", children: "Drop a file here or choose Add file" }) : null,
@@ -4950,6 +4976,57 @@ function confirmSeal(label) {
4950
4976
  variant: "destructive"
4951
4977
  });
4952
4978
  }
4979
+ function DraftFilesSection({ files, onFiles }) {
4980
+ const [pending, setPending] = useState20(null);
4981
+ const [error, setError] = useState20(null);
4982
+ const [dragging, setDragging] = useState20(false);
4983
+ const picker = useRef13(null);
4984
+ const choose = (file) => {
4985
+ if (!file) return;
4986
+ if (fileTooBig(file.size)) return setError(TOO_BIG);
4987
+ setError(null);
4988
+ setPending(file);
4989
+ };
4990
+ return /* @__PURE__ */ jsx20(
4991
+ "div",
4992
+ {
4993
+ className: cn9("rounded-xl", dragging && "outline outline-2 outline-primary"),
4994
+ onDragOver: (e) => {
4995
+ e.preventDefault();
4996
+ setDragging(true);
4997
+ },
4998
+ onDragLeave: () => setDragging(false),
4999
+ onDrop: (e) => {
5000
+ e.preventDefault();
5001
+ setDragging(false);
5002
+ choose(e.dataTransfer.files[0]);
5003
+ },
5004
+ children: /* @__PURE__ */ jsxs19(VaultSection, { title: files.length > 0 || pending ? "Files" : void 0, actions: files.length > 0 ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PlusGlyph, {}), onClick: () => picker.current?.click(), children: "Add file" }) : void 0, children: [
5005
+ /* @__PURE__ */ jsx20("input", { ref: picker, type: "file", hidden: true, "aria-label": "Choose a file", onChange: (e) => {
5006
+ choose(e.target.files?.[0]);
5007
+ e.target.value = "";
5008
+ } }),
5009
+ files.map((f, i) => /* @__PURE__ */ jsx20(VaultRow, { label: f.label, hint: f.description ?? void 0, actions: /* @__PURE__ */ jsx20(Button16, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx20(XGlyph, {}), "aria-label": `Remove ${f.label}`, onClick: () => onFiles(files.filter((_, j) => j !== i)) }), children: /* @__PURE__ */ jsxs19("span", { className: "flex min-w-0 items-center gap-2", children: [
5010
+ /* @__PURE__ */ jsx20("span", { className: "truncate", children: f.file.name }),
5011
+ /* @__PURE__ */ jsx20("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize2(f.file.size) })
5012
+ ] }) }, `${f.file.name}-${i}`)),
5013
+ pending ? /* @__PURE__ */ jsx20(
5014
+ NewFile,
5015
+ {
5016
+ file: pending,
5017
+ busy: false,
5018
+ onCancel: () => setPending(null),
5019
+ onAdd: async (d) => {
5020
+ onFiles([...files, { file: pending, ...d }]);
5021
+ setPending(null);
5022
+ }
5023
+ }
5024
+ ) : files.length === 0 ? /* @__PURE__ */ jsx20(AddRow, { label: "Files", onAdd: () => picker.current?.click(), children: "Add file" }) : null,
5025
+ error ? /* @__PURE__ */ jsx20("p", { role: "alert", className: "px-4 py-2 text-sm text-destructive", children: error }) : null
5026
+ ] })
5027
+ }
5028
+ );
5029
+ }
4953
5030
 
4954
5031
  // src/fields/RecoveryCodesRow.tsx
4955
5032
  import { useState as useState21 } from "react";
@@ -5057,6 +5134,134 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
5057
5134
  );
5058
5135
  }
5059
5136
 
5137
+ // src/fields/DraftRows.tsx
5138
+ import { useState as useState22 } from "react";
5139
+ import { Button as Button18, Field as Field8, SegmentedControl as SegmentedControl5, Select as Select7, Switch as Switch5 } from "@ai-matrx/design-system/controls";
5140
+ import { RecordId } from "@ai-matrx/design-system";
5141
+ import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
5142
+ import { Fragment as Fragment15, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
5143
+ var HANDLINGS = ["visible", "revealable", "sealed"];
5144
+ var hint = (text, tone = "muted") => /* @__PURE__ */ jsx22("span", { className: tone === "destructive" ? "text-destructive" : void 0, title: text, children: text });
5145
+ var hasSecretSettings = (s) => Boolean(s.envKey?.trim() || s.injectIntoSandbox || s.handling && s.handling !== "revealable");
5146
+ function SecretBuilderRow({ field, onChange, onRemove }) {
5147
+ const [open, setOpen] = useState22(hasSecretSettings(field));
5148
+ const env = field.envKey ?? "";
5149
+ const envProblem = envKeyProblem(env);
5150
+ const envOk = env.trim() !== "" && !envProblem;
5151
+ const handling = field.handling ?? "revealable";
5152
+ const name = field.label.trim() || "Secret";
5153
+ const chooseHandling = async (next) => {
5154
+ if (next === handling) return;
5155
+ if (next === "sealed") {
5156
+ const ok = await confirm7({
5157
+ title: `Seal ${name} permanently?`,
5158
+ description: "Once saved, no person can see or copy it again; only automation can use it.",
5159
+ confirmLabel: "Seal",
5160
+ variant: "destructive"
5161
+ });
5162
+ if (!ok) return;
5163
+ }
5164
+ onChange({ handling: next });
5165
+ };
5166
+ return /* @__PURE__ */ jsxs21(Fragment15, { children: [
5167
+ /* @__PURE__ */ jsx22(
5168
+ CustomEditRow,
5169
+ {
5170
+ label: field.label,
5171
+ value: field.value,
5172
+ secret: true,
5173
+ onLabel: (v) => onChange({ label: v }),
5174
+ onValue: (v) => onChange({ value: v }),
5175
+ onRemove,
5176
+ onPasteValue: (text) => {
5177
+ const a = parseEnvAssignment(text);
5178
+ if (!a) return false;
5179
+ onChange({ envKey: a.key, value: a.value, ...field.label.trim() ? {} : { label: labelFromEnvKey(a.key) } });
5180
+ setOpen(true);
5181
+ return true;
5182
+ },
5183
+ extra: /* @__PURE__ */ jsxs21(Fragment15, { children: [
5184
+ handling !== "sealed" ? /* @__PURE__ */ jsx22(GenerateButton, { onUse: (v) => onChange({ value: v }) }) : null,
5185
+ /* @__PURE__ */ jsx22(Button18, { variant: "quiet", icon: /* @__PURE__ */ jsx22(SlidersGlyph, {}), "aria-label": `${name} settings`, pressed: open, onClick: () => setOpen((o) => !o) })
5186
+ ] })
5187
+ }
5188
+ ),
5189
+ open ? /* @__PURE__ */ jsxs21(Fragment15, { children: [
5190
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Env key", hint: envProblem ? hint(envProblem, "destructive") : hint("The name sandboxes and workflows use"), children: /* @__PURE__ */ jsx22(
5191
+ Field8,
5192
+ {
5193
+ className: "w-full font-mono",
5194
+ "aria-label": `${name} env key`,
5195
+ "aria-invalid": Boolean(envProblem),
5196
+ placeholder: "e.g. GITHUB_TOKEN",
5197
+ autoComplete: "off",
5198
+ spellCheck: false,
5199
+ value: env,
5200
+ onChange: (e) => onChange({ envKey: e.target.value, ...e.target.value.trim() ? {} : { injectIntoSandbox: false } })
5201
+ }
5202
+ ) }),
5203
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Who can see it", hint: hint(HANDLING_WORDS[handling].hint), children: /* @__PURE__ */ jsx22(
5204
+ SegmentedControl5,
5205
+ {
5206
+ "aria-label": `Who can see ${name}`,
5207
+ value: handling,
5208
+ onValueChange: (v) => void chooseHandling(v),
5209
+ data: HANDLINGS.map((h) => ({ value: h, label: HANDLING_WORDS[h].label, title: HANDLING_WORDS[h].hint }))
5210
+ }
5211
+ ) }),
5212
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Use in sandbox", hint: envOk ? hint("Sandboxes get it as an env variable") : hint("Needs an env key"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": `Use ${name} in sandbox`, checked: envOk && field.injectIntoSandbox === true, disabled: !envOk, onCheckedChange: (v) => onChange({ injectIntoSandbox: v }) }) })
5213
+ ] }) : null
5214
+ ] });
5215
+ }
5216
+ function withMfaMethod(custom, v) {
5217
+ const rest = custom.filter((c) => c.key !== MFA_METHOD_KEY);
5218
+ return v === "sms" || v === "push_or_other" ? [...rest, { key: MFA_METHOD_KEY, label: "Two-factor method", value: v }] : rest;
5219
+ }
5220
+ function DraftTwoFactorRow({ custom, onCustom }) {
5221
+ const value = custom.find((c) => c.key === MFA_METHOD_KEY)?.value || "none";
5222
+ return /* @__PURE__ */ jsx22(VaultRow, { label: "Two-factor", children: /* @__PURE__ */ jsx22(
5223
+ Select7,
5224
+ {
5225
+ value: value === "sms" || value === "push_or_other" ? value : "none",
5226
+ "aria-label": "Two-factor method",
5227
+ options: MFA_OPTIONS.map((o) => ({ value: o.value, label: o.label })),
5228
+ onValueChange: (v) => onCustom(withMfaMethod(custom, v))
5229
+ }
5230
+ ) });
5231
+ }
5232
+ var defaultBrowserSettings = (hasWebsite) => ({ uriMatchMode: "host", browserFillEnabled: hasWebsite });
5233
+ function DraftBrowserRows({ value, hasWebsite, onChange }) {
5234
+ return /* @__PURE__ */ jsxs21(Fragment15, { children: [
5235
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Website matching", hint: hint(MATCH_WORDS[value.uriMatchMode].hint), children: /* @__PURE__ */ jsx22(
5236
+ Select7,
5237
+ {
5238
+ "aria-label": "Website matching",
5239
+ value: value.uriMatchMode,
5240
+ options: MATCH_MODES.map((m) => ({ value: m, label: MATCH_WORDS[m].label })),
5241
+ onValueChange: (m) => onChange({ ...value, uriMatchMode: m })
5242
+ }
5243
+ ) }),
5244
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Fill in browser", hint: hint(hasWebsite ? value.browserFillEnabled ? "Offered on matching pages" : "Never filled automatically" : "Add a website first"), children: /* @__PURE__ */ jsx22(Switch5, { "aria-label": "Fill in browser", checked: hasWebsite && value.browserFillEnabled, disabled: !hasWebsite, onCheckedChange: (v) => onChange({ ...value, browserFillEnabled: v }) }) })
5245
+ ] });
5246
+ }
5247
+ function AssignResult({ sent, onAnother, onDone }) {
5248
+ return /* @__PURE__ */ jsxs21("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", role: "status", children: [
5249
+ /* @__PURE__ */ jsxs21(VaultSection, { title: /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1.5", children: [
5250
+ /* @__PURE__ */ jsx22(CheckGlyph, { className: "size-4 text-success" }),
5251
+ "Sent to ",
5252
+ sent.recipientEmail
5253
+ ] }), children: [
5254
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx22("span", { className: "block truncate", children: sent.name }) }),
5255
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Item ID", children: /* @__PURE__ */ jsx22(RecordId, { value: sent.id, label: "Item" }) }),
5256
+ /* @__PURE__ */ jsx22(VaultRow, { label: "Password", children: /* @__PURE__ */ jsx22("span", { className: "block truncate text-muted-foreground", children: sent.generated ? "Generated privately, never shown to you" : "Theirs now; you keep no access" }) })
5257
+ ] }),
5258
+ /* @__PURE__ */ jsxs21("div", { className: "flex justify-end gap-2", children: [
5259
+ /* @__PURE__ */ jsx22(Button18, { variant: "outline", icon: /* @__PURE__ */ jsx22(PlusGlyph, {}), onClick: onAnother, children: "Create another" }),
5260
+ /* @__PURE__ */ jsx22(Button18, { variant: "primary", onClick: onDone, children: "Done" })
5261
+ ] })
5262
+ ] });
5263
+ }
5264
+
5060
5265
  // src/ItemPane.tsx
5061
5266
  import { HistoryIcon, SettingsIcon, UsersIcon as UsersIcon2 } from "@ai-matrx/design-system/icons";
5062
5267
  import { dropKeptDraft, keepDraft, readKeptDraft } from "@ai-matrx/kit/drafts";
@@ -5183,15 +5388,15 @@ function targetLabel(t) {
5183
5388
  }
5184
5389
 
5185
5390
  // src/extension/UseOnSiteButton.tsx
5186
- import { useState as useState22 } from "react";
5187
- import { Button as Button18 } from "@ai-matrx/design-system/controls";
5188
- import { jsx as jsx22 } from "react/jsx-runtime";
5391
+ import { useState as useState23 } from "react";
5392
+ import { Button as Button19 } from "@ai-matrx/design-system/controls";
5393
+ import { jsx as jsx23 } from "react/jsx-runtime";
5189
5394
  function canUseOnSite(item, pageUrl) {
5190
5395
  return item.capabilities.canEdit && isFillablePage(pageUrl) && !coversPage(item.loginUrls, item.uriMatchMode, pageUrl);
5191
5396
  }
5192
5397
  function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5193
5398
  const notify = useNotify();
5194
- const [busy, setBusy] = useState22(false);
5399
+ const [busy, setBusy] = useState23(false);
5195
5400
  if (!canUseOnSite(item, pageUrl)) return null;
5196
5401
  const site = pageSite(pageUrl);
5197
5402
  const run = async () => {
@@ -5206,13 +5411,13 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5206
5411
  setBusy(false);
5207
5412
  }
5208
5413
  };
5209
- return /* @__PURE__ */ jsx22(Button18, { variant: "outline", icon: /* @__PURE__ */ jsx22(PlusGlyph, {}), disabled: busy, onClick: () => void run(), title: `Fill this login on ${site}`, children: "Use here" });
5414
+ return /* @__PURE__ */ jsx23(Button19, { variant: "outline", icon: /* @__PURE__ */ jsx23(PlusGlyph, {}), disabled: busy, onClick: () => void run(), title: `Fill this login on ${site}`, children: "Use here" });
5210
5415
  }
5211
5416
 
5212
5417
  // src/sharing/SharePanel.tsx
5213
- import { useEffect as useEffect15, useState as useState25 } from "react";
5214
- import { confirm as confirm8 } from "@ai-matrx/kit/confirm-opener";
5215
- import { Button as Button20, DisclosureHeader as DisclosureHeader3, Field as Field9, RegionSkeleton, Select as Select8 } from "@ai-matrx/design-system/controls";
5418
+ import { useEffect as useEffect15, useState as useState26 } from "react";
5419
+ import { confirm as confirm9 } from "@ai-matrx/kit/confirm-opener";
5420
+ import { Button as Button21, DisclosureHeader as DisclosureHeader3, Field as Field10, RegionSkeleton, Select as Select9 } from "@ai-matrx/design-system/controls";
5216
5421
  import { cn as cn11 } from "@ai-matrx/design-system";
5217
5422
  import { UsersIcon } from "@ai-matrx/design-system/icons";
5218
5423
 
@@ -5268,18 +5473,18 @@ function shareSummary(grants) {
5268
5473
  var MEMBER_CHOICE_DEFAULT = "default";
5269
5474
 
5270
5475
  // src/sharing/parts.tsx
5271
- import { useState as useState23 } from "react";
5476
+ import { useState as useState24 } from "react";
5272
5477
  import { cn as cn10 } from "@ai-matrx/design-system";
5273
- import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
5478
+ import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
5274
5479
  var message = (e, fallback) => {
5275
5480
  const m = e instanceof Error && e.message ? e.message : fallback;
5276
5481
  return copyRefusal(m) ?? m;
5277
5482
  };
5278
5483
  function useConfirmedChange() {
5279
5484
  const confirmed = useConfirmed();
5280
- const [busy, setBusy] = useState23(null);
5281
- const [error, setError] = useState23(null);
5282
- const [notice, setNotice] = useState23(null);
5485
+ const [busy, setBusy] = useState24(null);
5486
+ const [error, setError] = useState24(null);
5487
+ const [notice, setNotice] = useState24(null);
5283
5488
  async function run(key, fn, done) {
5284
5489
  setBusy(key);
5285
5490
  setError(null);
@@ -5298,33 +5503,33 @@ function useConfirmedChange() {
5298
5503
  return { busy, error, notice, run, setNotice };
5299
5504
  }
5300
5505
  function AccessLine({ glyph: G, who, meta, children }) {
5301
- return /* @__PURE__ */ jsxs21("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5302
- /* @__PURE__ */ jsx23(G, { className: "size-4 shrink-0 text-muted-foreground" }),
5303
- /* @__PURE__ */ jsxs21("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
5304
- /* @__PURE__ */ jsx23("span", { className: "truncate text-sm text-foreground", children: who }),
5305
- meta ? /* @__PURE__ */ jsx23("span", { className: "shrink-0 text-xs text-muted-foreground", children: meta }) : null
5506
+ return /* @__PURE__ */ jsxs22("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5507
+ /* @__PURE__ */ jsx24(G, { className: "size-4 shrink-0 text-muted-foreground" }),
5508
+ /* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
5509
+ /* @__PURE__ */ jsx24("span", { className: "truncate text-sm text-foreground", children: who }),
5510
+ meta ? /* @__PURE__ */ jsx24("span", { className: "shrink-0 text-xs text-muted-foreground", children: meta }) : null
5306
5511
  ] }),
5307
- /* @__PURE__ */ jsx23("div", { className: "flex shrink-0 items-center gap-0.5", children })
5512
+ /* @__PURE__ */ jsx24("div", { className: "flex shrink-0 items-center gap-0.5", children })
5308
5513
  ] });
5309
5514
  }
5310
5515
  function StatusLine({ error, notice }) {
5311
5516
  if (!error && !notice) return null;
5312
- return /* @__PURE__ */ jsx23("p", { className: cn10("min-w-0 flex-1 line-clamp-2 text-sm", error ? "text-destructive" : "text-success"), title: error ?? notice ?? void 0, children: error ?? notice });
5517
+ return /* @__PURE__ */ jsx24("p", { className: cn10("min-w-0 flex-1 line-clamp-2 text-sm", error ? "text-destructive" : "text-success"), title: error ?? notice ?? void 0, children: error ?? notice });
5313
5518
  }
5314
5519
 
5315
5520
  // src/sharing/MovePanel.tsx
5316
- import { useState as useState24 } from "react";
5317
- import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
5318
- import { Button as Button19, Field as Field8, Select as Select7 } from "@ai-matrx/design-system/controls";
5319
- import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
5521
+ import { useState as useState25 } from "react";
5522
+ import { confirm as confirm8 } from "@ai-matrx/kit/confirm-opener";
5523
+ import { Button as Button20, Field as Field9, Select as Select8 } from "@ai-matrx/design-system/controls";
5524
+ import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5320
5525
  var NONE = "__none__";
5321
5526
  function MovePanel({ item, port, organizations, onClose, onChanged }) {
5322
5527
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
5323
5528
  const moves = moveDestinations(item, organizations);
5324
5529
  const copies = copyDestinations(organizations, item);
5325
- const [moveTo, setMoveTo] = useState24("");
5326
- const [copyTo, setCopyTo] = useState24("");
5327
- const [email, setEmail] = useState24("");
5530
+ const [moveTo, setMoveTo] = useState25("");
5531
+ const [copyTo, setCopyTo] = useState25("");
5532
+ const [email, setEmail] = useState25("");
5328
5533
  const passkey = isPasskey(item);
5329
5534
  const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
5330
5535
  const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
@@ -5334,7 +5539,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5334
5539
  const move = async () => {
5335
5540
  if (!moveChoice) return;
5336
5541
  const to = destinationOf(moveChoice.value);
5337
- const ok = await confirm7({
5542
+ const ok = await confirm8({
5338
5543
  title: `Move to ${moveChoice.label}?`,
5339
5544
  description: `"${item.name}" stays the same item, so everything using it keeps working. ${itemMoveConsequence(item, to)}.`,
5340
5545
  confirmLabel: "Move"
@@ -5349,7 +5554,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5349
5554
  const give = async () => {
5350
5555
  const to = email.trim();
5351
5556
  if (!isEmail(to)) return;
5352
- const ok = await confirm7({ title: "Give ownership away?", description: giveDescription(item, to), confirmLabel: "Give ownership", variant: "destructive" });
5557
+ const ok = await confirm8({ title: "Give ownership away?", description: giveDescription(item, to), confirmLabel: "Give ownership", variant: "destructive" });
5353
5558
  if (!ok) return;
5354
5559
  const out = await run("give", () => port.sharing.giveOwnership(item, to));
5355
5560
  if (!out) return;
@@ -5362,25 +5567,25 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5362
5567
  if (made) onChanged();
5363
5568
  };
5364
5569
  const nothing = !canMove && !canGive && !canCopy;
5365
- return /* @__PURE__ */ jsx24(
5570
+ return /* @__PURE__ */ jsx25(
5366
5571
  Panel,
5367
5572
  {
5368
5573
  title: "Move or copy",
5369
5574
  size: "md",
5370
5575
  onClose,
5371
- footer: /* @__PURE__ */ jsx24(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx24(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx24(Button19, { variant: "primary", onClick: onClose, children: "Done" }) }),
5372
- children: nothing ? /* @__PURE__ */ jsx24(VaultSection, { children: /* @__PURE__ */ jsx24(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ jsxs22(VaultSection, { children: [
5373
- canMove && moves.length > 0 ? /* @__PURE__ */ jsx24(
5576
+ footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
5577
+ children: nothing ? /* @__PURE__ */ jsx25(VaultSection, { children: /* @__PURE__ */ jsx25(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ jsxs23(VaultSection, { children: [
5578
+ canMove && moves.length > 0 ? /* @__PURE__ */ jsx25(
5374
5579
  VaultRow,
5375
5580
  {
5376
5581
  label: "Move to",
5377
5582
  hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
5378
- actions: /* @__PURE__ */ jsx24(Button19, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
5379
- children: /* @__PURE__ */ jsx24(Select7, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5583
+ actions: /* @__PURE__ */ jsx25(Button20, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
5584
+ children: /* @__PURE__ */ jsx25(Select8, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5380
5585
  }
5381
5586
  ) : null,
5382
- canGive ? /* @__PURE__ */ jsx24(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ jsx24(Button19, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ jsx24(
5383
- Field8,
5587
+ canGive ? /* @__PURE__ */ jsx25(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ jsx25(Button20, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ jsx25(
5588
+ Field9,
5384
5589
  {
5385
5590
  className: "w-full",
5386
5591
  type: "email",
@@ -5393,18 +5598,18 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5393
5598
  onChange: (e) => setEmail(e.target.value)
5394
5599
  }
5395
5600
  ) }) : null,
5396
- canCopy && copies.length > 0 ? /* @__PURE__ */ jsx24(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ jsx24(Button19, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ jsx24(Select7, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
5601
+ canCopy && copies.length > 0 ? /* @__PURE__ */ jsx25(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ jsx25(Button20, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ jsx25(Select8, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
5397
5602
  ] })
5398
5603
  }
5399
5604
  );
5400
5605
  }
5401
5606
 
5402
5607
  // src/sharing/SharePanel.tsx
5403
- import { Fragment as Fragment15, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5608
+ import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
5404
5609
  function useGrants(port, item) {
5405
- const [grants, setGrants] = useState25(null);
5406
- const [loadError, setLoadError] = useState25(null);
5407
- const [nonce, setNonce] = useState25(0);
5610
+ const [grants, setGrants] = useState26(null);
5611
+ const [loadError, setLoadError] = useState26(null);
5612
+ const [nonce, setNonce] = useState26(0);
5408
5613
  const allowed = item.capabilities.canManage;
5409
5614
  useEffect15(() => {
5410
5615
  if (!allowed) return;
@@ -5423,9 +5628,9 @@ function useGrants(port, item) {
5423
5628
  function SharePanel({ item, port, organizations, onClose, onChanged }) {
5424
5629
  const { grants, setGrants, loadError, reload } = useGrants(port, item);
5425
5630
  const { busy, error, notice, run } = useConfirmedChange();
5426
- const [email, setEmail] = useState25("");
5427
- const [level, setLevel] = useState25("use");
5428
- const [more, setMore] = useState25(false);
5631
+ const [email, setEmail] = useState26("");
5632
+ const [level, setLevel] = useState26("use");
5633
+ const [more, setMore] = useState26(false);
5429
5634
  const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
5430
5635
  const orgName = item.owner.label;
5431
5636
  const people = (grants ?? []).filter((g) => g.kind === "person");
@@ -5444,7 +5649,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5444
5649
  if (updated) setGrants((all) => (all ?? []).map((x) => x.id === g.id ? { ...updated, label: updated.label || g.label } : x));
5445
5650
  };
5446
5651
  const revoke = async (g) => {
5447
- const ok = await confirm8({
5652
+ const ok = await confirm9({
5448
5653
  title: g.kind === "organization" ? `Remove from ${g.label}?` : "Remove access?",
5449
5654
  description: g.kind === "organization" ? `${g.label} members can no longer use "${item.name}". It stays in your vault.` : `${g.label} can no longer use "${item.name}". This takes effect at once.`,
5450
5655
  confirmLabel: "Remove",
@@ -5460,7 +5665,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5460
5665
  const setMode = async (mode) => {
5461
5666
  if (mode === (item.accessMode === "restricted" ? "restricted" : "all_members")) return;
5462
5667
  if (mode === "all_members" && people.length > 0) {
5463
- const ok = await confirm8({
5668
+ const ok = await confirm9({
5464
5669
  title: "Open to every member?",
5465
5670
  description: `Every member of ${orgName} gets it at their own vault access. The ${people.length === 1 ? "person" : `${people.length} people`} listed here lose their own access.`,
5466
5671
  confirmLabel: "Open to members",
@@ -5475,20 +5680,20 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5475
5680
  }
5476
5681
  };
5477
5682
  if (!item.capabilities.canManage) {
5478
- return /* @__PURE__ */ jsx25(Panel, { title: "Share", size: "md", onClose, footer: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }), children: /* @__PURE__ */ jsx25(VaultSection, { children: /* @__PURE__ */ jsx25(Empty, { children: "Only the owner can change who has access." }) }) });
5683
+ return /* @__PURE__ */ jsx26(Panel, { title: "Share", size: "md", onClose, footer: /* @__PURE__ */ jsx26(Button21, { variant: "primary", onClick: onClose, children: "Done" }), children: /* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(Empty, { children: "Only the owner can change who has access." }) }) });
5479
5684
  }
5480
- return /* @__PURE__ */ jsxs23(
5685
+ return /* @__PURE__ */ jsxs24(
5481
5686
  Panel,
5482
5687
  {
5483
5688
  title: "Share",
5484
5689
  size: "md",
5485
5690
  onClose,
5486
- footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
5691
+ footer: /* @__PURE__ */ jsx26(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx26(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx26(Button21, { variant: "primary", onClick: onClose, children: "Done" }) }),
5487
5692
  children: [
5488
- /* @__PURE__ */ jsxs23(VaultSection, { title: "Who has access", children: [
5489
- isOrg ? /* @__PURE__ */ jsx25(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ jsx25("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ jsx25(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ jsx25("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
5490
- isOrg ? /* @__PURE__ */ jsx25(AccessLine, { glyph: UsersIcon, who: `${orgName} members`, children: /* @__PURE__ */ jsx25(
5491
- Select8,
5693
+ /* @__PURE__ */ jsxs24(VaultSection, { title: "Who has access", children: [
5694
+ isOrg ? /* @__PURE__ */ jsx26(AccessLine, { glyph: BuildingGlyph, who: `${orgName} admins`, children: /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }) : /* @__PURE__ */ jsx26(AccessLine, { glyph: PersonGlyph, who: "You", meta: "Owner", children: /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: "Full access" }) }),
5695
+ isOrg ? /* @__PURE__ */ jsx26(AccessLine, { glyph: UsersIcon, who: `${orgName} members`, children: /* @__PURE__ */ jsx26(
5696
+ Select9,
5492
5697
  {
5493
5698
  variant: "inline",
5494
5699
  align: "end",
@@ -5502,14 +5707,14 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5502
5707
  ]
5503
5708
  }
5504
5709
  ) }) : null,
5505
- loadError ? /* @__PURE__ */ jsx25(AccessLine, { glyph: XGlyph, who: /* @__PURE__ */ jsx25("span", { className: "text-destructive", children: loadError }), children: /* @__PURE__ */ jsx25(Button20, { variant: "quiet", onClick: reload, children: "Retry" }) }) : grants === null ? /* @__PURE__ */ jsx25(RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading who has access", className: "px-3 sm:px-4" }) : grants.map((g) => /* @__PURE__ */ jsxs23(AccessLine, { glyph: g.kind === "organization" ? BuildingGlyph : PersonGlyph, who: g.label, ...g.kind === "organization" ? { meta: "Organization vault" } : {}, children: [
5506
- /* @__PURE__ */ jsx25(Select8, { variant: "inline", align: "end", "aria-label": `What ${g.label} can do`, disabled: busy !== null, value: g.level, onValueChange: (v) => void change(g, v), options: LEVEL_OPTIONS }),
5507
- /* @__PURE__ */ jsx25(Button20, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx25(XGlyph, {}), "aria-label": `Remove ${g.label}`, disabled: busy !== null, onClick: () => void revoke(g) })
5710
+ loadError ? /* @__PURE__ */ jsx26(AccessLine, { glyph: XGlyph, who: /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: loadError }), children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", onClick: reload, children: "Retry" }) }) : grants === null ? /* @__PURE__ */ jsx26(RegionSkeleton, { shape: "rows", count: 2, "aria-label": "Loading who has access", className: "px-3 sm:px-4" }) : grants.map((g) => /* @__PURE__ */ jsxs24(AccessLine, { glyph: g.kind === "organization" ? BuildingGlyph : PersonGlyph, who: g.label, ...g.kind === "organization" ? { meta: "Organization vault" } : {}, children: [
5711
+ /* @__PURE__ */ jsx26(Select9, { variant: "inline", align: "end", "aria-label": `What ${g.label} can do`, disabled: busy !== null, value: g.level, onValueChange: (v) => void change(g, v), options: LEVEL_OPTIONS }),
5712
+ /* @__PURE__ */ jsx26(Button21, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx26(XGlyph, {}), "aria-label": `Remove ${g.label}`, disabled: busy !== null, onClick: () => void revoke(g) })
5508
5713
  ] }, g.id)),
5509
- /* @__PURE__ */ jsxs23("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5510
- /* @__PURE__ */ jsx25(PersonGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
5511
- /* @__PURE__ */ jsx25(
5512
- Field9,
5714
+ /* @__PURE__ */ jsxs24("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5715
+ /* @__PURE__ */ jsx26(PersonGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
5716
+ /* @__PURE__ */ jsx26(
5717
+ Field10,
5513
5718
  {
5514
5719
  className: "min-w-0 flex-1",
5515
5720
  type: "email",
@@ -5529,13 +5734,13 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5529
5734
  }
5530
5735
  }
5531
5736
  ),
5532
- /* @__PURE__ */ jsx25(Select8, { variant: "inline", align: "end", "aria-label": "What they can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
5533
- /* @__PURE__ */ jsx25(Button20, { variant: "primary", disabled: busy !== null || !isEmail(email), onClick: () => void add(), children: "Share" })
5737
+ /* @__PURE__ */ jsx26(Select9, { variant: "inline", align: "end", "aria-label": "What they can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
5738
+ /* @__PURE__ */ jsx26(Button21, { variant: "primary", disabled: busy !== null || !isEmail(email), onClick: () => void add(), children: "Share" })
5534
5739
  ] })
5535
5740
  ] }),
5536
- /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-3", children: [
5537
- /* @__PURE__ */ jsx25(DisclosureHeader3, { open: more, title: "More options", onClick: () => setMore((o) => !o) }),
5538
- more ? isOrg && item.owner.organizationId ? /* @__PURE__ */ jsx25(MemberAccess, { port, organizationId: item.owner.organizationId, organizationName: orgName }) : /* @__PURE__ */ jsx25(IntoOrganization, { item, port, organizations, grants: grants ?? [], onShared: (g) => setGrants((all) => [...(all ?? []).filter((x) => x.id !== g.id), g]) }) : null
5741
+ /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-3", children: [
5742
+ /* @__PURE__ */ jsx26(DisclosureHeader3, { open: more, title: "More options", onClick: () => setMore((o) => !o) }),
5743
+ more ? isOrg && item.owner.organizationId ? /* @__PURE__ */ jsx26(MemberAccess, { port, organizationId: item.owner.organizationId, organizationName: orgName }) : /* @__PURE__ */ jsx26(IntoOrganization, { item, port, organizations, grants: grants ?? [], onShared: (g) => setGrants((all) => [...(all ?? []).filter((x) => x.id !== g.id), g]) }) : null
5539
5744
  ] })
5540
5745
  ]
5541
5746
  }
@@ -5544,17 +5749,17 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5544
5749
  function IntoOrganization({ item, port, organizations, grants, onShared }) {
5545
5750
  const { busy, error, notice, run } = useConfirmedChange();
5546
5751
  const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
5547
- const [target, setTarget] = useState25("");
5548
- const [level, setLevel] = useState25("use");
5752
+ const [target, setTarget] = useState26("");
5753
+ const [level, setLevel] = useState26("use");
5549
5754
  const chosen = open.find((o) => o.id === target);
5550
5755
  if (item.owner.kind !== "me") return null;
5551
- return /* @__PURE__ */ jsx25(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs23(Fragment15, { children: [
5552
- /* @__PURE__ */ jsxs23("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5553
- /* @__PURE__ */ jsx25(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
5554
- /* @__PURE__ */ jsx25(Select8, { className: "min-w-0 flex-1", "aria-label": "Organization", value: target || "__none__", onValueChange: (v) => setTarget(v === "__none__" ? "" : v), options: [{ value: "__none__", label: "Choose an organization" }, ...open.map((o) => ({ value: o.id, label: o.name }))] }),
5555
- /* @__PURE__ */ jsx25(Select8, { variant: "inline", align: "end", "aria-label": "What its members can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
5556
- /* @__PURE__ */ jsx25(
5557
- Button20,
5756
+ return /* @__PURE__ */ jsx26(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5757
+ /* @__PURE__ */ jsxs24("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5758
+ /* @__PURE__ */ jsx26(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
5759
+ /* @__PURE__ */ jsx26(Select9, { className: "min-w-0 flex-1", "aria-label": "Organization", value: target || "__none__", onValueChange: (v) => setTarget(v === "__none__" ? "" : v), options: [{ value: "__none__", label: "Choose an organization" }, ...open.map((o) => ({ value: o.id, label: o.name }))] }),
5760
+ /* @__PURE__ */ jsx26(Select9, { variant: "inline", align: "end", "aria-label": "What its members can do", value: level, onValueChange: setLevel, options: LEVEL_OPTIONS }),
5761
+ /* @__PURE__ */ jsx26(
5762
+ Button21,
5558
5763
  {
5559
5764
  variant: "outline",
5560
5765
  disabled: busy !== null || !chosen,
@@ -5570,8 +5775,8 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
5570
5775
  }
5571
5776
  )
5572
5777
  ] }),
5573
- /* @__PURE__ */ jsx25("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx25("span", { className: "text-destructive", children: error }) : notice ? /* @__PURE__ */ jsx25("span", { className: "text-success", children: notice }) : "It stays yours; its members can use it too" })
5574
- ] }) : /* @__PURE__ */ jsx25(Empty, { children: organizations.length ? "Already in every organization you belong to." : "You are not in any organization." }) });
5778
+ /* @__PURE__ */ jsx26("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: error }) : notice ? /* @__PURE__ */ jsx26("span", { className: "text-success", children: notice }) : "It stays yours; its members can use it too" })
5779
+ ] }) : /* @__PURE__ */ jsx26(Empty, { children: organizations.length ? "Already in every organization you belong to." : "You are not in any organization." }) });
5575
5780
  }
5576
5781
  var CHOICES = [
5577
5782
  { value: MEMBER_CHOICE_DEFAULT, label: "Default" },
@@ -5580,8 +5785,8 @@ var CHOICES = [
5580
5785
  { value: "editor", label: "Can edit", meta: "See and change" }
5581
5786
  ];
5582
5787
  function MemberAccess({ port, organizationId, organizationName }) {
5583
- const [list, setList] = useState25(null);
5584
- const [loadError, setLoadError] = useState25(null);
5788
+ const [list, setList] = useState26(null);
5789
+ const [loadError, setLoadError] = useState26(null);
5585
5790
  const { busy, error, run } = useConfirmedChange();
5586
5791
  useEffect15(() => {
5587
5792
  let live = true;
@@ -5598,9 +5803,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
5598
5803
  const effective = await run(userId, () => port.sharing.setMemberAccess(organizationId, userId, access));
5599
5804
  if (effective) setList((l) => l ? { ...l, members: l.members.map((m) => m.userId === userId ? { ...m, access, effective } : m) } : l);
5600
5805
  };
5601
- return /* @__PURE__ */ jsxs23(VaultSection, { title: `${organizationName} vault access`, children: [
5602
- loadError ? /* @__PURE__ */ jsx25(Empty, { children: loadError }) : list === null ? /* @__PURE__ */ jsx25(RegionSkeleton, { shape: "rows", count: 3, "aria-label": "Loading member access", className: "px-3 sm:px-4" }) : list.members.length === 0 ? /* @__PURE__ */ jsx25(Empty, { children: "No members yet." }) : list.members.map((m) => /* @__PURE__ */ jsx25(AccessLine, { glyph: PersonGlyph, who: m.email || m.userId, meta: m.role, children: m.effective === "admin" ? /* @__PURE__ */ jsx25("span", { className: "px-2 text-sm text-muted-foreground", children: MEMBER_ACCESS_LABEL.admin }) : /* @__PURE__ */ jsx25(
5603
- Select8,
5806
+ return /* @__PURE__ */ jsxs24(VaultSection, { title: `${organizationName} vault access`, children: [
5807
+ loadError ? /* @__PURE__ */ jsx26(Empty, { children: loadError }) : list === null ? /* @__PURE__ */ jsx26(RegionSkeleton, { shape: "rows", count: 3, "aria-label": "Loading member access", className: "px-3 sm:px-4" }) : list.members.length === 0 ? /* @__PURE__ */ jsx26(Empty, { children: "No members yet." }) : list.members.map((m) => /* @__PURE__ */ jsx26(AccessLine, { glyph: PersonGlyph, who: m.email || m.userId, meta: m.role, children: m.effective === "admin" ? /* @__PURE__ */ jsx26("span", { className: "px-2 text-sm text-muted-foreground", children: MEMBER_ACCESS_LABEL.admin }) : /* @__PURE__ */ jsx26(
5808
+ Select9,
5604
5809
  {
5605
5810
  variant: "inline",
5606
5811
  align: "end",
@@ -5611,11 +5816,11 @@ function MemberAccess({ port, organizationId, organizationName }) {
5611
5816
  options: CHOICES.map((c) => c.value === MEMBER_CHOICE_DEFAULT ? { value: c.value, label: `Default (${MEMBER_ACCESS_LABEL[list.defaultAccess]})` } : c.meta ? { value: c.value, label: c.label, meta: c.meta } : { value: c.value, label: c.label })
5612
5817
  }
5613
5818
  ) }, m.userId)),
5614
- /* @__PURE__ */ jsx25("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx25("span", { className: "text-destructive", children: error }) : "Applies to every item in this organization" })
5819
+ /* @__PURE__ */ jsx26("p", { className: "truncate px-3 pb-1 text-xs text-muted-foreground sm:px-4", children: error ? /* @__PURE__ */ jsx26("span", { className: "text-destructive", children: error }) : "Applies to every item in this organization" })
5615
5820
  ] });
5616
5821
  }
5617
5822
  function SharingSummary({ item, port, className }) {
5618
- const [text, setText] = useState25("");
5823
+ const [text, setText] = useState26("");
5619
5824
  const allowed = item.capabilities.canManage;
5620
5825
  useEffect15(() => {
5621
5826
  if (!allowed) return;
@@ -5629,12 +5834,12 @@ function SharingSummary({ item, port, className }) {
5629
5834
  };
5630
5835
  }, [port, item, allowed]);
5631
5836
  if (!allowed || !text) return null;
5632
- return /* @__PURE__ */ jsx25("span", { className: cn11("truncate text-xs text-muted-foreground", className), children: text });
5837
+ return /* @__PURE__ */ jsx26("span", { className: cn11("truncate text-xs text-muted-foreground", className), children: text });
5633
5838
  }
5634
5839
 
5635
5840
  // src/ItemPane.tsx
5636
5841
  import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
5637
- import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
5842
+ import { Fragment as Fragment17, jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
5638
5843
  var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
5639
5844
  function ItemPane(props) {
5640
5845
  const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
@@ -5643,7 +5848,7 @@ function ItemPane(props) {
5643
5848
  const editing = mode !== "view";
5644
5849
  const seedName = seed?.name ?? "";
5645
5850
  const seedUrl = seed?.url ?? "";
5646
- const [loaded, setLoaded] = useState26({});
5851
+ const [loaded, setLoaded] = useState27({});
5647
5852
  const base = useMemo3(() => {
5648
5853
  const b = draftOf(item);
5649
5854
  if (!item) {
@@ -5653,16 +5858,21 @@ function ItemPane(props) {
5653
5858
  b.values = { ...loaded };
5654
5859
  return b;
5655
5860
  }, [item, seedName, seedUrl, loaded]);
5656
- const [draft, setDraft] = useState26(base);
5657
- const [tagsText, setTagsText] = useState26(base.tags.join(", "));
5658
- const [showTags, setShowTags] = useState26(false);
5659
- const [showDescription, setShowDescription] = useState26(false);
5660
- const [owner, setOwner] = useState26(defaultOwner ?? "me");
5661
- const [recipient, setRecipient] = useState26("");
5662
- const [generatePrivately, setGeneratePrivately] = useState26(false);
5663
- const [busy, setBusy] = useState26(false);
5664
- const [error, setError] = useState26(null);
5665
- const [destinations, setDestinations] = useState26({});
5861
+ const [draft, setDraft] = useState27(base);
5862
+ const [tagsText, setTagsText] = useState27(base.tags.join(", "));
5863
+ const [showTags, setShowTags] = useState27(false);
5864
+ const [showDescription, setShowDescription] = useState27(false);
5865
+ const [showRecovery, setShowRecovery] = useState27(false);
5866
+ const [settingUpOtp, setSettingUpOtp] = useState27(false);
5867
+ const [owner, setOwner] = useState27(defaultOwner ?? "me");
5868
+ const [recipient, setRecipient] = useState27("");
5869
+ const [generatePrivately, setGeneratePrivately] = useState27(false);
5870
+ const [busy, setBusy] = useState27(false);
5871
+ const [sent, setSent] = useState27(null);
5872
+ const [queuedFiles, setQueuedFiles] = useState27([]);
5873
+ const [showBrowser, setShowBrowser] = useState27(false);
5874
+ const [error, setError] = useState27(null);
5875
+ const [destinations, setDestinations] = useState27({});
5666
5876
  const dirty = editing && isDirty(base, draft);
5667
5877
  const declared = definition?.fields ?? [];
5668
5878
  const prev = useRef14(null);
@@ -5685,6 +5895,7 @@ function ItemPane(props) {
5685
5895
  setLoaded({});
5686
5896
  setShowTags(false);
5687
5897
  setShowDescription(false);
5898
+ setShowRecovery(false);
5688
5899
  }, [item?.id, mode]);
5689
5900
  useEffect16(() => onDirty(dirty), [dirty, onDirty]);
5690
5901
  const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
@@ -5712,33 +5923,37 @@ function ItemPane(props) {
5712
5923
  setBusy(true);
5713
5924
  setError(null);
5714
5925
  const out = { ...draft, values: Object.fromEntries(changedValues(base, draft)) };
5926
+ if (out.values[RECOVERY_CODES_KEY] !== void 0) out.values[RECOVERY_CODES_KEY] = parseRecoveryCodes(out.values[RECOVERY_CODES_KEY]).join("\n");
5715
5927
  const withOtp = async (saved, notice2) => {
5716
5928
  const setup = out.authenticator.trim();
5717
- if (!setup) return [saved, notice2];
5929
+ if (!setup) return [saved, notice2, false];
5718
5930
  try {
5719
5931
  await confirmed(() => port.authenticator.enrol(saved, setup));
5720
- return [await port.get(saved), notice2];
5932
+ return [await port.get(saved), notice2, true];
5721
5933
  } catch (e) {
5722
5934
  const why = wasCancelled(e) ? "it was not confirmed" : e instanceof Error ? e.message : "it was refused";
5723
- return [saved, `Saved, but the one-time password was not set up: ${why}. Add it with Edit.`];
5935
+ return [saved, `Saved, but the authenticator was not set up: ${why}. Add it with Edit.`, false];
5724
5936
  }
5725
5937
  };
5726
5938
  try {
5727
5939
  if (item) {
5728
5940
  const r = await port.save(item, definition, out);
5729
- const [next, n] = await withOtp(r.item, r.notice);
5941
+ const [next, n, enrolled] = await withOtp(r.item, r.notice);
5730
5942
  dropKeptDraft(keepKey);
5731
- onSaved(next, false, n);
5943
+ onSaved(next, false, n, enrolled);
5732
5944
  } else if (definition && owner === "person") {
5733
5945
  const secretKey = declared.find((f) => f.storage === "encrypted" && f.kind === "secret")?.key ?? null;
5734
5946
  const r = await port.sharing.assign({ recipientEmail: recipient.trim(), definition, draft: out, generateFieldKey: generatePrivately ? secretKey : null });
5735
5947
  notify(`Sent to ${r.recipientEmail}`);
5736
- onCancelNew();
5948
+ dropKeptDraft(keepKey);
5949
+ onDirty(false);
5950
+ setSent(r);
5737
5951
  } else if (definition) {
5738
5952
  const r = await port.create(definition, owner === "me" ? null : owner, out);
5739
- const [next, n] = await withOtp(r.item, r.notice);
5953
+ const [withCode, n0, enrolled] = await withOtp(r.item, r.notice);
5954
+ const [next, n] = await storeQueuedFiles(withCode, n0);
5740
5955
  dropKeptDraft(keepKey);
5741
- onSaved(next, true, n);
5956
+ onSaved(next, true, n, enrolled);
5742
5957
  }
5743
5958
  } catch (e) {
5744
5959
  setError(e instanceof Error ? e.message : "Saving failed. Nothing was changed.");
@@ -5746,9 +5961,32 @@ function ItemPane(props) {
5746
5961
  setBusy(false);
5747
5962
  }
5748
5963
  }
5964
+ async function storeQueuedFiles(saved, notice2) {
5965
+ let next = saved;
5966
+ const failed = [];
5967
+ for (const q of queuedFiles) {
5968
+ try {
5969
+ next = await confirmed(() => port.activity.addFile(next, q.file, { label: q.label, description: q.description, handling: q.handling }));
5970
+ } catch {
5971
+ failed.push(q.label);
5972
+ }
5973
+ }
5974
+ setQueuedFiles([]);
5975
+ if (failed.length === 0) return [next, notice2];
5976
+ const said = `Saved, but ${failed.length === 1 ? `the file ${failed[0]} was` : `${failed.length} files were`} not stored. Add ${failed.length === 1 ? "it" : "them"} with Add file.`;
5977
+ return [next, notice2 ? `${notice2} ${said}` : said];
5978
+ }
5979
+ function createAnother() {
5980
+ setSent(null);
5981
+ setDraft(base);
5982
+ setTagsText(base.tags.join(", "));
5983
+ setQueuedFiles([]);
5984
+ setShowBrowser(false);
5985
+ setError(null);
5986
+ }
5749
5987
  async function remove() {
5750
5988
  if (!item) return;
5751
- const ok = await confirm9({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
5989
+ const ok = await confirm10({ title: `Delete \u201C${item.name}\u201D?`, description: "It moves to Trash. You can restore it from there.", confirmLabel: "Delete", variant: "destructive" });
5752
5990
  if (!ok) return;
5753
5991
  setBusy(true);
5754
5992
  try {
@@ -5789,6 +6027,7 @@ function ItemPane(props) {
5789
6027
  onChanged();
5790
6028
  }
5791
6029
  }
6030
+ const fieldSettings = (f) => canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SlidersGlyph, {}), "aria-label": `${f.label} settings`, title: `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) }) : null;
5792
6031
  const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
5793
6032
  const declaredKeys = new Set(declared.map((f) => f.key));
5794
6033
  const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
@@ -5797,35 +6036,39 @@ function ItemPane(props) {
5797
6036
  const viewCustom = (item?.custom ?? []).filter((c) => !declaredKeys.has(c.key) && c.key !== MFA_METHOD_KEY && !isAuthenticatorStorage(c.key));
5798
6037
  const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
5799
6038
  const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
5800
- const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ jsx26(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ jsx26(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ jsx26(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ jsx26(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ jsx26(BuildingGlyph, {}) : /* @__PURE__ */ jsx26(UsersIcon2, {}) } : null;
6039
+ const recoveryDeclared = declaredKeys.has(RECOVERY_CODES_KEY);
6040
+ const recoveryExtra = extraFields.some(isRecoveryCodesField);
6041
+ const offerRecovery = isLogin || Boolean(item?.authenticator) || draft.authenticator.trim() !== "";
6042
+ const recoveryEditing = !recoveryDeclared && !recoveryExtra && (showRecovery || (draft.values[RECOVERY_CODES_KEY] ?? "") !== "");
6043
+ const shownOwner = mode === "new" ? owner === "me" ? { label: "Personal", glyph: /* @__PURE__ */ jsx27(PersonGlyph, {}) } : owner === "person" ? { label: "Someone else", glyph: /* @__PURE__ */ jsx27(SendGlyph, {}) } : { label: organizations.find((o) => o.id === owner)?.name ?? "Organization", glyph: /* @__PURE__ */ jsx27(BuildingGlyph, {}) } : item ? { label: item.owner.label, glyph: item.owner.kind === "me" ? /* @__PURE__ */ jsx27(PersonGlyph, {}) : item.owner.kind === "organization" ? /* @__PURE__ */ jsx27(BuildingGlyph, {}) : /* @__PURE__ */ jsx27(UsersIcon2, {}) } : null;
5801
6044
  const sameNamed = (id) => {
5802
6045
  const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
5803
6046
  return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
5804
6047
  };
5805
6048
  const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
5806
6049
  const descriptionVisible = showDescription || draft.description !== "";
5807
- const header = /* @__PURE__ */ jsxs24("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-5", children: [
5808
- onBack ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
5809
- /* @__PURE__ */ jsx26(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
5810
- /* @__PURE__ */ jsxs24("div", { className: "flex min-w-0 flex-1 flex-col", children: [
5811
- /* @__PURE__ */ jsx26("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
5812
- /* @__PURE__ */ jsxs24("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
5813
- typeLabel ? /* @__PURE__ */ jsx26("span", { className: "truncate", children: typeLabel }) : null,
5814
- shownOwner ? /* @__PURE__ */ jsx26(Badge7, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
5815
- item && !editing ? /* @__PURE__ */ jsx26(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
6050
+ const header = /* @__PURE__ */ jsxs25("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-5", children: [
6051
+ onBack ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(ChevronLeftGlyph, {}), "aria-label": "Back", onClick: mode === "new" ? onCancelNew : onBack }) : null,
6052
+ /* @__PURE__ */ jsx27(ItemIcon, { definitionKey: definition?.key ?? item?.definitionKey ?? "custom", family: definition?.family ?? "generic", site: item ? loginSiteOf(item) : loginSiteOf({ loginUrls: draft.loginUrls }), size: "lg" }),
6053
+ /* @__PURE__ */ jsxs25("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6054
+ /* @__PURE__ */ jsx27("h2", { className: "truncate text-base font-semibold leading-tight", children: editing ? draft.name || (mode === "new" ? `New ${typeLabel.toLowerCase()}` : item?.name) : item?.name }),
6055
+ /* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", children: [
6056
+ typeLabel ? /* @__PURE__ */ jsx27("span", { className: "truncate", children: typeLabel }) : null,
6057
+ shownOwner ? /* @__PURE__ */ jsx27(Badge7, { className: "shrink-0", icon: shownOwner.glyph, "aria-label": `Saved in ${shownOwner.label}`, children: shownOwner.label }) : null,
6058
+ item && !editing ? /* @__PURE__ */ jsx27(SharingSummary, { item, port, className: "hidden truncate before:mr-1 before:content-['\xB7'] sm:inline" }, `${item.updatedAt}-${refreshKey ?? ""}`) : null
5816
6059
  ] })
5817
6060
  ] }),
5818
- editing ? /* @__PURE__ */ jsxs24("div", { className: "flex shrink-0 items-center gap-2", children: [
5819
- dirty ? /* @__PURE__ */ jsxs24("span", { className: "hidden items-center gap-1.5 text-xs text-muted-foreground sm:flex", role: "status", children: [
5820
- /* @__PURE__ */ jsx26("span", { className: "size-1.5 rounded-full bg-warning", "aria-hidden": true }),
6061
+ editing ? /* @__PURE__ */ jsxs25("div", { className: "flex shrink-0 items-center gap-2", children: [
6062
+ dirty ? /* @__PURE__ */ jsxs25("span", { className: "hidden items-center gap-1.5 text-xs text-muted-foreground sm:flex", role: "status", children: [
6063
+ /* @__PURE__ */ jsx27("span", { className: "size-1.5 rounded-full bg-warning", "aria-hidden": true }),
5821
6064
  "Unsaved"
5822
6065
  ] }) : null,
5823
- /* @__PURE__ */ jsx26(Button21, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
5824
- /* @__PURE__ */ jsx26(Button21, { variant: "primary", disabled: busy || draft.name.trim() === "" || mode === "edit" && !dirty || mode === "new" && owner === "person" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(recipient.trim()), onClick: () => void save(), children: mode === "new" && owner === "person" ? "Send" : "Save" })
5825
- ] }) : item ? /* @__PURE__ */ jsxs24("div", { className: "flex shrink-0 items-center gap-1", children: [
5826
- host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ jsx26(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
5827
- host.fill && item.capabilities.canUse ? /* @__PURE__ */ jsx26(
5828
- Button21,
6066
+ /* @__PURE__ */ jsx27(Button22, { variant: "quiet", disabled: busy, onClick: () => mode === "new" ? onCancelNew() : onMode("view"), children: dirty ? "Discard" : "Cancel" }),
6067
+ /* @__PURE__ */ jsx27(Button22, { variant: "primary", disabled: busy || sent !== null || draft.name.trim() === "" || mode === "edit" && !dirty || mode === "new" && owner === "person" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(recipient.trim()), onClick: () => void save(), children: mode === "new" && owner === "person" ? "Send" : "Save" })
6068
+ ] }) : item ? /* @__PURE__ */ jsxs25("div", { className: "flex shrink-0 items-center gap-1", children: [
6069
+ host.page && canUseOnSite(item, host.page.url) ? /* @__PURE__ */ jsx27(UseOnSiteButton, { port, item, pageUrl: host.page.url, onChanged: (next) => onChanged(next) }) : null,
6070
+ host.fill && item.capabilities.canUse ? /* @__PURE__ */ jsx27(
6071
+ Button22,
5829
6072
  {
5830
6073
  variant: "primary",
5831
6074
  onClick: () => void host.fill?.(item.id).then((outcome) => {
@@ -5835,44 +6078,44 @@ function ItemPane(props) {
5835
6078
  children: "Fill"
5836
6079
  }
5837
6080
  ) : null,
5838
- favorite ? /* @__PURE__ */ jsx26("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "size-4" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", pressed: favorite.on, onClick: favorite.toggle }) }) : null,
5839
- canManage ? /* @__PURE__ */ jsx26("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(ShareGlyph, {}), "aria-label": "Share", onClick: () => onPanel("share") }) }) : null,
5840
- canEdit ? /* @__PURE__ */ jsx26(Button21, { variant: "outline", icon: /* @__PURE__ */ jsx26(PencilGlyph, {}), collapse: "container", "aria-label": "Edit", onClick: () => onMode("edit"), children: "Edit" }) : null,
5841
- /* @__PURE__ */ jsxs24(DropdownMenu3, { children: [
5842
- /* @__PURE__ */ jsx26(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(MoreGlyph, {}), "aria-label": "More actions" }) }),
5843
- /* @__PURE__ */ jsxs24(DropdownMenuContent3, { align: "end", children: [
5844
- favorite ? /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: favorite.toggle, children: [
5845
- /* @__PURE__ */ jsx26(StarGlyph, { className: "size-4" }),
6081
+ favorite ? /* @__PURE__ */ jsx27("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "size-4" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", pressed: favorite.on, onClick: favorite.toggle }) }) : null,
6082
+ canManage ? /* @__PURE__ */ jsx27("span", { className: "hidden sm:contents", children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(ShareGlyph, {}), "aria-label": "Share", onClick: () => onPanel("share") }) }) : null,
6083
+ canEdit ? /* @__PURE__ */ jsx27(Button22, { variant: "outline", icon: /* @__PURE__ */ jsx27(PencilGlyph, {}), collapse: "container", "aria-label": "Edit", onClick: () => onMode("edit"), children: "Edit" }) : null,
6084
+ /* @__PURE__ */ jsxs25(DropdownMenu3, { children: [
6085
+ /* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(MoreGlyph, {}), "aria-label": "More actions" }) }),
6086
+ /* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
6087
+ favorite ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: favorite.toggle, children: [
6088
+ /* @__PURE__ */ jsx27(StarGlyph, { className: "size-4" }),
5846
6089
  favorite.on ? "Remove from favorites" : "Add to favorites"
5847
6090
  ] }) : null,
5848
- canManage ? /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("share"), children: [
5849
- /* @__PURE__ */ jsx26(ShareGlyph, { className: "size-4" }),
6091
+ canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("share"), children: [
6092
+ /* @__PURE__ */ jsx27(ShareGlyph, { className: "size-4" }),
5850
6093
  "Share"
5851
6094
  ] }) : null,
5852
- canManage ? /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
5853
- /* @__PURE__ */ jsx26(MoveGlyph, { className: "size-4" }),
6095
+ canManage ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("move"), children: [
6096
+ /* @__PURE__ */ jsx27(MoveGlyph, { className: "size-4" }),
5854
6097
  "Move or copy"
5855
6098
  ] }) : null,
5856
- item.capabilities.canReveal ? /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("send"), children: [
5857
- /* @__PURE__ */ jsx26(SendGlyph, { className: "size-4" }),
6099
+ item.capabilities.canReveal ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("send"), children: [
6100
+ /* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }),
5858
6101
  "Send securely"
5859
6102
  ] }) : null,
5860
- /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("history"), children: [
5861
- /* @__PURE__ */ jsx26(HistoryIcon, { className: "size-4" }),
6103
+ /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("history"), children: [
6104
+ /* @__PURE__ */ jsx27(HistoryIcon, { className: "size-4" }),
5862
6105
  "Password history"
5863
6106
  ] }),
5864
- /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("activity"), children: [
5865
- /* @__PURE__ */ jsx26(ListGlyph, { className: "size-4" }),
6107
+ /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("activity"), children: [
6108
+ /* @__PURE__ */ jsx27(ListGlyph, { className: "size-4" }),
5866
6109
  "Activity"
5867
6110
  ] }),
5868
- canEdit ? /* @__PURE__ */ jsxs24(DropdownMenuItem3, { onSelect: () => onPanel("settings"), children: [
5869
- /* @__PURE__ */ jsx26(SettingsIcon, { className: "size-4" }),
6111
+ canEdit ? /* @__PURE__ */ jsxs25(DropdownMenuItem3, { onSelect: () => onPanel("settings"), children: [
6112
+ /* @__PURE__ */ jsx27(SettingsIcon, { className: "size-4" }),
5870
6113
  "Settings"
5871
6114
  ] }) : null,
5872
- canManage ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5873
- /* @__PURE__ */ jsx26(DropdownMenuSeparator3, {}),
5874
- /* @__PURE__ */ jsxs24(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
5875
- /* @__PURE__ */ jsx26(TrashGlyph, { className: "size-4" }),
6115
+ canManage ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6116
+ /* @__PURE__ */ jsx27(DropdownMenuSeparator3, {}),
6117
+ /* @__PURE__ */ jsxs25(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
6118
+ /* @__PURE__ */ jsx27(TrashGlyph, { className: "size-4" }),
5876
6119
  "Delete"
5877
6120
  ] })
5878
6121
  ] }) : null
@@ -5881,17 +6124,17 @@ function ItemPane(props) {
5881
6124
  ] }) : null
5882
6125
  ] });
5883
6126
  const filesProps = item ? { item, port, host, definition, organizations, arg: null, onClose: () => void 0, onChanged, onPanel } : null;
5884
- return /* @__PURE__ */ jsx26(RoomProvider, { value: room, children: /* @__PURE__ */ jsxs24("article", { ref: paneRef, "aria-label": item?.name ?? "New item", className: cn12(CONTROLS_CONTAINER_CLASS, "flex h-full min-h-0 flex-col bg-background"), children: [
6127
+ return /* @__PURE__ */ jsx27(RoomProvider, { value: room, children: /* @__PURE__ */ jsxs25("article", { ref: paneRef, "aria-label": item?.name ?? "New item", className: cn12(CONTROLS_CONTAINER_CLASS, "flex h-full min-h-0 flex-col bg-background"), children: [
5885
6128
  header,
5886
- error ? /* @__PURE__ */ jsx26("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
5887
- notice && !editing ? /* @__PURE__ */ jsx26("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
5888
- item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ jsxs24("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
5889
- /* @__PURE__ */ jsx26("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
5890
- canTurnOn ? /* @__PURE__ */ jsx26(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
6129
+ error ? /* @__PURE__ */ jsx27("div", { role: "alert", className: "border-b border-border bg-muted px-5 py-2 text-sm text-destructive", children: error }) : null,
6130
+ notice && !editing ? /* @__PURE__ */ jsx27("div", { role: "status", className: "border-b border-border bg-muted px-5 py-2 text-sm text-warning", children: notice }) : null,
6131
+ item && !editing && (itemOff || offFields.length > 0) ? /* @__PURE__ */ jsxs25("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-5 py-2 text-sm", children: [
6132
+ /* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 truncate text-warning", children: offFields.length === 0 ? "This item is turned off" : offFields.length === 1 ? "1 field is turned off" : `${offFields.length} fields are turned off` }),
6133
+ canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "all fields", onTurnOn: () => turnOn(offFields) }) : null
5891
6134
  ] }) : null,
5892
- /* @__PURE__ */ jsx26("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx26("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5893
- /* @__PURE__ */ jsxs24(VaultSection, { children: [
5894
- mode === "new" ? /* @__PURE__ */ jsx26(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx26(
6135
+ /* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto", children: sent ? /* @__PURE__ */ jsx27(AssignResult, { sent, onAnother: createAnother, onDone: onCancelNew }) : /* @__PURE__ */ jsx27("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-4 sm:px-6 sm:py-6", children: editing ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6136
+ /* @__PURE__ */ jsxs25(VaultSection, { children: [
6137
+ mode === "new" ? /* @__PURE__ */ jsx27(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx27(
5895
6138
  OptionCombobox,
5896
6139
  {
5897
6140
  value: owner,
@@ -5906,20 +6149,20 @@ function ItemPane(props) {
5906
6149
  ],
5907
6150
  getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
5908
6151
  getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
5909
- renderIcon: (v) => v === "me" ? /* @__PURE__ */ jsx26(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ jsx26(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ jsx26(BuildingGlyph, { className: "size-4" })
6152
+ renderIcon: (v) => v === "me" ? /* @__PURE__ */ jsx27(PersonGlyph, { className: "size-4" }) : v === "person" ? /* @__PURE__ */ jsx27(SendGlyph, { className: "size-4" }) : /* @__PURE__ */ jsx27(BuildingGlyph, { className: "size-4" })
5910
6153
  }
5911
6154
  ) }) : null,
5912
- /* @__PURE__ */ jsx26(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
5913
- mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5914
- /* @__PURE__ */ jsx26(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
5915
- declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx26(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx26(Switch5, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
6155
+ /* @__PURE__ */ jsx27(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
6156
+ mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6157
+ /* @__PURE__ */ jsx27(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
6158
+ declared.some((f) => f.storage === "encrypted" && f.kind === "secret") ? /* @__PURE__ */ jsx27(VaultRow, { label: "Password", hint: "You never see it", children: /* @__PURE__ */ jsx27(Switch6, { checked: generatePrivately, onCheckedChange: setGeneratePrivately, "aria-label": "Generate the password privately" }) }) : null
5916
6159
  ] }) : null,
5917
6160
  declared.map((f) => {
5918
6161
  const existing = item?.fields.find((x) => x.key === f.key);
5919
6162
  const secretKind = f.storage === "encrypted" && f.kind === "secret";
5920
6163
  const value = f.storage === "metadata" ? metaValue(f.key) : draft.values[f.key] ?? "";
5921
6164
  const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
5922
- return /* @__PURE__ */ jsx26(
6165
+ return /* @__PURE__ */ jsx27(
5923
6166
  EditRow,
5924
6167
  {
5925
6168
  label: f.label,
@@ -5929,37 +6172,38 @@ function ItemPane(props) {
5929
6172
  multiline: f.kind === "multiline",
5930
6173
  inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
5931
6174
  onChange: (v) => setValue(f.key, v),
5932
- actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
5933
- hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
5934
- secretKind ? /* @__PURE__ */ jsx26(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
5935
- existing ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
6175
+ actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
6176
+ hidden && existing?.handling === "revealable" && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
6177
+ secretKind ? /* @__PURE__ */ jsx27(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
6178
+ existing ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
5936
6179
  ] })
5937
6180
  },
5938
6181
  f.key
5939
6182
  );
5940
6183
  }),
5941
- extraFields.map((f) => /* @__PURE__ */ jsx26(
6184
+ extraFields.map((f) => /* @__PURE__ */ jsx27(
5942
6185
  EditRow,
5943
6186
  {
5944
6187
  label: f.label,
5945
6188
  value: draft.values[f.key] ?? "",
5946
6189
  placeholder: f.handling === "visible" || f.key in loaded ? "" : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
5947
- secret: f.handling !== "visible",
6190
+ secret: f.handling !== "visible" && !isRecoveryCodesField(f),
6191
+ multiline: isRecoveryCodesField(f),
5948
6192
  onChange: (v) => setValue(f.key, v),
5949
6193
  onRemove: () => patch({ removed: [...draft.removed, f.id] }),
5950
6194
  removeLabel: `Delete ${f.label}`,
5951
- actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
5952
- f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
5953
- /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
6195
+ actions: /* @__PURE__ */ jsxs25(Fragment17, { children: [
6196
+ f.handling === "revealable" && !(f.key in loaded) && item?.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(EyeGlyph, {}), "aria-label": `Show current ${f.label}`, onClick: () => void loadForEdit(f.key) }) : null,
6197
+ /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
5954
6198
  ] })
5955
6199
  },
5956
6200
  f.id
5957
6201
  )),
5958
- draft.loginUrls.map((u, i) => /* @__PURE__ */ jsx26(
6202
+ draft.loginUrls.map((u, i) => /* @__PURE__ */ jsx27(
5959
6203
  EditRow,
5960
6204
  {
5961
6205
  label: i === 0 ? "Website" : `Website ${i + 1}`,
5962
- hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */ jsx26("span", { className: destinations[i].tone === "destructive" ? "text-destructive" : "text-warning", children: destinations[i].message }) : void 0,
6206
+ hint: destinations[i] && destinations[i].tone !== "success" ? /* @__PURE__ */ jsx27("span", { className: destinations[i].tone === "destructive" ? "text-destructive" : "text-warning", children: destinations[i].message }) : void 0,
5963
6207
  value: u,
5964
6208
  autoFocus: i > 0 && u === "" && i === draft.loginUrls.length - 1,
5965
6209
  placeholder: "https://",
@@ -5979,27 +6223,53 @@ function ItemPane(props) {
5979
6223
  },
5980
6224
  i
5981
6225
  )),
5982
- /* @__PURE__ */ jsx26(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
5983
- /* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
5984
- item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
6226
+ /* @__PURE__ */ jsx27(AddRow, { label: draft.loginUrls.length === 0 ? "Website" : "", onAdd: () => patch({ loginUrls: [...draft.loginUrls, ""] }), children: draft.loginUrls.length === 0 ? "Add website" : "Add another website" }),
6227
+ /* @__PURE__ */ jsx27(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
6228
+ item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx27(TwoFactorMethodRow, { port, item, onChanged }) : null,
6229
+ !item && isLogin && draft.authenticator.trim() === "" ? /* @__PURE__ */ jsx27(DraftTwoFactorRow, { custom: draft.custom, onCustom: (custom) => patch({ custom }) }) : null,
6230
+ recoveryEditing ? /* @__PURE__ */ jsx27(
6231
+ EditRow,
6232
+ {
6233
+ label: "Recovery codes",
6234
+ value: draft.values[RECOVERY_CODES_KEY] ?? "",
6235
+ multiline: true,
6236
+ autoFocus: showRecovery && (draft.values[RECOVERY_CODES_KEY] ?? "") === "",
6237
+ placeholder: "Backup codes, one per line",
6238
+ onChange: (v) => setValue(RECOVERY_CODES_KEY, v),
6239
+ onRemove: () => {
6240
+ setShowRecovery(false);
6241
+ setDraft((d) => {
6242
+ const values = { ...d.values };
6243
+ delete values[RECOVERY_CODES_KEY];
6244
+ return { ...d, values };
6245
+ });
6246
+ },
6247
+ removeLabel: "Remove recovery codes"
6248
+ }
6249
+ ) : !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ jsx27(AddRow, { label: "Recovery codes", onAdd: () => setShowRecovery(true), children: "Add backup codes" }) : null
5985
6250
  ] }),
5986
- /* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
5987
- /* @__PURE__ */ jsxs24(
6251
+ /* @__PURE__ */ jsx27(VaultSection, { children: /* @__PURE__ */ jsx27(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
6252
+ /* @__PURE__ */ jsxs25(
5988
6253
  VaultSection,
5989
6254
  {
5990
6255
  title: "More",
5991
- actions: /* @__PURE__ */ jsxs24(DropdownMenu3, { children: [
5992
- /* @__PURE__ */ jsx26(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(PlusGlyph, {}), children: "Add" }) }),
5993
- /* @__PURE__ */ jsxs24(DropdownMenuContent3, { align: "end", children: [
5994
- /* @__PURE__ */ jsx26(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
5995
- /* @__PURE__ */ jsx26(DropdownMenuItem3, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
5996
- !tagsVisible ? /* @__PURE__ */ jsx26(DropdownMenuItem3, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
5997
- !descriptionVisible ? /* @__PURE__ */ jsx26(DropdownMenuItem3, { onSelect: () => setShowDescription(true), children: "Description" }) : null
6256
+ actions: /* @__PURE__ */ jsxs25(DropdownMenu3, { children: [
6257
+ /* @__PURE__ */ jsx27(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), children: "Add" }) }),
6258
+ /* @__PURE__ */ jsxs25(DropdownMenuContent3, { align: "end", children: [
6259
+ /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ secrets: [...draft.secrets, { key: "", label: "", value: "" }] }), children: "Secret field" }),
6260
+ /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => patch({ custom: [...draft.custom, { key: `custom_${draft.custom.length + 1}_${Date.now() % 1e5}`, label: "", value: "" }] }), children: "Text field" }),
6261
+ !tagsVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowTags(true), children: "Tags" }) : null,
6262
+ !descriptionVisible ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowDescription(true), children: "Description" }) : null,
6263
+ mode === "new" && !showBrowser ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => {
6264
+ setShowBrowser(true);
6265
+ if (!draft.browser) patch({ browser: defaultBrowserSettings(draft.loginUrls.some((u) => u.trim() !== "")) });
6266
+ }, children: "Browser settings" }) : null,
6267
+ !recoveryDeclared && !recoveryExtra && !recoveryEditing ? /* @__PURE__ */ jsx27(DropdownMenuItem3, { onSelect: () => setShowRecovery(true), children: "Recovery codes" }) : null
5998
6268
  ] })
5999
6269
  ] }),
6000
6270
  children: [
6001
- descriptionVisible ? /* @__PURE__ */ jsx26(EditRow, { label: "Description", value: draft.description, placeholder: "What this is for", onChange: (v) => patch({ description: v }) }) : null,
6002
- tagsVisible ? /* @__PURE__ */ jsx26(
6271
+ descriptionVisible ? /* @__PURE__ */ jsx27(EditRow, { label: "Description", value: draft.description, placeholder: "What this is for", onChange: (v) => patch({ description: v }) }) : null,
6272
+ tagsVisible ? /* @__PURE__ */ jsx27(
6003
6273
  EditRow,
6004
6274
  {
6005
6275
  label: "Tags",
@@ -6011,63 +6281,83 @@ function ItemPane(props) {
6011
6281
  }
6012
6282
  }
6013
6283
  ) : null,
6014
- draft.secrets.map((s, i) => /* @__PURE__ */ jsx26(CustomEditRow, { label: s.label, value: s.value, secret: true, onLabel: (v) => patch({ secrets: draft.secrets.map((x, j) => j === i ? { ...x, label: v } : x) }), onValue: (v) => patch({ secrets: draft.secrets.map((x, j) => j === i ? { ...x, value: v } : x) }), onRemove: () => patch({ secrets: draft.secrets.filter((_, j) => j !== i) }) }, `s${i}`)),
6015
- extraCustom.map((c) => /* @__PURE__ */ jsx26(CustomEditRow, { label: c.label, value: c.value, secret: false, onLabel: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, label: v } : x) }), onValue: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, value: v } : x) }), onRemove: () => patch({ custom: draft.custom.filter((x) => x.key !== c.key) }) }, c.key)),
6016
- !descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
6284
+ mode === "new" && showBrowser && draft.browser ? /* @__PURE__ */ jsx27(DraftBrowserRows, { value: draft.browser, hasWebsite: draft.loginUrls.some((u) => u.trim() !== ""), onChange: (browser) => patch({ browser }) }) : null,
6285
+ draft.secrets.map((s, i) => /* @__PURE__ */ jsx27(SecretBuilderRow, { field: s, onChange: (p) => setDraft((d) => ({ ...d, secrets: d.secrets.map((x, j) => j === i ? { ...x, ...p } : x) })), onRemove: () => patch({ secrets: draft.secrets.filter((_, j) => j !== i) }) }, `s${i}`)),
6286
+ extraCustom.map((c) => /* @__PURE__ */ jsx27(CustomEditRow, { label: c.label, value: c.value, secret: false, onLabel: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, label: v } : x) }), onValue: (v) => patch({ custom: draft.custom.map((x) => x.key === c.key ? { ...x, value: v } : x) }), onRemove: () => patch({ custom: draft.custom.filter((x) => x.key !== c.key) }) }, c.key)),
6287
+ !descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx27(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
6017
6288
  ]
6018
6289
  }
6019
6290
  ),
6020
- filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: true }) : null
6021
- ] }) : item ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
6022
- /* @__PURE__ */ jsxs24(VaultSection, { children: [
6291
+ filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: true }) : mode === "new" && owner !== "person" ? /* @__PURE__ */ jsx27(DraftFilesSection, { files: queuedFiles, onFiles: setQueuedFiles }) : null
6292
+ ] }) : item ? /* @__PURE__ */ jsxs25(Fragment17, { children: [
6293
+ /* @__PURE__ */ jsxs25(VaultSection, { children: [
6023
6294
  declared.map((f) => {
6024
6295
  if (f.storage === "metadata") {
6025
6296
  const v = metaValue(f.key);
6026
- return v ? /* @__PURE__ */ jsx26(PlainRow, { label: f.label, value: v, openUrl: host.openUrl }, f.key) : null;
6297
+ return v ? /* @__PURE__ */ jsx27(PlainRow, { label: f.label, value: v, openUrl: host.openUrl }, f.key) : null;
6027
6298
  }
6028
6299
  const field = item.fields.find((x) => x.key === f.key);
6029
- if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
6030
- return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field, onTurnOn: turnOnOne(field) }, field.id) : null;
6300
+ if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
6301
+ return field ? /* @__PURE__ */ jsx27(SecretRow, { port, item, field, onTurnOn: turnOnOne(field), extra: fieldSettings(field) }, field.id) : null;
6031
6302
  }),
6032
- extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx26(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f) }, f.id)),
6033
- item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ jsx26(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ jsx26(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
6034
- item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
6303
+ extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx27(SecretRow, { port, item, field: f, onTurnOn: turnOnOne(f), extra: fieldSettings(f) }, f.id)),
6304
+ item.loginUrls.length > 0 ? item.loginUrls.map((u, i) => /* @__PURE__ */ jsx27(PlainRow, { label: i === 0 ? "Website" : `Website ${i + 1}`, value: u, openUrl: host.openUrl }, `${u}-${i}`)) : /* @__PURE__ */ jsx27(AddRow, { label: "Website", onAdd: canEdit ? () => onMode("edit") : null, children: "Add website" }),
6305
+ item.authenticator ? /* @__PURE__ */ jsx27(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
6035
6306
  // The secret is still there, only off: turning it on brings the codes back. Never "Set up",
6036
6307
  // which would invite replacing a working two-factor secret.
6037
- /* @__PURE__ */ jsx26(VaultRow, { label: "One-time password", actions: canTurnOn ? /* @__PURE__ */ jsx26(TurnOnButton, { label: "One-time password", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ jsx26("span", { className: "text-muted-foreground", children: "Turned off" }) })
6038
- ) : /* @__PURE__ */ jsx26(AddRow, { label: "One-time password", onAdd: canEdit ? () => onMode("edit") : null, children: "Set up" }),
6039
- !item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
6308
+ /* @__PURE__ */ jsx27(VaultRow, { label: "Authenticator", actions: canTurnOn ? /* @__PURE__ */ jsx27(TurnOnButton, { label: "Authenticator", onTurnOn: () => turnOn([seedField]) }) : null, children: /* @__PURE__ */ jsx27("span", { className: "text-muted-foreground", children: "Turned off" }) })
6309
+ ) : /* @__PURE__ */ jsx27(AddRow, { label: "Authenticator", onAdd: canEdit ? () => setSettingUpOtp(true) : null, children: "Set up" }),
6310
+ !recoveryDeclared && !recoveryExtra && offerRecovery ? /* @__PURE__ */ jsx27(RecoveryCodesRow, { item, field: null, port, onChanged }) : null,
6311
+ !item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx27(TwoFactorMethodRow, { port, item, onChanged }) : null
6040
6312
  ] }),
6041
- /* @__PURE__ */ jsx26(VaultSection, { children: item.notes ? /* @__PURE__ */ jsx26(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ jsx26(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
6042
- item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */ jsxs24(VaultSection, { title: "More", children: [
6043
- item.description ? /* @__PURE__ */ jsx26(PlainRow, { label: "Description", value: item.description }) : null,
6044
- item.tags.length > 0 ? /* @__PURE__ */ jsx26(VaultRow, { label: "Tags", children: /* @__PURE__ */ jsx26("div", { className: "flex flex-wrap gap-1", children: item.tags.map((t) => /* @__PURE__ */ jsx26("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-xs", children: t }, t)) }) }) : null,
6045
- viewCustom.map((c) => /* @__PURE__ */ jsx26(PlainRow, { label: c.label, value: c.value, openUrl: host.openUrl }, c.key))
6313
+ /* @__PURE__ */ jsx27(VaultSection, { children: item.notes ? /* @__PURE__ */ jsx27(PlainRow, { label: "Notes", value: item.notes, multiline: true }) : /* @__PURE__ */ jsx27(AddRow, { label: "Notes", onAdd: canEdit ? () => onMode("edit") : null, children: "Add notes" }) }),
6314
+ item.description || item.tags.length > 0 || viewCustom.length > 0 ? /* @__PURE__ */ jsxs25(VaultSection, { title: "More", children: [
6315
+ item.description ? /* @__PURE__ */ jsx27(PlainRow, { label: "Description", value: item.description }) : null,
6316
+ item.tags.length > 0 ? /* @__PURE__ */ jsx27(VaultRow, { label: "Tags", children: /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap gap-1", children: item.tags.map((t) => /* @__PURE__ */ jsx27("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-xs", children: t }, t)) }) }) : null,
6317
+ viewCustom.map((c) => /* @__PURE__ */ jsx27(PlainRow, { label: c.label, value: c.value, openUrl: host.openUrl }, c.key))
6046
6318
  ] }) : null,
6047
- filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: false }) : null,
6048
- /* @__PURE__ */ jsxs24("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
6319
+ filesProps ? /* @__PURE__ */ jsx27(FilesSection, { ...filesProps, editing: false }) : null,
6320
+ /* @__PURE__ */ jsxs25("p", { className: cn12("px-1 text-xs text-muted-foreground"), children: [
6049
6321
  "Modified ",
6050
6322
  formatAbsoluteDate3(item.updatedAt, DAY_FORMAT, ""),
6051
6323
  " \xB7 Created ",
6052
6324
  formatAbsoluteDate3(item.createdAt, DAY_FORMAT, "")
6053
6325
  ] })
6054
- ] }) : null }) })
6326
+ ] }) : null }) }),
6327
+ settingUpOtp && item ? /* @__PURE__ */ jsx27(
6328
+ AddOtpPanel,
6329
+ {
6330
+ port,
6331
+ items: [item],
6332
+ definitions: definition ? [definition] : [],
6333
+ itemId: item.id,
6334
+ onClose: () => setSettingUpOtp(false),
6335
+ onChanged: () => onChanged(),
6336
+ onDone: () => {
6337
+ setSettingUpOtp(false);
6338
+ onChanged();
6339
+ }
6340
+ }
6341
+ ) : null
6055
6342
  ] }) });
6056
6343
  }
6057
6344
 
6058
6345
  // src/ItemList.tsx
6059
- import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
6346
+ import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
6060
6347
  var SORTS2 = [
6061
- { value: "name", label: "Name" },
6348
+ { value: "name", label: "Name A\u2013Z" },
6349
+ { value: "name-desc", label: "Name Z\u2013A" },
6062
6350
  { value: "website", label: "Website" },
6063
6351
  { value: "updated", label: "Recently changed" },
6064
- { value: "created", label: "Recently added" }
6352
+ { value: "created", label: "Recently added" },
6353
+ { value: "viewed", label: "Recently viewed" }
6065
6354
  ];
6066
6355
  function subtitleOf(item, withOwner) {
6067
6356
  const what = loginSiteOf(item) || item.definitionLabel;
6068
6357
  return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
6069
6358
  }
6070
- function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
6359
+ function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner, canSortViewed = false }) {
6360
+ const sorts = SORTS2.filter((s) => canSortViewed || s.value !== "viewed");
6071
6361
  const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
6072
6362
  const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
6073
6363
  const ordered = [...pinned, ...rest];
@@ -6087,34 +6377,34 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
6087
6377
  }
6088
6378
  };
6089
6379
  const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
6090
- const row = (i) => /* @__PURE__ */ jsx27(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
6091
- const sortLabel = SORTS2.find((s) => s.value === sort)?.label ?? "Name";
6092
- return /* @__PURE__ */ jsxs25("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
6093
- /* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
6380
+ const row = (i) => /* @__PURE__ */ jsx28(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
6381
+ const sortLabel = sorts.find((s) => s.value === sort)?.label ?? "Name A\u2013Z";
6382
+ return /* @__PURE__ */ jsxs26("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
6383
+ /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children: [
6094
6384
  header,
6095
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
6096
- /* @__PURE__ */ jsx27(SearchField, { value: query, onChange: (e) => onQuery(e.target.value), onKeyDown, placeholder: `Search ${title}`, className: "min-w-0 flex-1", "aria-label": "Search the vault" }),
6097
- /* @__PURE__ */ jsx27(Button22, { variant: "primary", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
6385
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
6386
+ /* @__PURE__ */ jsx28(SearchField, { value: query, onChange: (e) => onQuery(e.target.value), onKeyDown, placeholder: `Search ${title}`, className: "min-w-0 flex-1", "aria-label": "Search the vault" }),
6387
+ /* @__PURE__ */ jsx28(Button23, { variant: "primary", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), "aria-label": "New item", onClick: onNew })
6098
6388
  ] }),
6099
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between gap-2 px-1", children: [
6100
- /* @__PURE__ */ jsxs25("span", { className: "truncate text-xs text-muted-foreground", children: [
6389
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between gap-2 px-1", children: [
6390
+ /* @__PURE__ */ jsxs26("span", { className: "truncate text-xs text-muted-foreground", children: [
6101
6391
  items.length,
6102
6392
  " ",
6103
6393
  items.length === 1 ? "item" : "items"
6104
6394
  ] }),
6105
- /* @__PURE__ */ jsxs25(DropdownMenu4, { children: [
6106
- /* @__PURE__ */ jsx27(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(SortGlyph, {}), "aria-label": `Sort: ${sortLabel}`, children: sortLabel }) }),
6107
- /* @__PURE__ */ jsx27(DropdownMenuContent4, { align: "end", children: /* @__PURE__ */ jsx27(DropdownMenuRadioGroup, { value: sort, onValueChange: (v) => onSort(SORTS2.find((s) => s.value === v)?.value ?? "name"), children: SORTS2.map((s) => /* @__PURE__ */ jsx27(DropdownMenuRadioItem, { value: s.value, children: s.label }, s.value)) }) })
6395
+ /* @__PURE__ */ jsxs26(DropdownMenu4, { children: [
6396
+ /* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(SortGlyph, {}), "aria-label": `Sort: ${sortLabel}`, children: sortLabel }) }),
6397
+ /* @__PURE__ */ jsx28(DropdownMenuContent4, { align: "end", children: /* @__PURE__ */ jsx28(DropdownMenuRadioGroup, { value: sort, onValueChange: (v) => onSort(sorts.find((s) => s.value === v)?.value ?? "name"), children: sorts.map((s) => /* @__PURE__ */ jsx28(DropdownMenuRadioItem, { value: s.value, children: s.label }, s.value)) }) })
6108
6398
  ] })
6109
6399
  ] })
6110
6400
  ] }),
6111
- /* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ jsxs25("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
6112
- /* @__PURE__ */ jsx27("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
6113
- query ? /* @__PURE__ */ jsx27(Button22, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ jsx27(Button22, { variant: "outline", icon: /* @__PURE__ */ jsx27(PlusGlyph, {}), onClick: onNew, children: "New item" })
6114
- ] }) : /* @__PURE__ */ jsxs25("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
6115
- pinned.length > 0 ? /* @__PURE__ */ jsx27("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
6401
+ /* @__PURE__ */ jsx28("div", { className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3", onKeyDown, children: items.length === 0 ? /* @__PURE__ */ jsxs26("div", { className: "flex flex-col items-center gap-3 px-4 py-12 text-center", children: [
6402
+ /* @__PURE__ */ jsx28("span", { className: "text-sm text-muted-foreground", children: query ? `Nothing matches \u201C${query}\u201D.` : "Nothing here yet." }),
6403
+ query ? /* @__PURE__ */ jsx28(Button23, { variant: "outline", onClick: () => onQuery(""), children: "Clear search" }) : /* @__PURE__ */ jsx28(Button23, { variant: "outline", icon: /* @__PURE__ */ jsx28(PlusGlyph, {}), onClick: onNew, children: "New item" })
6404
+ ] }) : /* @__PURE__ */ jsxs26("ul", { ref: listRef, className: "flex flex-col gap-px", children: [
6405
+ pinned.length > 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 pb-1 pt-1 text-xs font-medium text-muted-foreground", children: "This page" }) : null,
6116
6406
  pinned.map(row),
6117
- pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */ jsx27("li", { className: "px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children: "Everything else" }) : null,
6407
+ pinned.length > 0 && rest.length > 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children: "Everything else" }) : null,
6118
6408
  rest.map(row)
6119
6409
  ] }) })
6120
6410
  ] });
@@ -6123,48 +6413,93 @@ function ListRow({ item, family, port, on, onSelect, withOwner }) {
6123
6413
  const confirmed = useConfirmed();
6124
6414
  const copy = useCopy();
6125
6415
  const notify = useNotify();
6126
- const [busy, setBusy] = useState27(false);
6127
- const user = item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed");
6128
- const secret = item.fields.find((f) => f.key === "password" && f.handling === "revealable");
6129
- const quick = async (key, label) => {
6416
+ const [busy, setBusy] = useState28(false);
6417
+ const [menuOpen, setMenuOpen] = useState28(false);
6418
+ const canUse = item.capabilities.canUse;
6419
+ const user = canUse ? item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active !== false) : void 0;
6420
+ const secret = canUse && item.capabilities.canReveal ? item.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active !== false) : void 0;
6421
+ const code = canUse && item.authenticator?.enabled ? item.authenticator : null;
6422
+ const run = async (label, read, isSecret) => {
6130
6423
  setBusy(true);
6131
6424
  try {
6132
- const v = await confirmed(() => port.reveal(item, key));
6133
- await copy(v, label, { secret: key !== user?.key || user.handling !== "visible" });
6425
+ const v = await confirmed(read);
6426
+ await copy(v, label, { secret: isSecret });
6134
6427
  } catch (e) {
6135
6428
  if (!wasCancelled(e)) notify(e instanceof Error ? e.message : `${label} could not be read`, "error");
6136
6429
  } finally {
6137
6430
  setBusy(false);
6138
6431
  }
6139
6432
  };
6140
- return /* @__PURE__ */ jsxs25("li", { className: "group relative", "data-item": item.id, children: [
6141
- /* @__PURE__ */ jsxs25(
6433
+ const copyUser = () => user && void run(user.label, () => port.reveal(item, user.key), user.handling !== "visible");
6434
+ const copyPassword = () => secret && void run("Password", () => port.reveal(item, secret.key), true);
6435
+ const copyCode = () => code && void run("One-time code", async () => (await port.authenticator.code(item)).code, true);
6436
+ const copyName = () => void copy(item.name, "Name", { secret: false });
6437
+ return /* @__PURE__ */ jsxs26("li", { className: "group relative", "data-item": item.id, children: [
6438
+ /* @__PURE__ */ jsxs26(
6142
6439
  "button",
6143
6440
  {
6144
6441
  type: "button",
6145
6442
  "aria-current": on ? "true" : void 0,
6146
6443
  "data-surface": on ? "primary" : void 0,
6147
6444
  onClick: () => onSelect(item.id),
6148
- className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
6445
+ className: cn13("flex h-12 w-full items-center gap-3 rounded-lg px-2 pr-10 text-left", on ? "bg-primary text-primary-foreground" : "hover:bg-accent"),
6149
6446
  children: [
6150
- /* @__PURE__ */ jsx27(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
6151
- /* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6152
- /* @__PURE__ */ jsx27("span", { className: "truncate text-sm font-medium", children: item.name }),
6153
- /* @__PURE__ */ jsx27("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
6447
+ /* @__PURE__ */ jsx28(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
6448
+ /* @__PURE__ */ jsxs26("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6449
+ /* @__PURE__ */ jsx28("span", { className: "truncate text-sm font-medium", children: item.name }),
6450
+ /* @__PURE__ */ jsx28("span", { className: "truncate text-xs text-muted-foreground", children: subtitleOf(item, withOwner) })
6154
6451
  ] })
6155
6452
  ]
6156
6453
  }
6157
6454
  ),
6158
- item.capabilities.canUse && (user || secret && item.capabilities.canReveal) ? /* @__PURE__ */ jsxs25("div", { className: cn13("absolute right-1.5 top-1/2 hidden -translate-y-1/2 items-center gap-0.5 rounded-md pl-2 group-hover:flex", on ? "bg-primary" : "bg-accent"), "data-surface": on ? "primary" : void 0, children: [
6159
- user ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: () => void quick(user.key, user.label) }) : null,
6160
- secret && item.capabilities.canReveal ? /* @__PURE__ */ jsx27(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx27(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: () => void quick(secret.key, "Password") }) : null
6161
- ] }) : null
6455
+ /* @__PURE__ */ jsxs26("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
6456
+ user || secret ? /* @__PURE__ */ jsxs26("div", { className: cn13("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
6457
+ user ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
6458
+ secret ? /* @__PURE__ */ jsx28(Button23, { variant: "quiet", icon: /* @__PURE__ */ jsx28(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
6459
+ ] }) : null,
6460
+ /* @__PURE__ */ jsxs26(DropdownMenu4, { open: menuOpen, onOpenChange: setMenuOpen, children: [
6461
+ /* @__PURE__ */ jsx28(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx28(
6462
+ Button23,
6463
+ {
6464
+ variant: "quiet",
6465
+ icon: /* @__PURE__ */ jsx28(MoreGlyph, {}),
6466
+ "aria-label": `Actions for ${item.name}`,
6467
+ disabled: busy,
6468
+ className: cn13("[@media(hover:hover)]:invisible [@media(hover:hover)]:group-hover:visible [@media(hover:hover)]:group-focus-within:visible", menuOpen && "[@media(hover:hover)]:visible")
6469
+ }
6470
+ ) }),
6471
+ /* @__PURE__ */ jsxs26(DropdownMenuContent4, { align: "end", children: [
6472
+ user ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyUser, children: [
6473
+ /* @__PURE__ */ jsx28(UserGlyph, { className: "size-4" }),
6474
+ "Copy ",
6475
+ user.label.toLowerCase()
6476
+ ] }) : null,
6477
+ secret ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyPassword, children: [
6478
+ /* @__PURE__ */ jsx28(KeyGlyph, { className: "size-4" }),
6479
+ "Copy password"
6480
+ ] }) : null,
6481
+ code ? /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyCode, children: [
6482
+ /* @__PURE__ */ jsx28(ClockGlyph, { className: "size-4" }),
6483
+ "Copy one-time code"
6484
+ ] }) : null,
6485
+ user || secret || code ? /* @__PURE__ */ jsx28(DropdownMenuSeparator4, {}) : null,
6486
+ /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: () => onSelect(item.id), children: [
6487
+ /* @__PURE__ */ jsx28(ChevronRightGlyph, { className: "size-4" }),
6488
+ "Open"
6489
+ ] }),
6490
+ /* @__PURE__ */ jsxs26(DropdownMenuItem4, { onSelect: copyName, children: [
6491
+ /* @__PURE__ */ jsx28(CopyIcon7, { className: "size-4" }),
6492
+ "Copy name"
6493
+ ] })
6494
+ ] })
6495
+ ] })
6496
+ ] })
6162
6497
  ] });
6163
6498
  }
6164
6499
 
6165
6500
  // src/lists/TrashView.tsx
6166
- import { useState as useState29 } from "react";
6167
- import { Button as Button24 } from "@ai-matrx/design-system/controls";
6501
+ import { useState as useState30 } from "react";
6502
+ import { Button as Button25 } from "@ai-matrx/design-system/controls";
6168
6503
  import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
6169
6504
 
6170
6505
  // src/lists/logic.ts
@@ -6237,15 +6572,15 @@ function refusalText(reason) {
6237
6572
  }
6238
6573
 
6239
6574
  // src/lists/RestorePanel.tsx
6240
- import { useEffect as useEffect18, useState as useState28 } from "react";
6241
- import { Button as Button23 } from "@ai-matrx/design-system/controls";
6242
- import { Fragment as Fragment17, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
6575
+ import { useEffect as useEffect18, useState as useState29 } from "react";
6576
+ import { Button as Button24 } from "@ai-matrx/design-system/controls";
6577
+ import { Fragment as Fragment18, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6243
6578
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
6244
6579
  function RestorePanel({ lists, item, restore, onClose }) {
6245
- const [preview, setPreview] = useState28(null);
6246
- const [error, setError] = useState28(null);
6247
- const [busy, setBusy] = useState28(false);
6248
- const [loading, setLoading] = useState28(Boolean(lists.preview));
6580
+ const [preview, setPreview] = useState29(null);
6581
+ const [error, setError] = useState29(null);
6582
+ const [busy, setBusy] = useState29(false);
6583
+ const [loading, setLoading] = useState29(Boolean(lists.preview));
6249
6584
  useEffect18(() => {
6250
6585
  if (!lists.preview) return;
6251
6586
  let live = true;
@@ -6278,41 +6613,41 @@ function RestorePanel({ lists, item, restore, onClose }) {
6278
6613
  setBusy(false);
6279
6614
  }
6280
6615
  };
6281
- return /* @__PURE__ */ jsxs26(
6616
+ return /* @__PURE__ */ jsxs27(
6282
6617
  Panel,
6283
6618
  {
6284
6619
  title: `Restore "${item.name}"`,
6285
6620
  size: "md",
6286
6621
  onClose,
6287
- footer: /* @__PURE__ */ jsxs26(Fragment17, { children: [
6288
- /* @__PURE__ */ jsx28(Button23, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
6289
- refused ? null : /* @__PURE__ */ jsx28(Button23, { variant: "primary", icon: /* @__PURE__ */ jsx28(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
6622
+ footer: /* @__PURE__ */ jsxs27(Fragment18, { children: [
6623
+ /* @__PURE__ */ jsx29(Button24, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
6624
+ refused ? null : /* @__PURE__ */ jsx29(Button24, { variant: "primary", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busy || loading || lists.preview !== void 0 && preview === null, onClick: () => void run(), children: busy ? "Restoring\u2026" : "Restore" })
6290
6625
  ] }),
6291
6626
  children: [
6292
- loading ? /* @__PURE__ */ jsx28(VaultSection, { children: /* @__PURE__ */ jsx28(Empty, { children: "Checking what comes back\u2026" }) }) : preview?.supported ? /* @__PURE__ */ jsxs26(VaultSection, { title: "Comes back", children: [
6293
- /* @__PURE__ */ jsx28(VaultRow, { label: "Fields", children: /* @__PURE__ */ jsx28("span", { className: "text-foreground", children: count(preview.fields, "field") }) }),
6294
- /* @__PURE__ */ jsx28(VaultRow, { label: "Files", children: /* @__PURE__ */ jsx28("span", { className: "text-foreground", children: count(preview.attachments, "file") }) }),
6295
- preview.passkeys === 1 ? /* @__PURE__ */ jsx28(VaultRow, { label: "Passkey", hint: "Not turned on; the site may not accept it", children: /* @__PURE__ */ jsx28("span", { className: "text-foreground", children: "1 passkey" }) }) : null,
6296
- /* @__PURE__ */ jsx28(VaultRow, { label: "Stays off", hint: "Turn each back on yourself", children: /* @__PURE__ */ jsx28("span", { className: "text-muted-foreground", children: "Sharing, browser fill, codes, sandboxes, agents" }) }),
6297
- preview.priorWasDisabled ? /* @__PURE__ */ jsx28(VaultRow, { label: "Before", children: /* @__PURE__ */ jsx28("span", { className: "text-muted-foreground", children: "It was already off before it was deleted." }) }) : null
6298
- ] }) : preview ? /* @__PURE__ */ jsx28(VaultSection, { children: /* @__PURE__ */ jsx28(Empty, { children: refusalText(preview.reason) }) }) : /* @__PURE__ */ jsx28(VaultSection, { children: /* @__PURE__ */ jsx28(Empty, { children: "It comes back turned off: sharing, browser fill, codes and sandbox use stay off." }) }),
6299
- error ? /* @__PURE__ */ jsx28("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
6627
+ loading ? /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: "Checking what comes back\u2026" }) }) : preview?.supported ? /* @__PURE__ */ jsxs27(VaultSection, { title: "Comes back", children: [
6628
+ /* @__PURE__ */ jsx29(VaultRow, { label: "Fields", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: count(preview.fields, "field") }) }),
6629
+ /* @__PURE__ */ jsx29(VaultRow, { label: "Files", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: count(preview.attachments, "file") }) }),
6630
+ preview.passkeys === 1 ? /* @__PURE__ */ jsx29(VaultRow, { label: "Passkey", hint: "Not turned on; the site may not accept it", children: /* @__PURE__ */ jsx29("span", { className: "text-foreground", children: "1 passkey" }) }) : null,
6631
+ /* @__PURE__ */ jsx29(VaultRow, { label: "Stays off", hint: "Turn each back on yourself", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "Sharing, browser fill, codes, sandboxes, agents" }) }),
6632
+ preview.priorWasDisabled ? /* @__PURE__ */ jsx29(VaultRow, { label: "Before", children: /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground", children: "It was already off before it was deleted." }) }) : null
6633
+ ] }) : preview ? /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: refusalText(preview.reason) }) }) : /* @__PURE__ */ jsx29(VaultSection, { children: /* @__PURE__ */ jsx29(Empty, { children: "It comes back turned off: sharing, browser fill, codes and sandbox use stay off." }) }),
6634
+ error ? /* @__PURE__ */ jsx29("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null
6300
6635
  ]
6301
6636
  }
6302
6637
  );
6303
6638
  }
6304
6639
 
6305
6640
  // src/lists/TrashView.tsx
6306
- import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6641
+ import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
6307
6642
  function trashLineOf(item) {
6308
6643
  return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
6309
6644
  }
6310
6645
  function TrashView({ port, deleted, query, header, onChanged }) {
6311
6646
  const confirmed = useConfirmed();
6312
- const [busyId, setBusyId] = useState29(null);
6313
- const [message2, setMessage] = useState29(null);
6647
+ const [busyId, setBusyId] = useState30(null);
6648
+ const [message2, setMessage] = useState30(null);
6314
6649
  const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
6315
- const [restoring, setRestoring] = useState29(null);
6650
+ const [restoring, setRestoring] = useState30(null);
6316
6651
  const restore = async (item, deletionId) => {
6317
6652
  setBusyId(item.id);
6318
6653
  setMessage(null);
@@ -6328,32 +6663,32 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6328
6663
  setBusyId(null);
6329
6664
  }
6330
6665
  };
6331
- return /* @__PURE__ */ jsxs27("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
6666
+ return /* @__PURE__ */ jsxs28("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3", children: [
6332
6667
  header,
6333
- /* @__PURE__ */ jsx29(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ jsx29(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
6668
+ /* @__PURE__ */ jsx30(VaultSection, { title: "Trash", children: shown.length === 0 ? /* @__PURE__ */ jsx30(Empty, { children: deleted.length === 0 ? "The trash is empty." : "Nothing matches." }) : shown.map((item) => (
6334
6669
  // A list row, not a field row: the name gets the whole width (on a phone a label column
6335
6670
  // left "Vau…" for every row), the deletion date sits under it.
6336
- /* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
6337
- /* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6338
- /* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
6339
- /* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
6671
+ /* @__PURE__ */ jsxs28("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
6672
+ /* @__PURE__ */ jsxs28("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6673
+ /* @__PURE__ */ jsx30("span", { className: "truncate text-sm text-foreground", children: item.name }),
6674
+ /* @__PURE__ */ jsx30("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
6340
6675
  ] }),
6341
- /* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
6676
+ /* @__PURE__ */ jsx30(Button25, { variant: "outline", icon: /* @__PURE__ */ jsx30(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
6342
6677
  ] }, item.id)
6343
6678
  )) }),
6344
- restoring ? /* @__PURE__ */ jsx29(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
6345
- message2 ? /* @__PURE__ */ jsx29("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
6679
+ restoring ? /* @__PURE__ */ jsx30(RestorePanel, { lists: port.lists, item: restoring, restore: (deletionId) => restore(restoring, deletionId), onClose: () => setRestoring(null) }) : null,
6680
+ message2 ? /* @__PURE__ */ jsx30("p", { role: "status", className: message2.tone === "error" ? "px-1 text-sm text-destructive" : "px-1 text-sm text-muted-foreground", children: message2.text }) : null
6346
6681
  ] });
6347
6682
  }
6348
6683
 
6349
6684
  // src/NewItemFlow.tsx
6350
- import { useMemo as useMemo4, useState as useState30 } from "react";
6685
+ import { useMemo as useMemo4, useState as useState31 } from "react";
6351
6686
  import { cn as cn14 } from "@ai-matrx/design-system";
6352
- import { Button as Button25, Field as Field10, SearchField as SearchField2 } from "@ai-matrx/design-system/controls";
6687
+ import { Button as Button26, Field as Field11, SearchField as SearchField2 } from "@ai-matrx/design-system/controls";
6353
6688
  import { GlobeIcon as GlobeIcon3 } from "@ai-matrx/design-system/icons";
6354
- import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
6689
+ import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
6355
6690
  function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6356
- const [search, setSearch] = useState30("");
6691
+ const [search, setSearch] = useState31("");
6357
6692
  const guess = useMemo4(() => inferFromUrl(url, definitions), [url, definitions]);
6358
6693
  const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
6359
6694
  const matches = useMemo4(() => {
@@ -6365,15 +6700,15 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6365
6700
  const alternatives = (guess?.alternatives ?? []).map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0).slice(0, 4);
6366
6701
  const use = (d) => onChoose(d.key, guess?.name ?? "", guess?.url ?? url.trim());
6367
6702
  const shown = search.trim() ? matches : common;
6368
- return /* @__PURE__ */ jsxs28("div", { className: "flex h-full min-h-0 flex-col bg-background", children: [
6369
- /* @__PURE__ */ jsxs28("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 sm:px-5", children: [
6370
- /* @__PURE__ */ jsx30(Button25, { variant: "quiet", icon: /* @__PURE__ */ jsx30(ChevronLeftGlyph, {}), "aria-label": "Cancel", onClick: onCancel }),
6371
- /* @__PURE__ */ jsx30("h2", { className: "text-base font-semibold", children: "New item" })
6703
+ return /* @__PURE__ */ jsxs29("div", { className: "flex h-full min-h-0 flex-col bg-background", children: [
6704
+ /* @__PURE__ */ jsxs29("header", { className: "flex min-h-14 items-center gap-2 border-b border-border px-3 sm:px-5", children: [
6705
+ /* @__PURE__ */ jsx31(Button26, { variant: "quiet", icon: /* @__PURE__ */ jsx31(ChevronLeftGlyph, {}), "aria-label": "Cancel", onClick: onCancel }),
6706
+ /* @__PURE__ */ jsx31("h2", { className: "text-base font-semibold", children: "New item" })
6372
6707
  ] }),
6373
- /* @__PURE__ */ jsx30("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxs28("div", { className: "mx-auto flex w-full max-w-2xl flex-col gap-8 px-4 py-8 sm:px-6 sm:py-12", children: [
6374
- /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-3", children: [
6375
- /* @__PURE__ */ jsx30(
6376
- Field10,
6708
+ /* @__PURE__ */ jsx31("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxs29("div", { className: "mx-auto flex w-full max-w-2xl flex-col gap-8 px-4 py-8 sm:px-6 sm:py-12", children: [
6709
+ /* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-3", children: [
6710
+ /* @__PURE__ */ jsx31(
6711
+ Field11,
6377
6712
  {
6378
6713
  hero: true,
6379
6714
  value: url,
@@ -6385,45 +6720,45 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6385
6720
  "aria-label": "Website address",
6386
6721
  inputMode: "url",
6387
6722
  autoFocus: true,
6388
- icon: /* @__PURE__ */ jsx30(GlobeIcon3, {})
6723
+ icon: /* @__PURE__ */ jsx31(GlobeIcon3, {})
6389
6724
  }
6390
6725
  ),
6391
- guess && login ? /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-2 rounded-xl border border-border bg-card p-3", children: [
6392
- /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-3", children: [
6393
- /* @__PURE__ */ jsx30("span", { "aria-hidden": true, className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-sm font-semibold", children: guess.name.charAt(0).toUpperCase() }),
6394
- /* @__PURE__ */ jsxs28("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6395
- /* @__PURE__ */ jsx30("span", { className: "truncate text-sm font-medium", children: guess.name }),
6396
- /* @__PURE__ */ jsx30("span", { className: "truncate text-xs text-muted-foreground", children: guess.url.replace(/^https?:\/\//, "") })
6726
+ guess && login ? /* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-2 rounded-xl border border-border bg-card p-3", children: [
6727
+ /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-3", children: [
6728
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": true, className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-sm font-semibold", children: guess.name.charAt(0).toUpperCase() }),
6729
+ /* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6730
+ /* @__PURE__ */ jsx31("span", { className: "truncate text-sm font-medium", children: guess.name }),
6731
+ /* @__PURE__ */ jsx31("span", { className: "truncate text-xs text-muted-foreground", children: guess.url.replace(/^https?:\/\//, "") })
6397
6732
  ] }),
6398
- /* @__PURE__ */ jsx30(Button25, { variant: "primary", onClick: () => use(login), children: "Save login" })
6733
+ /* @__PURE__ */ jsx31(Button26, { variant: "primary", onClick: () => use(login), children: "Save login" })
6399
6734
  ] }),
6400
- alternatives.length > 0 ? /* @__PURE__ */ jsxs28("div", { className: "flex flex-wrap items-center gap-1.5 pl-12", children: [
6401
- /* @__PURE__ */ jsx30("span", { className: "text-xs text-muted-foreground", children: "Or" }),
6402
- alternatives.map((d) => /* @__PURE__ */ jsx30(Button25, { variant: "outline", onClick: () => use(d), children: d.label }, d.key))
6735
+ alternatives.length > 0 ? /* @__PURE__ */ jsxs29("div", { className: "flex flex-wrap items-center gap-1.5 pl-12", children: [
6736
+ /* @__PURE__ */ jsx31("span", { className: "text-xs text-muted-foreground", children: "Or" }),
6737
+ alternatives.map((d) => /* @__PURE__ */ jsx31(Button26, { variant: "outline", onClick: () => use(d), children: d.label }, d.key))
6403
6738
  ] }) : null
6404
- ] }) : url.trim() ? /* @__PURE__ */ jsx30("p", { className: "px-1 text-sm text-muted-foreground", children: "Not a website address. Pick a type below; it is kept." }) : null
6739
+ ] }) : url.trim() ? /* @__PURE__ */ jsx31("p", { className: "px-1 text-sm text-muted-foreground", children: "Not a website address. Pick a type below; it is kept." }) : null
6405
6740
  ] }),
6406
- /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-3", children: [
6407
- /* @__PURE__ */ jsx30("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsx30("h3", { className: "text-xs font-medium text-muted-foreground", children: search.trim() ? "Matching types" : "Or choose a type" }) }),
6408
- /* @__PURE__ */ jsx30("ul", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: shown.map((d) => {
6741
+ /* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-3", children: [
6742
+ /* @__PURE__ */ jsx31("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsx31("h3", { className: "text-xs font-medium text-muted-foreground", children: search.trim() ? "Matching types" : "Or choose a type" }) }),
6743
+ /* @__PURE__ */ jsx31("ul", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: shown.map((d) => {
6409
6744
  const Icon = definitionGlyph(d.key, d.family);
6410
- return /* @__PURE__ */ jsx30("li", { children: /* @__PURE__ */ jsxs28("button", { type: "button", onClick: () => use(d), className: cn14("flex h-12 w-full items-center gap-3 rounded-xl border border-border bg-card px-3 text-left hover:bg-accent"), children: [
6411
- /* @__PURE__ */ jsx30("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ jsx30(Icon, { className: "size-4" }) }),
6412
- /* @__PURE__ */ jsx30("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: d.label })
6745
+ return /* @__PURE__ */ jsx31("li", { children: /* @__PURE__ */ jsxs29("button", { type: "button", onClick: () => use(d), className: cn14("flex h-12 w-full items-center gap-3 rounded-xl border border-border bg-card px-3 text-left hover:bg-accent"), children: [
6746
+ /* @__PURE__ */ jsx31("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ jsx31(Icon, { className: "size-4" }) }),
6747
+ /* @__PURE__ */ jsx31("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: d.label })
6413
6748
  ] }) }, d.key);
6414
6749
  }) }),
6415
- search.trim() && matches.length === 0 ? /* @__PURE__ */ jsx30("p", { className: "px-1 text-sm text-muted-foreground", children: "No type matches." }) : null,
6416
- /* @__PURE__ */ jsx30(SearchField2, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: `Search all ${definitions.length} types`, "aria-label": "Search types" })
6750
+ search.trim() && matches.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "px-1 text-sm text-muted-foreground", children: "No type matches." }) : null,
6751
+ /* @__PURE__ */ jsx31(SearchField2, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: `Search all ${definitions.length} types`, "aria-label": "Search types" })
6417
6752
  ] })
6418
6753
  ] }) })
6419
6754
  ] });
6420
6755
  }
6421
6756
 
6422
6757
  // src/sharing/SecureLinkPanel.tsx
6423
- import { useEffect as useEffect19, useRef as useRef16, useState as useState31 } from "react";
6424
- import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
6758
+ import { useEffect as useEffect19, useRef as useRef16, useState as useState32 } from "react";
6759
+ import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
6425
6760
  import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
6426
- import { Badge as Badge8, Button as Button26, Field as Field11, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl5, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
6761
+ import { Badge as Badge8, Button as Button27, Field as Field12, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl6, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
6427
6762
  import { formatAbsoluteDate as formatAbsoluteDate5 } from "@ai-matrx/kit/format";
6428
6763
 
6429
6764
  // src/sharing/secure-link-logic.ts
@@ -6499,23 +6834,23 @@ function sortSent(rows) {
6499
6834
  }
6500
6835
 
6501
6836
  // src/sharing/SecureLinkPanel.tsx
6502
- import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
6837
+ import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
6503
6838
  function SecureLinkPanel({ item, port, onClose }) {
6504
6839
  const sharing = port.sharing;
6505
6840
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
6506
- const [remedy, setRemedy] = useState31(null);
6507
- const [options, setOptions] = useState31(null);
6508
- const [optionsError, setOptionsError] = useState31(null);
6509
- const [sent, setSent] = useState31(null);
6510
- const [sentError, setSentError] = useState31(null);
6511
- const [nonce, setNonce] = useState31(0);
6512
- const [email, setEmail] = useState31("");
6513
- const [phone, setPhone] = useState31("");
6514
- const [name, setName] = useState31("");
6515
- const [linkBy, setLinkBy] = useState31("email");
6516
- const [fields, setFields] = useState31([]);
6517
- const [note, setNote] = useState31("");
6518
- const [sameChannelSent, setSameChannelSent] = useState31(false);
6841
+ const [remedy, setRemedy] = useState32(null);
6842
+ const [options, setOptions] = useState32(null);
6843
+ const [optionsError, setOptionsError] = useState32(null);
6844
+ const [sent, setSent] = useState32(null);
6845
+ const [sentError, setSentError] = useState32(null);
6846
+ const [nonce, setNonce] = useState32(0);
6847
+ const [email, setEmail] = useState32("");
6848
+ const [phone, setPhone] = useState32("");
6849
+ const [name, setName] = useState32("");
6850
+ const [linkBy, setLinkBy] = useState32("email");
6851
+ const [fields, setFields] = useState32([]);
6852
+ const [note, setNote] = useState32("");
6853
+ const [sameChannelSent, setSameChannelSent] = useState32(false);
6519
6854
  useEffect19(() => {
6520
6855
  let live = true;
6521
6856
  setOptionsError(null);
@@ -6544,7 +6879,7 @@ function SecureLinkPanel({ item, port, onClose }) {
6544
6879
  live = false;
6545
6880
  };
6546
6881
  }, [sharing, item, nonce]);
6547
- const [phoneTyped, setPhoneTyped] = useState31(false);
6882
+ const [phoneTyped, setPhoneTyped] = useState32(false);
6548
6883
  const prefilled = useRef16(false);
6549
6884
  useEffect19(() => {
6550
6885
  const lookup = sharing.phoneOnFile;
@@ -6608,7 +6943,7 @@ function SecureLinkPanel({ item, port, onClose }) {
6608
6943
  setNonce((n) => n + 1);
6609
6944
  };
6610
6945
  const turnOff = async (row) => {
6611
- const ok = await confirm10({
6946
+ const ok = await confirm11({
6612
6947
  title: "Turn off this link?",
6613
6948
  description: `The link to ${recipientOf(row)} stops working at once and what it carries is deleted. They will need a new one.`,
6614
6949
  confirmLabel: "Turn off",
@@ -6621,23 +6956,23 @@ function SecureLinkPanel({ item, port, onClose }) {
6621
6956
  setNonce((n) => n + 1);
6622
6957
  };
6623
6958
  const toggle2 = (key, on) => setFields((cur) => on ? [...cur.filter((k) => k !== key), key] : cur.filter((k) => k !== key));
6624
- return /* @__PURE__ */ jsxs29(
6959
+ return /* @__PURE__ */ jsxs30(
6625
6960
  Panel,
6626
6961
  {
6627
6962
  title: "Send securely",
6628
6963
  size: "md",
6629
6964
  onClose,
6630
- footer: /* @__PURE__ */ jsxs29(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx31(StatusLine, { error, notice }) : null, children: [
6631
- sameChannelSent && !error ? /* @__PURE__ */ jsx31(Badge8, { tone: "warning", children: "Both by email" }) : null,
6632
- /* @__PURE__ */ jsx31(Button26, { variant: "quiet", onClick: onClose, children: "Close" }),
6633
- /* @__PURE__ */ jsx31(Button26, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
6965
+ footer: /* @__PURE__ */ jsxs30(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx32(StatusLine, { error, notice }) : null, children: [
6966
+ sameChannelSent && !error ? /* @__PURE__ */ jsx32(Badge8, { tone: "warning", children: "Both by email" }) : null,
6967
+ /* @__PURE__ */ jsx32(Button27, { variant: "quiet", onClick: onClose, children: "Close" }),
6968
+ /* @__PURE__ */ jsx32(Button27, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
6634
6969
  ] }),
6635
6970
  children: [
6636
- remedy ? /* @__PURE__ */ jsx31("p", { className: "px-1 text-xs text-muted-foreground", children: remedy }) : null,
6637
- /* @__PURE__ */ jsxs29(VaultSection, { title: "Recipient", children: [
6638
- /* @__PURE__ */ jsx31(VaultRow, { label: "Email", children: /* @__PURE__ */ jsx31(Field11, { type: "email", autoComplete: "off", placeholder: "name@example.com", "aria-label": "Their email", value: email, onChange: (e) => setEmail(e.target.value), className: "w-full" }) }),
6639
- /* @__PURE__ */ jsx31(VaultRow, { label: "Mobile", hint: "For the code", children: /* @__PURE__ */ jsx31(
6640
- Field11,
6971
+ remedy ? /* @__PURE__ */ jsx32("p", { className: "px-1 text-xs text-muted-foreground", children: remedy }) : null,
6972
+ /* @__PURE__ */ jsxs30(VaultSection, { title: "Recipient", children: [
6973
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Email", children: /* @__PURE__ */ jsx32(Field12, { type: "email", autoComplete: "off", placeholder: "name@example.com", "aria-label": "Their email", value: email, onChange: (e) => setEmail(e.target.value), className: "w-full" }) }),
6974
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Mobile", hint: "For the code", children: /* @__PURE__ */ jsx32(
6975
+ Field12,
6641
6976
  {
6642
6977
  type: "tel",
6643
6978
  autoComplete: "off",
@@ -6652,9 +6987,9 @@ function SecureLinkPanel({ item, port, onClose }) {
6652
6987
  className: "w-full"
6653
6988
  }
6654
6989
  ) }),
6655
- /* @__PURE__ */ jsx31(VaultRow, { label: "Name", hint: "Optional", children: /* @__PURE__ */ jsx31(Field11, { autoComplete: "off", placeholder: "Their name", "aria-label": "Their name", value: name, onChange: (e) => setName(e.target.value), className: "w-full" }) }),
6656
- plan && !plan.same ? /* @__PURE__ */ jsx31(VaultRow, { label: "Link by", children: /* @__PURE__ */ jsx31(
6657
- SegmentedControl5,
6990
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Name", hint: "Optional", children: /* @__PURE__ */ jsx32(Field12, { autoComplete: "off", placeholder: "Their name", "aria-label": "Their name", value: name, onChange: (e) => setName(e.target.value), className: "w-full" }) }),
6991
+ plan && !plan.same ? /* @__PURE__ */ jsx32(VaultRow, { label: "Link by", children: /* @__PURE__ */ jsx32(
6992
+ SegmentedControl6,
6658
6993
  {
6659
6994
  "aria-label": "Send the link by",
6660
6995
  value: linkBy,
@@ -6665,28 +7000,28 @@ function SecureLinkPanel({ item, port, onClose }) {
6665
7000
  ]
6666
7001
  }
6667
7002
  ) }) : null,
6668
- email.trim() ? /* @__PURE__ */ jsx31(VaultRow, { label: "Delivery", children: /* @__PURE__ */ jsx31("span", { className: plan?.same ? "text-warning" : "text-foreground", children: planWords(plan) }) }) : null
7003
+ email.trim() ? /* @__PURE__ */ jsx32(VaultRow, { label: "Delivery", children: /* @__PURE__ */ jsx32("span", { className: plan?.same ? "text-warning" : "text-foreground", children: planWords(plan) }) }) : null
6669
7004
  ] }),
6670
- /* @__PURE__ */ jsx31(VaultSection, { title: "Include", children: optionsError ? /* @__PURE__ */ jsx31(Empty, { children: /* @__PURE__ */ jsx31("span", { className: "text-destructive", children: optionsError }) }) : !options ? /* @__PURE__ */ jsx31(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading what can be sent", className: "px-3 sm:px-4" }) : options.fields.length === 0 ? /* @__PURE__ */ jsx31(Empty, { children: "Name and details only" }) : options.fields.map((f) => /* @__PURE__ */ jsxs29("label", { className: "flex min-h-11 items-center gap-3 px-3 py-1 sm:px-4", "data-clickable": f.available ? "" : void 0, children: [
6671
- /* @__PURE__ */ jsx31(Checkbox2, { checked: fields.includes(f.key), disabled: !f.available, onCheckedChange: (v) => toggle2(f.key, v === true), "aria-label": f.label }),
6672
- /* @__PURE__ */ jsx31("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: f.label }),
6673
- !f.available && f.reason ? /* @__PURE__ */ jsx31("span", { className: "min-w-0 max-w-[55%] truncate text-xs text-muted-foreground", title: f.reason, children: f.reason }) : null
7005
+ /* @__PURE__ */ jsx32(VaultSection, { title: "Include", children: optionsError ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: optionsError }) }) : !options ? /* @__PURE__ */ jsx32(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading what can be sent", className: "px-3 sm:px-4" }) : options.fields.length === 0 ? /* @__PURE__ */ jsx32(Empty, { children: "Name and details only" }) : options.fields.map((f) => /* @__PURE__ */ jsxs30("label", { className: "flex min-h-11 items-center gap-3 px-3 py-1 sm:px-4", "data-clickable": f.available ? "" : void 0, children: [
7006
+ /* @__PURE__ */ jsx32(Checkbox2, { checked: fields.includes(f.key), disabled: !f.available, onCheckedChange: (v) => toggle2(f.key, v === true), "aria-label": f.label }),
7007
+ /* @__PURE__ */ jsx32("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: f.label }),
7008
+ !f.available && f.reason ? /* @__PURE__ */ jsx32("span", { className: "min-w-0 max-w-[55%] truncate text-xs text-muted-foreground", title: f.reason, children: f.reason }) : null
6674
7009
  ] }, f.key)) }),
6675
- /* @__PURE__ */ jsx31(VaultSection, { title: "Message", children: /* @__PURE__ */ jsx31("div", { className: "px-3 py-1 sm:px-4", children: /* @__PURE__ */ jsx31(Textarea4, { className: "w-full", rows: 2, maxLength: NOTE_MAX, placeholder: "Shown once, with it", "aria-label": "Message", value: note, onChange: (e) => setNote(e.target.value) }) }) }),
6676
- options ? /* @__PURE__ */ jsxs29(VaultSection, { title: "Link", children: [
6677
- /* @__PURE__ */ jsx31(VaultRow, { label: "Opens", children: /* @__PURE__ */ jsx31("span", { className: "text-foreground", children: "Once" }) }),
6678
- /* @__PURE__ */ jsx31(VaultRow, { label: "Link expires", children: /* @__PURE__ */ jsxs29("span", { className: "text-foreground", children: [
7010
+ /* @__PURE__ */ jsx32(VaultSection, { title: "Message", children: /* @__PURE__ */ jsx32("div", { className: "px-3 py-1 sm:px-4", children: /* @__PURE__ */ jsx32(Textarea4, { className: "w-full", rows: 2, maxLength: NOTE_MAX, placeholder: "Shown once, with it", "aria-label": "Message", value: note, onChange: (e) => setNote(e.target.value) }) }) }),
7011
+ options ? /* @__PURE__ */ jsxs30(VaultSection, { title: "Link", children: [
7012
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Opens", children: /* @__PURE__ */ jsx32("span", { className: "text-foreground", children: "Once" }) }),
7013
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Link expires", children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
6679
7014
  "After ",
6680
7015
  lifetimeWords(options.linkMinutes)
6681
7016
  ] }) }),
6682
- /* @__PURE__ */ jsx31(VaultRow, { label: "Code expires", children: /* @__PURE__ */ jsxs29("span", { className: "text-foreground", children: [
7017
+ /* @__PURE__ */ jsx32(VaultRow, { label: "Code expires", children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
6683
7018
  "After ",
6684
7019
  lifetimeWords(options.codeMinutes)
6685
7020
  ] }) })
6686
7021
  ] }) : null,
6687
- sharing.sentSecureLinks ? /* @__PURE__ */ jsx31(VaultSection, { title: "Sent links", children: sentError ? /* @__PURE__ */ jsx31(Empty, { children: /* @__PURE__ */ jsx31("span", { className: "text-destructive", children: sentError }) }) : !sent ? /* @__PURE__ */ jsx31(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading sent links", className: "px-3 sm:px-4" }) : sent.length === 0 ? /* @__PURE__ */ jsx31(Empty, { children: "None yet" }) : sent.map((row) => /* @__PURE__ */ jsxs29(AccessLine, { glyph: row.status === "pending" ? ClockGlyph : row.fieldKeys.length ? LockGlyph : ShareGlyph, who: recipientOf(row), meta: sentMeta(row, options), children: [
6688
- /* @__PURE__ */ jsx31(Badge8, { tone: STATUS_TONE[row.status] ?? "neutral", children: statusWord(row.status) }),
6689
- row.status === "pending" ? /* @__PURE__ */ jsx31(Button26, { variant: "quiet", disabled: busy !== null, onClick: () => void turnOff(row), children: "Turn off" }) : null
7022
+ sharing.sentSecureLinks ? /* @__PURE__ */ jsx32(VaultSection, { title: "Sent links", children: sentError ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: sentError }) }) : !sent ? /* @__PURE__ */ jsx32(RegionSkeleton2, { shape: "rows", count: 2, "aria-label": "Loading sent links", className: "px-3 sm:px-4" }) : sent.length === 0 ? /* @__PURE__ */ jsx32(Empty, { children: "None yet" }) : sent.map((row) => /* @__PURE__ */ jsxs30(AccessLine, { glyph: row.status === "pending" ? ClockGlyph : row.fieldKeys.length ? LockGlyph : ShareGlyph, who: recipientOf(row), meta: sentMeta(row, options), children: [
7023
+ /* @__PURE__ */ jsx32(Badge8, { tone: STATUS_TONE[row.status] ?? "neutral", children: statusWord(row.status) }),
7024
+ row.status === "pending" ? /* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: () => void turnOff(row), children: "Turn off" }) : null
6690
7025
  ] }, row.id)) }) : null
6691
7026
  ]
6692
7027
  }
@@ -6699,9 +7034,9 @@ function sentMeta(row, options) {
6699
7034
  }
6700
7035
 
6701
7036
  // src/devices/DevicesPanel.tsx
6702
- import { useCallback as useCallback4, useEffect as useEffect20, useState as useState32 } from "react";
6703
- import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
6704
- import { Button as Button27, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
7037
+ import { useCallback as useCallback4, useEffect as useEffect20, useState as useState33 } from "react";
7038
+ import { confirm as confirm12 } from "@ai-matrx/kit/confirm-opener";
7039
+ import { Button as Button28, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
6705
7040
  import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
6706
7041
 
6707
7042
  // src/devices/logic.ts
@@ -6782,17 +7117,17 @@ function addPasskeyFailure(message2) {
6782
7117
  var isRevoked = (d) => d.revokedAt !== null;
6783
7118
 
6784
7119
  // src/devices/DevicesPanel.tsx
6785
- import { Fragment as Fragment18, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
7120
+ import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
6786
7121
  var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
6787
7122
  function ErrorLine2({ text }) {
6788
- return text ? /* @__PURE__ */ jsx32("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
7123
+ return text ? /* @__PURE__ */ jsx33("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
6789
7124
  }
6790
7125
  function DevicesPanel({ port, onClose }) {
6791
7126
  const confirmed = useConfirmed();
6792
7127
  const notify = useNotify();
6793
- const [devices, setDevices] = useState32(null);
6794
- const [error, setError] = useState32(null);
6795
- const [busyId, setBusyId] = useState32(null);
7128
+ const [devices, setDevices] = useState33(null);
7129
+ const [error, setError] = useState33(null);
7130
+ const [busyId, setBusyId] = useState33(null);
6796
7131
  const load = useCallback4(async () => {
6797
7132
  setError(null);
6798
7133
  try {
@@ -6805,7 +7140,7 @@ function DevicesPanel({ port, onClose }) {
6805
7140
  void load();
6806
7141
  }, [load]);
6807
7142
  const revoke = async (device) => {
6808
- const yes = await confirm11({
7143
+ const yes = await confirm12({
6809
7144
  title: `Revoke ${device.label}?`,
6810
7145
  description: "It stops filling now and the extension there signs out. It fills again only after you sign in there and confirm.",
6811
7146
  confirmLabel: "Revoke",
@@ -6824,19 +7159,19 @@ function DevicesPanel({ port, onClose }) {
6824
7159
  setBusyId(null);
6825
7160
  }
6826
7161
  };
6827
- return /* @__PURE__ */ jsxs30(Panel, { title: "Browsers that can fill", onClose, size: "md", children: [
6828
- /* @__PURE__ */ jsx32(ErrorLine2, { text: error }),
6829
- /* @__PURE__ */ jsx32(VaultSection, { children: devices === null ? error ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32(Button27, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx32(RegionSkeleton3, { shape: "rows", count: 2, "aria-label": "Loading your browsers", className: "px-3 sm:px-4" }) : devices.length === 0 ? /* @__PURE__ */ jsx32(Empty, { children: "No browser can fill yet. Turn it on in the extension." }) : devices.map((device) => {
7162
+ return /* @__PURE__ */ jsxs31(Panel, { title: "Browsers that can fill", onClose, size: "md", children: [
7163
+ /* @__PURE__ */ jsx33(ErrorLine2, { text: error }),
7164
+ /* @__PURE__ */ jsx33(VaultSection, { children: devices === null ? error ? /* @__PURE__ */ jsx33(Empty, { children: /* @__PURE__ */ jsx33(Button28, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx33(RegionSkeleton3, { shape: "rows", count: 2, "aria-label": "Loading your browsers", className: "px-3 sm:px-4" }) : devices.length === 0 ? /* @__PURE__ */ jsx33(Empty, { children: "No browser can fill yet. Turn it on in the extension." }) : devices.map((device) => {
6830
7165
  const off = isRevoked(device);
6831
- return /* @__PURE__ */ jsx32(
7166
+ return /* @__PURE__ */ jsx33(
6832
7167
  VaultRow,
6833
7168
  {
6834
7169
  label: off ? "Turned off" : "Can fill",
6835
7170
  hint: off ? formatAbsoluteDate6(device.revokedAt, DAY_FORMAT, "") : void 0,
6836
- actions: off ? null : /* @__PURE__ */ jsx32(Button27, { variant: "outline", icon: /* @__PURE__ */ jsx32(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
6837
- children: /* @__PURE__ */ jsxs30("span", { className: "flex min-w-0 flex-col", children: [
6838
- /* @__PURE__ */ jsx32("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
6839
- /* @__PURE__ */ jsxs30("span", { className: "truncate text-xs text-muted-foreground", children: [
7171
+ actions: off ? null : /* @__PURE__ */ jsx33(Button28, { variant: "outline", icon: /* @__PURE__ */ jsx33(PowerGlyph, {}), disabled: busyId !== null, onClick: () => void revoke(device), children: "Revoke" }),
7172
+ children: /* @__PURE__ */ jsxs31("span", { className: "flex min-w-0 flex-col", children: [
7173
+ /* @__PURE__ */ jsx33("span", { className: off ? "truncate text-muted-foreground" : "truncate text-foreground", children: device.label }),
7174
+ /* @__PURE__ */ jsxs31("span", { className: "truncate text-xs text-muted-foreground", children: [
6840
7175
  device.lastUsedAt ? `Last used ${formatAbsoluteDate6(device.lastUsedAt, void 0, "")}` : "Never used",
6841
7176
  device.addedAt ? ` \xB7 added ${formatAbsoluteDate6(device.addedAt, DAY_FORMAT, "")}` : ""
6842
7177
  ] })
@@ -6859,10 +7194,10 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6859
7194
  const where = isMac ? "the Mac app" : "the extension";
6860
7195
  const passkeys = port.devices.passkeys;
6861
7196
  const here = passkeys?.available() ?? false;
6862
- const [methods, setMethods] = useState32(null);
6863
- const [busy, setBusy] = useState32(null);
6864
- const [error, setError] = useState32(null);
6865
- const [approvedUntil, setApprovedUntil] = useState32(null);
7197
+ const [methods, setMethods] = useState33(null);
7198
+ const [busy, setBusy] = useState33(null);
7199
+ const [error, setError] = useState33(null);
7200
+ const [approvedUntil, setApprovedUntil] = useState33(null);
6866
7201
  const load = useCallback4(async () => {
6867
7202
  setError(null);
6868
7203
  try {
@@ -6913,55 +7248,55 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6913
7248
  };
6914
7249
  const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
6915
7250
  const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
6916
- const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
6917
- /* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
6918
- canApprove ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", icon: /* @__PURE__ */ jsx32(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
7251
+ const footer = approvedUntil ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7252
+ /* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
7253
+ canApprove ? /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void approve(), children: busy === "approve" ? "Approving\u2026" : "Approve with passkey" }) : null
6919
7254
  ] });
6920
- return /* @__PURE__ */ jsx32(Panel, { title, onClose: refuse, size: "sm", footer, children: !key ? /* @__PURE__ */ jsx32(VaultSection, { children: /* @__PURE__ */ jsxs30(Empty, { children: [
7255
+ return /* @__PURE__ */ jsx33(Panel, { title, onClose: refuse, size: "sm", footer, children: !key ? /* @__PURE__ */ jsx33(VaultSection, { children: /* @__PURE__ */ jsxs31(Empty, { children: [
6921
7256
  "This link names no key. Start again from ",
6922
7257
  where,
6923
7258
  "."
6924
- ] }) }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
6925
- /* @__PURE__ */ jsxs30(VaultSection, { title: "What is asking", children: [
6926
- /* @__PURE__ */ jsx32(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
6927
- name ? /* @__PURE__ */ jsx32(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx32("span", { className: "block truncate", children: name }) }) : null,
6928
- /* @__PURE__ */ jsx32(VaultRow, { label: "Code", hint: `Must match ${where}`, children: /* @__PURE__ */ jsx32("span", { className: "font-mono tracking-wider text-foreground", children: shortFingerprint(key) }) })
7259
+ ] }) }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7260
+ /* @__PURE__ */ jsxs31(VaultSection, { title: "What is asking", children: [
7261
+ /* @__PURE__ */ jsx33(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
7262
+ name ? /* @__PURE__ */ jsx33(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx33("span", { className: "block truncate", children: name }) }) : null,
7263
+ /* @__PURE__ */ jsx33(VaultRow, { label: "Code", hint: `Must match ${where}`, children: /* @__PURE__ */ jsx33("span", { className: "font-mono tracking-wider text-foreground", children: shortFingerprint(key) }) })
6929
7264
  ] }),
6930
- /* @__PURE__ */ jsx32(ErrorLine2, { text: error }),
6931
- /* @__PURE__ */ jsx32(VaultSection, { title: "Confirm it\u2019s you", children: approvedUntil ? /* @__PURE__ */ jsx32(VaultRow, { label: "Approved", actions: /* @__PURE__ */ jsx32(CheckGlyph, { className: "size-4 text-primary" }), children: /* @__PURE__ */ jsxs30("span", { className: "text-foreground", children: [
7265
+ /* @__PURE__ */ jsx33(ErrorLine2, { text: error }),
7266
+ /* @__PURE__ */ jsx33(VaultSection, { title: "Confirm it\u2019s you", children: approvedUntil ? /* @__PURE__ */ jsx33(VaultRow, { label: "Approved", actions: /* @__PURE__ */ jsx33(CheckGlyph, { className: "size-4 text-primary" }), children: /* @__PURE__ */ jsxs31("span", { className: "text-foreground", children: [
6932
7267
  "Return to ",
6933
7268
  where,
6934
7269
  " by ",
6935
7270
  formatAbsoluteDate6(approvedUntil, void 0, ""),
6936
7271
  "."
6937
- ] }) }) : !passkeys ? /* @__PURE__ */ jsxs30(Empty, { children: [
7272
+ ] }) }) : !passkeys ? /* @__PURE__ */ jsxs31(Empty, { children: [
6938
7273
  "Approve with your password in ",
6939
7274
  where,
6940
7275
  "."
6941
- ] }) : !here ? /* @__PURE__ */ jsx32(
7276
+ ] }) : !here ? /* @__PURE__ */ jsx33(
6942
7277
  VaultRow,
6943
7278
  {
6944
7279
  label: "Passkey",
6945
7280
  hint: `Passkeys work only on ${passkeys.rpId}`,
6946
- actions: /* @__PURE__ */ jsx32(Button27, { variant: "outline", icon: /* @__PURE__ */ jsx32(ExternalGlyph, {}), onClick: openOnDomain, children: "Open there" }),
6947
- children: /* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: "Not on this page" })
7281
+ actions: /* @__PURE__ */ jsx33(Button28, { variant: "outline", icon: /* @__PURE__ */ jsx33(ExternalGlyph, {}), onClick: openOnDomain, children: "Open there" }),
7282
+ children: /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground", children: "Not on this page" })
6948
7283
  }
6949
- ) : methods === null ? error ? /* @__PURE__ */ jsx32(Empty, { children: /* @__PURE__ */ jsx32(Button27, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx32(RegionSkeleton3, { shape: "rows", count: 1, "aria-label": "Checking your account", className: "px-3 sm:px-4" }) : !methods.passkey ? /* @__PURE__ */ jsx32(
7284
+ ) : methods === null ? error ? /* @__PURE__ */ jsx33(Empty, { children: /* @__PURE__ */ jsx33(Button28, { variant: "outline", onClick: () => void load(), children: "Try again" }) }) : /* @__PURE__ */ jsx33(RegionSkeleton3, { shape: "rows", count: 1, "aria-label": "Checking your account", className: "px-3 sm:px-4" }) : !methods.passkey ? /* @__PURE__ */ jsx33(
6950
7285
  VaultRow,
6951
7286
  {
6952
7287
  label: "Passkey",
6953
7288
  hint: methods.password ? `Or type your password in ${where}` : "Add one to approve",
6954
- actions: /* @__PURE__ */ jsx32(Button27, { variant: "primary", icon: /* @__PURE__ */ jsx32(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void addPasskey(), children: busy === "add" ? "Adding\u2026" : "Add passkey" }),
6955
- children: /* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: methods.password ? "None yet" : "No password or passkey" })
7289
+ actions: /* @__PURE__ */ jsx33(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(FingerprintGlyph, {}), disabled: busy !== null, onClick: () => void addPasskey(), children: busy === "add" ? "Adding\u2026" : "Add passkey" }),
7290
+ children: /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground", children: methods.password ? "None yet" : "No password or passkey" })
6956
7291
  }
6957
- ) : /* @__PURE__ */ jsx32(VaultRow, { label: "Passkey", hint: "Your device asks for it next", children: /* @__PURE__ */ jsx32("span", { className: "text-foreground", children: "Ready" }) }) })
7292
+ ) : /* @__PURE__ */ jsx33(VaultRow, { label: "Passkey", hint: "Your device asks for it next", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: "Ready" }) }) })
6958
7293
  ] }) });
6959
7294
  }
6960
7295
 
6961
7296
  // src/native/NativeImportPanel.tsx
6962
- import { useEffect as useEffect22, useMemo as useMemo5, useState as useState34 } from "react";
6963
- import { confirm as confirm12 } from "@ai-matrx/kit/confirm-opener";
6964
- import { Badge as Badge9, Button as Button28, Select as Select9 } from "@ai-matrx/design-system/controls";
7297
+ import { useEffect as useEffect22, useMemo as useMemo5, useState as useState35 } from "react";
7298
+ import { confirm as confirm13 } from "@ai-matrx/kit/confirm-opener";
7299
+ import { Badge as Badge9, Button as Button29, Select as Select10 } from "@ai-matrx/design-system/controls";
6965
7300
 
6966
7301
  // src/native/logic.ts
6967
7302
  var ACTIVE_PHASES = /* @__PURE__ */ new Set(["authorizing", "importing"]);
@@ -7022,12 +7357,12 @@ async function loadFullPreview(bridge, operationId, current) {
7022
7357
  }
7023
7358
 
7024
7359
  // src/native/use-native-import.ts
7025
- import { useEffect as useEffect21, useRef as useRef17, useState as useState33 } from "react";
7360
+ import { useEffect as useEffect21, useRef as useRef17, useState as useState34 } from "react";
7026
7361
  var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
7027
7362
  var RESTART = "Your account changed. The import was stopped; start it again.";
7028
7363
  function useNativeImport(bridge, stillAllowed, onImported) {
7029
- const [screen, setScreen] = useState33({ kind: "idle", message: null });
7030
- const [busy, setBusy] = useState33(false);
7364
+ const [screen, setScreen] = useState34({ kind: "idle", message: null });
7365
+ const [busy, setBusy] = useState34(false);
7031
7366
  const generation = useRef17(0);
7032
7367
  const mounted = useRef17(false);
7033
7368
  const op = useRef17(null);
@@ -7135,7 +7470,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7135
7470
  }
7136
7471
  };
7137
7472
  refreshRef.current = refresh;
7138
- const confirm14 = async () => {
7473
+ const confirm15 = async () => {
7139
7474
  if (screen.kind !== "preview") return;
7140
7475
  const active = op.current;
7141
7476
  if (!active?.organizationId || active.id !== screen.preview.operation_id) return;
@@ -7217,11 +7552,11 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7217
7552
  off?.();
7218
7553
  };
7219
7554
  }, [bridge]);
7220
- return { screen, busy, begin, refresh: () => refresh(false), confirm: confirm14, cancel, recover, reset };
7555
+ return { screen, busy, begin, refresh: () => refresh(false), confirm: confirm15, cancel, recover, reset };
7221
7556
  }
7222
7557
 
7223
7558
  // src/native/NativeImportPanel.tsx
7224
- import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7559
+ import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7225
7560
  var TONE = {
7226
7561
  eligible: "success",
7227
7562
  committed: "success",
@@ -7232,15 +7567,15 @@ var TONE = {
7232
7567
  };
7233
7568
  function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
7234
7569
  if (!bridge) {
7235
- return /* @__PURE__ */ jsx33(Panel, { title: "Import passkeys", size: "md", onClose, footer: /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Close" }), children: /* @__PURE__ */ jsx33(VaultSection, { children: /* @__PURE__ */ jsx33(Empty, { children: "Passkey import needs the desktop app." }) }) });
7570
+ return /* @__PURE__ */ jsx34(Panel, { title: "Import passkeys", size: "md", onClose, footer: /* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Close" }), children: /* @__PURE__ */ jsx34(VaultSection, { children: /* @__PURE__ */ jsx34(Empty, { children: "Passkey import needs the desktop app." }) }) });
7236
7571
  }
7237
- return /* @__PURE__ */ jsx33(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
7572
+ return /* @__PURE__ */ jsx34(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
7238
7573
  }
7239
7574
  function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
7240
7575
  const options = useMemo5(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
7241
- const [organizationId, setOrganizationId] = useState34(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7242
- const [limits, setLimits] = useState34(null);
7243
- const [limitError, setLimitError] = useState34(null);
7576
+ const [organizationId, setOrganizationId] = useState35(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7577
+ const [limits, setLimits] = useState35(null);
7578
+ const [limitError, setLimitError] = useState35(null);
7244
7579
  const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
7245
7580
  const { screen, busy } = flow;
7246
7581
  const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
@@ -7262,64 +7597,64 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
7262
7597
  const active = status !== null && !TERMINAL_PHASES.has(status.phase);
7263
7598
  const ready = preview?.slots.filter((s) => s.disposition === "eligible").length ?? 0;
7264
7599
  const importNow = async () => {
7265
- const yes = await confirm12({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
7600
+ const yes = await confirm13({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
7266
7601
  if (yes) await flow.confirm();
7267
7602
  };
7268
- const footer = preview ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
7269
- /* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
7270
- /* @__PURE__ */ jsxs31(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
7603
+ const footer = preview ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
7604
+ /* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
7605
+ /* @__PURE__ */ jsxs32(Button29, { variant: "primary", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
7271
7606
  "Import ",
7272
7607
  ready
7273
7608
  ] })
7274
- ] }) : status ? active ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
7275
- /* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
7276
- /* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
7277
- ] }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7278
- /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: flow.reset, children: "New file" }),
7279
- /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" })
7280
- ] }) : /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: onClose, children: "Close" });
7281
- return /* @__PURE__ */ jsxs31(Panel, { title: "Import passkeys", size: "lg", onClose, footer, children: [
7282
- screen.kind === "idle" ? /* @__PURE__ */ jsxs31(VaultSection, { children: [
7283
- /* @__PURE__ */ jsx33(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx33(Select9, { value: organizationId, options, "aria-label": "Save to", disabled: busy, onValueChange: setOrganizationId }) }),
7284
- /* @__PURE__ */ jsx33(VaultRow, { label: "File", hint: limits ? `Up to ${plural2(limits.maxItems, "passkey")}` : "A passkey exchange file", children: /* @__PURE__ */ jsx33(Button28, { variant: "outline", icon: /* @__PURE__ */ jsx33(ImportGlyph, { className: "size-4" }), disabled: busy || !organizationId || limitError !== null, onClick: () => void flow.begin(organizationId), children: busy ? "Opening\u2026" : "Choose file" }) }),
7285
- /* @__PURE__ */ jsx33(VaultRow, { label: "Interrupted", hint: "Finish or clear an earlier import", children: /* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy, onClick: () => void flow.recover(), children: "Recover" }) })
7609
+ ] }) : status ? active ? /* @__PURE__ */ jsxs32(Fragment20, { children: [
7610
+ /* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
7611
+ /* @__PURE__ */ jsx34(Button29, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
7612
+ ] }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
7613
+ /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: flow.reset, children: "New file" }),
7614
+ /* @__PURE__ */ jsx34(Button29, { variant: "primary", onClick: onClose, children: "Done" })
7615
+ ] }) : /* @__PURE__ */ jsx34(Button29, { variant: "quiet", onClick: onClose, children: "Close" });
7616
+ return /* @__PURE__ */ jsxs32(Panel, { title: "Import passkeys", size: "lg", onClose, footer, children: [
7617
+ screen.kind === "idle" ? /* @__PURE__ */ jsxs32(VaultSection, { children: [
7618
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx34(Select10, { value: organizationId, options, "aria-label": "Save to", disabled: busy, onValueChange: setOrganizationId }) }),
7619
+ /* @__PURE__ */ jsx34(VaultRow, { label: "File", hint: limits ? `Up to ${plural2(limits.maxItems, "passkey")}` : "A passkey exchange file", children: /* @__PURE__ */ jsx34(Button29, { variant: "outline", icon: /* @__PURE__ */ jsx34(ImportGlyph, { className: "size-4" }), disabled: busy || !organizationId || limitError !== null, onClick: () => void flow.begin(organizationId), children: busy ? "Opening\u2026" : "Choose file" }) }),
7620
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Interrupted", hint: "Finish or clear an earlier import", children: /* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void flow.recover(), children: "Recover" }) })
7286
7621
  ] }) : null,
7287
- preview ? /* @__PURE__ */ jsx33(VaultSection, { title: `${ready} of ${preview.total} ready`, children: /* @__PURE__ */ jsx33(
7622
+ preview ? /* @__PURE__ */ jsx34(VaultSection, { title: `${ready} of ${preview.total} ready`, children: /* @__PURE__ */ jsx34(
7288
7623
  Windowed,
7289
7624
  {
7290
7625
  items: preview.slots,
7291
- render: (slot) => /* @__PURE__ */ jsx33(VaultRow, { label: /* @__PURE__ */ jsx33(Badge9, { tone: TONE[slot.disposition], children: dispositionLabel(slot.disposition) }), hint: void 0, children: /* @__PURE__ */ jsx33("span", { className: "block truncate text-foreground", title: slot.reason ?? void 0, children: slot.title ?? "Unnamed passkey" }) }, slot.slot_id)
7626
+ render: (slot) => /* @__PURE__ */ jsx34(VaultRow, { label: /* @__PURE__ */ jsx34(Badge9, { tone: TONE[slot.disposition], children: dispositionLabel(slot.disposition) }), hint: void 0, children: /* @__PURE__ */ jsx34("span", { className: "block truncate text-foreground", title: slot.reason ?? void 0, children: slot.title ?? "Unnamed passkey" }) }, slot.slot_id)
7292
7627
  }
7293
7628
  ) }) : null,
7294
- status && !preview ? /* @__PURE__ */ jsxs31(VaultSection, { title: `${accounted(status)} of ${status.total} done`, children: [
7295
- /* @__PURE__ */ jsx33(VaultRow, { label: "Imported", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: status.committed }) }),
7296
- /* @__PURE__ */ jsx33(VaultRow, { label: "Already there", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: status.already_present }) }),
7297
- /* @__PURE__ */ jsx33(VaultRow, { label: "Can't import", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: status.unsupported }) }),
7298
- /* @__PURE__ */ jsx33(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx33("span", { className: status.failed > 0 ? "text-destructive" : "text-foreground", children: status.failed }) }),
7299
- status.uncertain > 0 ? /* @__PURE__ */ jsx33(VaultRow, { label: "Needs recovery", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: status.uncertain }) }) : null,
7300
- status.not_attempted > 0 ? /* @__PURE__ */ jsx33(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx33("span", { className: "text-foreground", children: status.not_attempted }) }) : null
7629
+ status && !preview ? /* @__PURE__ */ jsxs32(VaultSection, { title: `${accounted(status)} of ${status.total} done`, children: [
7630
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Imported", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.committed }) }),
7631
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Already there", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.already_present }) }),
7632
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Can't import", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.unsupported }) }),
7633
+ /* @__PURE__ */ jsx34(VaultRow, { label: "Failed", children: /* @__PURE__ */ jsx34("span", { className: status.failed > 0 ? "text-destructive" : "text-foreground", children: status.failed }) }),
7634
+ status.uncertain > 0 ? /* @__PURE__ */ jsx34(VaultRow, { label: "Needs recovery", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.uncertain }) }) : null,
7635
+ status.not_attempted > 0 ? /* @__PURE__ */ jsx34(VaultRow, { label: "Not tried", children: /* @__PURE__ */ jsx34("span", { className: "text-foreground", children: status.not_attempted }) }) : null
7301
7636
  ] }) : null,
7302
- screen.message ? /* @__PURE__ */ jsx33("p", { role: "status", className: "px-1 text-sm text-muted-foreground", children: screen.message }) : null,
7303
- /* @__PURE__ */ jsx33(ErrorLine, { message: limitError })
7637
+ screen.message ? /* @__PURE__ */ jsx34("p", { role: "status", className: "px-1 text-sm text-muted-foreground", children: screen.message }) : null,
7638
+ /* @__PURE__ */ jsx34(ErrorLine, { message: limitError })
7304
7639
  ] });
7305
7640
  }
7306
7641
 
7307
7642
  // src/extension/PageView.tsx
7308
- import { useState as useState38 } from "react";
7309
- import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as DropdownMenuItem4, DropdownMenuTrigger as DropdownMenuTrigger5, SiteIcon } from "@ai-matrx/design-system";
7310
- import { Button as Button32 } from "@ai-matrx/design-system/controls";
7643
+ import { useState as useState39 } from "react";
7644
+ import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as DropdownMenuItem5, DropdownMenuTrigger as DropdownMenuTrigger5, SiteIcon } from "@ai-matrx/design-system";
7645
+ import { Button as Button33 } from "@ai-matrx/design-system/controls";
7311
7646
  import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
7312
7647
 
7313
7648
  // src/extension/CaptureCard.tsx
7314
- import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
7315
- import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
7316
- import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7649
+ import { useState as useState36, useSyncExternalStore as useSyncExternalStore3 } from "react";
7650
+ import { Button as Button30, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
7651
+ import { Fragment as Fragment21, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
7317
7652
  var SEARCH_FROM = 4;
7318
7653
  function CaptureCard({ capture, onChanged }) {
7319
7654
  const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
7320
7655
  const notify = useNotify();
7321
- const [busy, setBusy] = useState35(false);
7322
- const [q, setQ] = useState35("");
7656
+ const [busy, setBusy] = useState36(false);
7657
+ const [q, setQ] = useState36("");
7323
7658
  if (!prompt) return null;
7324
7659
  const decide = async (d) => {
7325
7660
  setBusy(true);
@@ -7337,53 +7672,53 @@ function CaptureCard({ capture, onChanged }) {
7337
7672
  const existing = prompt.existing;
7338
7673
  const needle = q.trim().toLocaleLowerCase();
7339
7674
  const shown = needle ? existing.filter((x) => x.name.toLocaleLowerCase().includes(needle)) : existing;
7340
- return /* @__PURE__ */ jsxs32("section", { "aria-label": "Save this login", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
7341
- /* @__PURE__ */ jsxs32("div", { className: "flex items-center gap-2.5", children: [
7342
- /* @__PURE__ */ jsx34(ShieldGlyph, { className: "size-5 shrink-0 text-primary" }),
7343
- /* @__PURE__ */ jsxs32("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7344
- /* @__PURE__ */ jsx34("span", { className: "truncate text-sm font-medium", children: prompt.unavailable ? "Couldn\u2019t hold this login" : "Save this login?" }),
7345
- /* @__PURE__ */ jsx34("span", { className: "truncate text-xs text-muted-foreground", children: prompt.username ? `${prompt.host} \xB7 ${prompt.username}` : prompt.host })
7675
+ return /* @__PURE__ */ jsxs33("section", { "aria-label": "Save this login", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
7676
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2.5", children: [
7677
+ /* @__PURE__ */ jsx35(ShieldGlyph, { className: "size-5 shrink-0 text-primary" }),
7678
+ /* @__PURE__ */ jsxs33("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7679
+ /* @__PURE__ */ jsx35("span", { className: "truncate text-sm font-medium", children: prompt.unavailable ? "Couldn\u2019t hold this login" : "Save this login?" }),
7680
+ /* @__PURE__ */ jsx35("span", { className: "truncate text-xs text-muted-foreground", children: prompt.username ? `${prompt.host} \xB7 ${prompt.username}` : prompt.host })
7346
7681
  ] }),
7347
- /* @__PURE__ */ jsx34(Button29, { variant: "quiet", icon: /* @__PURE__ */ jsx34(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
7682
+ /* @__PURE__ */ jsx35(Button30, { variant: "quiet", icon: /* @__PURE__ */ jsx35(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
7348
7683
  ] }),
7349
- prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(Fragment20, { children: [
7350
- existing.length > 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
7351
- existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx34(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
7352
- /* @__PURE__ */ jsxs32("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
7684
+ prompt.unavailable ? /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs33(Fragment21, { children: [
7685
+ existing.length > 0 ? /* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1", children: [
7686
+ existing.length >= SEARCH_FROM ? /* @__PURE__ */ jsx35(SearchField3, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Search logins", "aria-label": "Search logins to update" }) : null,
7687
+ /* @__PURE__ */ jsxs33("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
7353
7688
  shown.map((x) => {
7354
7689
  const tag = distinguish(x, existing);
7355
- return /* @__PURE__ */ jsxs32("li", { className: "flex h-9 items-center gap-2 px-1", children: [
7356
- /* @__PURE__ */ jsxs32("span", { className: "min-w-0 flex-1 truncate text-sm", children: [
7690
+ return /* @__PURE__ */ jsxs33("li", { className: "flex h-9 items-center gap-2 px-1", children: [
7691
+ /* @__PURE__ */ jsxs33("span", { className: "min-w-0 flex-1 truncate text-sm", children: [
7357
7692
  x.name,
7358
- tag ? /* @__PURE__ */ jsxs32("span", { className: "text-muted-foreground", children: [
7693
+ tag ? /* @__PURE__ */ jsxs33("span", { className: "text-muted-foreground", children: [
7359
7694
  " \xB7 ",
7360
7695
  tag
7361
7696
  ] }) : null
7362
7697
  ] }),
7363
- /* @__PURE__ */ jsx34(Button29, { variant: "primary", disabled: busy, onClick: () => void decide({ action: "update", itemId: x.itemId }), "aria-label": `Update ${x.name}`, children: "Update" })
7698
+ /* @__PURE__ */ jsx35(Button30, { variant: "primary", disabled: busy, onClick: () => void decide({ action: "update", itemId: x.itemId }), "aria-label": `Update ${x.name}`, children: "Update" })
7364
7699
  ] }, x.itemId);
7365
7700
  }),
7366
- shown.length === 0 ? /* @__PURE__ */ jsx34("li", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No saved login matches." }) : null
7701
+ shown.length === 0 ? /* @__PURE__ */ jsx35("li", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No saved login matches." }) : null
7367
7702
  ] })
7368
7703
  ] }) : null,
7369
- /* @__PURE__ */ jsxs32("div", { className: "flex flex-wrap items-center gap-2", children: [
7370
- /* @__PURE__ */ jsx34(Button29, { variant: existing.length > 0 ? "outline" : "primary", disabled: busy, onClick: () => void decide({ action: "save" }), children: existing.length > 0 ? "Save as new" : "Save" }),
7371
- /* @__PURE__ */ jsx34(Button29, { variant: "quiet", disabled: busy, onClick: () => void decide({ action: "never" }), children: "Never here" })
7704
+ /* @__PURE__ */ jsxs33("div", { className: "flex flex-wrap items-center gap-2", children: [
7705
+ /* @__PURE__ */ jsx35(Button30, { variant: existing.length > 0 ? "outline" : "primary", disabled: busy, onClick: () => void decide({ action: "save" }), children: existing.length > 0 ? "Save as new" : "Save" }),
7706
+ /* @__PURE__ */ jsx35(Button30, { variant: "quiet", disabled: busy, onClick: () => void decide({ action: "never" }), children: "Never here" })
7372
7707
  ] })
7373
7708
  ] })
7374
7709
  ] });
7375
7710
  }
7376
7711
 
7377
7712
  // src/extension/FillSetupCard.tsx
7378
- import { useRef as useRef18, useState as useState36, useSyncExternalStore as useSyncExternalStore4 } from "react";
7379
- import { Button as Button30, Field as Field12 } from "@ai-matrx/design-system/controls";
7380
- import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
7713
+ import { useRef as useRef18, useState as useState37, useSyncExternalStore as useSyncExternalStore4 } from "react";
7714
+ import { Button as Button31, Field as Field13 } from "@ai-matrx/design-system/controls";
7715
+ import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
7381
7716
  function FillSetupCard({ fillSetup }) {
7382
7717
  const notify = useNotify();
7383
7718
  const state = useSyncExternalStore4(fillSetup.subscribe, fillSetup.get, fillSetup.get);
7384
7719
  const box = useRef18(null);
7385
- const [busy, setBusy] = useState36(false);
7386
- const [error, setError] = useState36(null);
7720
+ const [busy, setBusy] = useState37(false);
7721
+ const [error, setError] = useState37(null);
7387
7722
  if (state.status !== "off") return null;
7388
7723
  const finish = async (run) => {
7389
7724
  setBusy(true);
@@ -7409,15 +7744,15 @@ function FillSetupCard({ fillSetup }) {
7409
7744
  const neither = m !== null && !m.password && !m.passkey;
7410
7745
  const showPassword = !neither && (m === null || m.password);
7411
7746
  const showPasskey = state.passkey !== null && (neither || m === null || m.passkey);
7412
- return /* @__PURE__ */ jsxs33("section", { "aria-label": "Turn on filling", "data-testid": "fill-setup", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
7413
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2.5", children: [
7414
- /* @__PURE__ */ jsx35(KeyGlyph, { className: "size-5 shrink-0 text-primary" }),
7415
- /* @__PURE__ */ jsxs33("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7416
- /* @__PURE__ */ jsx35("span", { className: "truncate text-sm font-medium", children: "Turn on filling" }),
7417
- /* @__PURE__ */ jsx35("span", { className: "truncate text-xs text-muted-foreground", children: neither ? "Add a passkey on the web first." : "Confirm it\u2019s you once in this browser." })
7747
+ return /* @__PURE__ */ jsxs34("section", { "aria-label": "Turn on filling", "data-testid": "fill-setup", className: "flex flex-col gap-2 rounded-xl border border-border bg-card px-3 py-2.5", children: [
7748
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2.5", children: [
7749
+ /* @__PURE__ */ jsx36(KeyGlyph, { className: "size-5 shrink-0 text-primary" }),
7750
+ /* @__PURE__ */ jsxs34("div", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7751
+ /* @__PURE__ */ jsx36("span", { className: "truncate text-sm font-medium", children: "Turn on filling" }),
7752
+ /* @__PURE__ */ jsx36("span", { className: "truncate text-xs text-muted-foreground", children: neither ? "Add a passkey on the web first." : "Confirm it\u2019s you once in this browser." })
7418
7753
  ] })
7419
7754
  ] }),
7420
- showPassword ? /* @__PURE__ */ jsxs33(
7755
+ showPassword ? /* @__PURE__ */ jsxs34(
7421
7756
  "form",
7422
7757
  {
7423
7758
  className: "flex items-center gap-2",
@@ -7426,42 +7761,42 @@ function FillSetupCard({ fillSetup }) {
7426
7761
  withPassword();
7427
7762
  },
7428
7763
  children: [
7429
- /* @__PURE__ */ jsx35(Field12, { ref: box, className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "AI Matrx password", "aria-label": "Your AI Matrx password", disabled: busy }),
7430
- /* @__PURE__ */ jsx35(Button30, { variant: "primary", type: "submit", disabled: busy, children: "Turn on" })
7764
+ /* @__PURE__ */ jsx36(Field13, { ref: box, className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "AI Matrx password", "aria-label": "Your AI Matrx password", disabled: busy }),
7765
+ /* @__PURE__ */ jsx36(Button31, { variant: "primary", type: "submit", disabled: busy, children: "Turn on" })
7431
7766
  ]
7432
7767
  }
7433
7768
  ) : null,
7434
- showPasskey ? /* @__PURE__ */ jsx35(Button30, { variant: "outline", iconEnd: /* @__PURE__ */ jsx35(ExternalGlyph, {}), disabled: busy, onClick: () => {
7769
+ showPasskey ? /* @__PURE__ */ jsx36(Button31, { variant: "outline", iconEnd: /* @__PURE__ */ jsx36(ExternalGlyph, {}), disabled: busy, onClick: () => {
7435
7770
  setError(null);
7436
7771
  fillSetup.openPasskey();
7437
7772
  }, children: neither ? "Add a passkey" : "Use a passkey" }) : null,
7438
- showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2", "data-testid": "fill-setup-waiting", children: [
7439
- /* @__PURE__ */ jsxs33("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: [
7773
+ showPasskey && state.awaitingPasskey && state.passkey ? /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", "data-testid": "fill-setup-waiting", children: [
7774
+ /* @__PURE__ */ jsxs34("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: [
7440
7775
  "Approve code ",
7441
- /* @__PURE__ */ jsx35("span", { className: "font-mono text-foreground", children: state.passkey.code }),
7776
+ /* @__PURE__ */ jsx36("span", { className: "font-mono text-foreground", children: state.passkey.code }),
7442
7777
  " on that page."
7443
7778
  ] }),
7444
- /* @__PURE__ */ jsx35(Button30, { variant: "primary", disabled: busy, onClick: () => void finish(() => fillSetup.finishPasskey()), children: "I approved" })
7779
+ /* @__PURE__ */ jsx36(Button31, { variant: "primary", disabled: busy, onClick: () => void finish(() => fillSetup.finishPasskey()), children: "I approved" })
7445
7780
  ] }) : null,
7446
- error ? /* @__PURE__ */ jsx35("p", { role: "alert", className: "text-xs text-destructive", children: error }) : null
7781
+ error ? /* @__PURE__ */ jsx36("p", { role: "alert", className: "text-xs text-destructive", children: error }) : null
7447
7782
  ] });
7448
7783
  }
7449
7784
 
7450
7785
  // src/extension/PageGenerator.tsx
7451
- import { useState as useState37 } from "react";
7786
+ import { useState as useState38 } from "react";
7452
7787
  import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
7453
- import { Button as Button31 } from "@ai-matrx/design-system/controls";
7454
- import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
7455
- import { Fragment as Fragment21, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
7788
+ import { Button as Button32 } from "@ai-matrx/design-system/controls";
7789
+ import { CopyIcon as CopyIcon8 } from "@ai-matrx/design-system/icons";
7790
+ import { Fragment as Fragment22, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
7456
7791
  var HOLD_MS = 6e4;
7457
7792
  function PageGenerator({ fields }) {
7458
7793
  const limits = useGeneratorLimitsSource();
7459
7794
  const copy = useCopy();
7460
7795
  const held = useTransientSecret(HOLD_MS);
7461
- const [open, setOpen] = useState37(false);
7462
- const [busy, setBusy] = useState37(false);
7463
- const [targets, setTargets] = useState37([]);
7464
- const [said, setSaid] = useState37(null);
7796
+ const [open, setOpen] = useState38(false);
7797
+ const [busy, setBusy] = useState38(false);
7798
+ const [targets, setTargets] = useState38([]);
7799
+ const [said, setSaid] = useState38(null);
7465
7800
  if (!limits) return null;
7466
7801
  const say3 = setSaid;
7467
7802
  const put = async (targetId, value2) => {
@@ -7503,30 +7838,30 @@ function PageGenerator({ fields }) {
7503
7838
  }
7504
7839
  };
7505
7840
  const value = held.value;
7506
- return /* @__PURE__ */ jsxs34(Fragment21, { children: [
7507
- /* @__PURE__ */ jsx36(
7841
+ return /* @__PURE__ */ jsxs35(Fragment22, { children: [
7842
+ /* @__PURE__ */ jsx37(
7508
7843
  VaultRow,
7509
7844
  {
7510
7845
  label: "New password",
7511
- actions: /* @__PURE__ */ jsxs34(Fragment21, { children: [
7512
- value ? /* @__PURE__ */ jsx36(Button31, { variant: "quiet", icon: /* @__PURE__ */ jsx36(CopyIcon7, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
7513
- /* @__PURE__ */ jsxs34(Popover2, { open, onOpenChange: setOpen, children: [
7514
- /* @__PURE__ */ jsx36(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx36(Button31, { variant: "outline", icon: /* @__PURE__ */ jsx36(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
7515
- /* @__PURE__ */ jsx36(PopoverContent2, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx36(PasswordGenerator, { limits, useLabel: "Fill page", onUse: (v) => void onUse(v) }) : null })
7846
+ actions: /* @__PURE__ */ jsxs35(Fragment22, { children: [
7847
+ value ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(CopyIcon8, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
7848
+ /* @__PURE__ */ jsxs35(Popover2, { open, onOpenChange: setOpen, children: [
7849
+ /* @__PURE__ */ jsx37(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx37(Button32, { variant: "outline", icon: /* @__PURE__ */ jsx37(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
7850
+ /* @__PURE__ */ jsx37(PopoverContent2, { sizing: "content", align: "end", children: open ? /* @__PURE__ */ jsx37(PasswordGenerator, { limits, useLabel: "Fill page", onUse: (v) => void onUse(v) }) : null })
7516
7851
  ] })
7517
7852
  ] }),
7518
- children: said ? /* @__PURE__ */ jsx36("span", { role: "status", className: said.tone === "success" ? "line-clamp-2 text-xs text-foreground" : "line-clamp-2 text-xs text-muted-foreground", children: said.text }) : targets.length > 0 ? /* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children: "Choose the boxes to fill." }) : /* @__PURE__ */ jsx36("span", { className: "text-xs text-disabled-foreground", children: "Fills the page\u2019s new-password box" })
7853
+ children: said ? /* @__PURE__ */ jsx37("span", { role: "status", className: said.tone === "success" ? "line-clamp-2 text-xs text-foreground" : "line-clamp-2 text-xs text-muted-foreground", children: said.text }) : targets.length > 0 ? /* @__PURE__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: "Choose the boxes to fill." }) : /* @__PURE__ */ jsx37("span", { className: "text-xs text-disabled-foreground", children: "Fills the page\u2019s new-password box" })
7519
7854
  }
7520
7855
  ),
7521
- value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */ jsx36(VaultRow, { label: t.topFrame ? "This page" : "In a frame", actions: /* @__PURE__ */ jsx36(Button31, { variant: "primary", icon: /* @__PURE__ */ jsx36(CheckGlyph, {}), disabled: busy, onClick: () => void put(t.id, value), children: "Fill" }), children: /* @__PURE__ */ jsx36("span", { className: "block truncate text-sm", children: targetLabel(t) }) }, t.id)) : null
7856
+ value && targets.length > 0 ? targets.map((t) => /* @__PURE__ */ jsx37(VaultRow, { label: t.topFrame ? "This page" : "In a frame", actions: /* @__PURE__ */ jsx37(Button32, { variant: "primary", icon: /* @__PURE__ */ jsx37(CheckGlyph, {}), disabled: busy, onClick: () => void put(t.id, value), children: "Fill" }), children: /* @__PURE__ */ jsx37("span", { className: "block truncate text-sm", children: targetLabel(t) }) }, t.id)) : null
7522
7857
  ] });
7523
7858
  }
7524
7859
 
7525
7860
  // src/extension/PageView.tsx
7526
- import { jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
7861
+ import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
7527
7862
  function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
7528
- const [running, setRunning] = useState38(null);
7529
- const [said, setSaid] = useState38(null);
7863
+ const [running, setRunning] = useState39(null);
7864
+ const [said, setSaid] = useState39(null);
7530
7865
  const site = pageSite(page.url);
7531
7866
  const state = page.matchState ?? { status: "ready" };
7532
7867
  const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
@@ -7547,20 +7882,20 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
7547
7882
  }
7548
7883
  };
7549
7884
  let body;
7550
- if (!page.url) body = /* @__PURE__ */ jsx37(Empty, { children: "No page is open in this tab." });
7885
+ if (!page.url) body = /* @__PURE__ */ jsx38(Empty, { children: "No page is open in this tab." });
7551
7886
  else if (state.status === "error") {
7552
- body = /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 px-3 py-2 sm:px-4", children: [
7553
- /* @__PURE__ */ jsx37("span", { role: "alert", className: "min-w-0 flex-1 text-sm text-muted-foreground", children: MATCH_ERROR_WORDS[state.reason] }),
7554
- /* @__PURE__ */ jsx37(Button32, { variant: "outline", icon: /* @__PURE__ */ jsx37(RefreshGlyph, {}), onClick: state.retry, children: "Retry" })
7887
+ body = /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 px-3 py-2 sm:px-4", children: [
7888
+ /* @__PURE__ */ jsx38("span", { role: "alert", className: "min-w-0 flex-1 text-sm text-muted-foreground", children: MATCH_ERROR_WORDS[state.reason] }),
7889
+ /* @__PURE__ */ jsx38(Button33, { variant: "outline", icon: /* @__PURE__ */ jsx38(RefreshGlyph, {}), onClick: state.retry, children: "Retry" })
7555
7890
  ] });
7556
7891
  } else if (state.status === "loading") {
7557
- body = /* @__PURE__ */ jsx37("div", { "aria-busy": "true", "aria-label": "Checking saved logins", className: "flex flex-col", children: [0, 1].map((n) => /* @__PURE__ */ jsxs35("div", { className: "flex h-12 items-center gap-3 px-3", children: [
7558
- /* @__PURE__ */ jsx37("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
7559
- /* @__PURE__ */ jsx37("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })
7892
+ body = /* @__PURE__ */ jsx38("div", { "aria-busy": "true", "aria-label": "Checking saved logins", className: "flex flex-col", children: [0, 1].map((n) => /* @__PURE__ */ jsxs36("div", { className: "flex h-12 items-center gap-3 px-3", children: [
7893
+ /* @__PURE__ */ jsx38("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
7894
+ /* @__PURE__ */ jsx38("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })
7560
7895
  ] }, n)) });
7561
- } else if (matches.length === 0) body = /* @__PURE__ */ jsx37(Empty, { children: "No saved login for this site." });
7896
+ } else if (matches.length === 0) body = /* @__PURE__ */ jsx38(Empty, { children: "No saved login for this site." });
7562
7897
  else {
7563
- body = /* @__PURE__ */ jsx37("ul", { className: "flex flex-col", children: matches.map(({ itemId, item }) => /* @__PURE__ */ jsx37(
7898
+ body = /* @__PURE__ */ jsx38("ul", { className: "flex flex-col", children: matches.map(({ itemId, item }) => /* @__PURE__ */ jsx38(
7564
7899
  MatchRow,
7565
7900
  {
7566
7901
  itemId,
@@ -7577,40 +7912,40 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
7577
7912
  itemId
7578
7913
  )) });
7579
7914
  }
7580
- return /* @__PURE__ */ jsx37("div", { className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background text-foreground", children: /* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-3 px-3 pb-4 pt-3", children: [
7915
+ return /* @__PURE__ */ jsx38("div", { className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background text-foreground", children: /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-3 px-3 pb-4 pt-3", children: [
7581
7916
  header,
7582
- /* @__PURE__ */ jsxs35("div", { className: "flex min-h-7 items-center gap-2 px-1", children: [
7583
- /* @__PURE__ */ jsx37(SiteIcon, { site: page.url, fallback: GlobeIcon4, className: "size-4" }),
7584
- /* @__PURE__ */ jsx37("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", title: page.url, children: site || "No page open" }),
7585
- page.refresh ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(RefreshGlyph, {}), "aria-label": "Check again", onClick: page.refresh }) : null,
7586
- onBrowse ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(ListGlyph, {}), onClick: onBrowse, children: "All items" }) : null
7917
+ /* @__PURE__ */ jsxs36("div", { className: "flex min-h-7 items-center gap-2 px-1", children: [
7918
+ /* @__PURE__ */ jsx38(SiteIcon, { site: page.url, fallback: GlobeIcon4, className: "size-4" }),
7919
+ /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", title: page.url, children: site || "No page open" }),
7920
+ page.refresh ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(RefreshGlyph, {}), "aria-label": "Check again", onClick: page.refresh }) : null,
7921
+ onBrowse ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(ListGlyph, {}), onClick: onBrowse, children: "All items" }) : null
7587
7922
  ] }),
7588
- fillSetup ? /* @__PURE__ */ jsx37(FillSetupCard, { fillSetup }) : null,
7589
- capture ? /* @__PURE__ */ jsx37(CaptureCard, { capture, onChanged }) : null,
7590
- /* @__PURE__ */ jsx37(
7923
+ fillSetup ? /* @__PURE__ */ jsx38(FillSetupCard, { fillSetup }) : null,
7924
+ capture ? /* @__PURE__ */ jsx38(CaptureCard, { capture, onChanged }) : null,
7925
+ /* @__PURE__ */ jsx38(
7591
7926
  VaultSection,
7592
7927
  {
7593
7928
  title: "This site",
7594
- actions: canSave ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(PlusGlyph, {}), onClick: () => onNewForPage(normalizeLoginUrl2(page.url) ?? page.url), children: "Save a login" }) : null,
7929
+ actions: canSave ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(PlusGlyph, {}), onClick: () => onNewForPage(normalizeLoginUrl2(page.url) ?? page.url), children: "Save a login" }) : null,
7595
7930
  children: body
7596
7931
  }
7597
7932
  ),
7598
- said ? /* @__PURE__ */ jsx37(Outcome, { said, onDismiss: () => setSaid(null) }) : page.blocked && page.url && state.status === "ready" ? /* @__PURE__ */ jsx37("p", { className: "px-1 text-xs text-muted-foreground", children: BLOCK_WORDS[page.blocked] }) : null,
7599
- newPasswordFields && canSave ? /* @__PURE__ */ jsx37(VaultSection, { children: /* @__PURE__ */ jsx37(PageGenerator, { fields: newPasswordFields }) }) : null
7933
+ said ? /* @__PURE__ */ jsx38(Outcome, { said, onDismiss: () => setSaid(null) }) : page.blocked && page.url && state.status === "ready" ? /* @__PURE__ */ jsx38("p", { className: "px-1 text-xs text-muted-foreground", children: BLOCK_WORDS[page.blocked] }) : null,
7934
+ newPasswordFields && canSave ? /* @__PURE__ */ jsx38(VaultSection, { children: /* @__PURE__ */ jsx38(PageGenerator, { fields: newPasswordFields }) }) : null
7600
7935
  ] }) });
7601
7936
  }
7602
7937
  function Outcome({ said, onDismiss }) {
7603
- return /* @__PURE__ */ jsxs35("div", { role: "status", className: "flex items-center gap-2 px-1", children: [
7604
- said.tone === "success" ? /* @__PURE__ */ jsx37(CheckGlyph, { className: "size-4 shrink-0 text-primary" }) : /* @__PURE__ */ jsx37(ShieldGlyph, { className: "size-4 shrink-0 text-destructive" }),
7605
- /* @__PURE__ */ jsx37("span", { className: "min-w-0 flex-1 text-xs text-foreground", children: said.text }),
7606
- /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(XGlyph, {}), "aria-label": "Dismiss", onClick: onDismiss })
7938
+ return /* @__PURE__ */ jsxs36("div", { role: "status", className: "flex items-center gap-2 px-1", children: [
7939
+ said.tone === "success" ? /* @__PURE__ */ jsx38(CheckGlyph, { className: "size-4 shrink-0 text-primary" }) : /* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4 shrink-0 text-destructive" }),
7940
+ /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 text-xs text-foreground", children: said.text }),
7941
+ /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(XGlyph, {}), "aria-label": "Dismiss", onClick: onDismiss })
7607
7942
  ] });
7608
7943
  }
7609
7944
  function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFill, onSignIn }) {
7610
7945
  const confirmed = useConfirmed();
7611
7946
  const copy = useCopy();
7612
7947
  const notify = useNotify();
7613
- const [reading, setReading] = useState38(false);
7948
+ const [reading, setReading] = useState39(false);
7614
7949
  const usable = item?.capabilities.canUse ?? false;
7615
7950
  const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
7616
7951
  const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
@@ -7626,27 +7961,27 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7626
7961
  }
7627
7962
  };
7628
7963
  const subtitle = [item ? loginSiteOf(item) || item.definitionLabel : "", tag].filter(Boolean).join(" \xB7 ");
7629
- return /* @__PURE__ */ jsxs35("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
7630
- /* @__PURE__ */ jsxs35("button", { type: "button", onClick: () => onOpen(itemId), className: "flex h-11 min-w-0 flex-1 items-center gap-3 rounded-lg px-2 text-left hover:bg-accent", children: [
7631
- /* @__PURE__ */ jsx37(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
7632
- /* @__PURE__ */ jsxs35("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7633
- /* @__PURE__ */ jsx37("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
7634
- subtitle ? /* @__PURE__ */ jsx37("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
7964
+ return /* @__PURE__ */ jsxs36("li", { className: "flex h-12 items-center gap-1 pl-1 pr-2", "data-item": itemId, children: [
7965
+ /* @__PURE__ */ jsxs36("button", { type: "button", onClick: () => onOpen(itemId), className: "flex h-11 min-w-0 flex-1 items-center gap-3 rounded-lg px-2 text-left hover:bg-accent", children: [
7966
+ /* @__PURE__ */ jsx38(ItemIcon, { definitionKey: item?.definitionKey ?? "website_login", family, site: item ? loginSiteOf(item) : "" }),
7967
+ /* @__PURE__ */ jsxs36("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
7968
+ /* @__PURE__ */ jsx38("span", { className: "truncate text-sm font-medium", children: item?.name ?? "Saved login" }),
7969
+ subtitle ? /* @__PURE__ */ jsx38("span", { className: "truncate text-xs text-muted-foreground", children: subtitle }) : null
7635
7970
  ] })
7636
7971
  ] }),
7637
- onFill ? /* @__PURE__ */ jsx37(Button32, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
7638
- user && item ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
7639
- secret && item ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
7640
- otp ? /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null,
7641
- onSignIn ? /* @__PURE__ */ jsxs35(DropdownMenu5, { children: [
7642
- /* @__PURE__ */ jsx37(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx37(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx37(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
7643
- /* @__PURE__ */ jsxs35(DropdownMenuContent5, { align: "end", children: [
7644
- /* @__PURE__ */ jsxs35(DropdownMenuItem4, { onSelect: onSignIn, children: [
7645
- /* @__PURE__ */ jsx37(ShieldGlyph, { className: "size-4" }),
7972
+ onFill ? /* @__PURE__ */ jsx38(Button33, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
7973
+ user && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
7974
+ secret && item ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
7975
+ otp ? /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null,
7976
+ onSignIn ? /* @__PURE__ */ jsxs36(DropdownMenu5, { children: [
7977
+ /* @__PURE__ */ jsx38(DropdownMenuTrigger5, { asChild: true, children: /* @__PURE__ */ jsx38(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx38(MoreGlyph, {}), "aria-label": "More", disabled: busy }) }),
7978
+ /* @__PURE__ */ jsxs36(DropdownMenuContent5, { align: "end", children: [
7979
+ /* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: onSignIn, children: [
7980
+ /* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4" }),
7646
7981
  "Sign me in"
7647
7982
  ] }),
7648
- /* @__PURE__ */ jsxs35(DropdownMenuItem4, { onSelect: () => onOpen(itemId), children: [
7649
- /* @__PURE__ */ jsx37(ListGlyph, { className: "size-4" }),
7983
+ /* @__PURE__ */ jsxs36(DropdownMenuItem5, { onSelect: () => onOpen(itemId), children: [
7984
+ /* @__PURE__ */ jsx38(ListGlyph, { className: "size-4" }),
7650
7985
  "Open item"
7651
7986
  ] })
7652
7987
  ] })
@@ -7655,11 +7990,12 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7655
7990
  }
7656
7991
 
7657
7992
  // src/Sidebar.tsx
7658
- import { useState as useState39 } from "react";
7993
+ import { useState as useState40 } from "react";
7659
7994
  import { cn as cn15, useLook as useLook2 } from "@ai-matrx/design-system";
7660
- import { Select as Select10 } from "@ai-matrx/design-system/controls";
7995
+ import { Select as Select11 } from "@ai-matrx/design-system/controls";
7661
7996
  import { GlobeIcon as GlobeIcon5 } from "@ai-matrx/design-system/icons";
7662
- import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
7997
+ import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
7998
+ var AUTHENTICATOR_LABEL = "Authenticator";
7663
7999
  function vaultChoices(items, organizations, current) {
7664
8000
  const n = (f) => items.filter(f).length;
7665
8001
  const shared = n((i) => i.owner.kind === "shared");
@@ -7672,7 +8008,7 @@ function vaultChoices(items, organizations, current) {
7672
8008
  ];
7673
8009
  }
7674
8010
  function VaultSelect({ value, choices, onChange }) {
7675
- return /* @__PURE__ */ jsx38(Select10, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
8011
+ return /* @__PURE__ */ jsx39(Select11, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
7676
8012
  }
7677
8013
  var CATEGORY_GLYPHS = { logins: GlobeIcon5, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
7678
8014
  var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -7699,7 +8035,7 @@ function buildViews(items, definitions, favoriteIds2, recentIds2) {
7699
8035
  function viewLabel(view, views) {
7700
8036
  if (view === "favorites") return "Favorites";
7701
8037
  if (view === "recent") return "Recently opened";
7702
- if (view === "authenticator") return "One-time passwords";
8038
+ if (view === "authenticator") return AUTHENTICATOR_LABEL;
7703
8039
  if (view === "trash") return "Trash";
7704
8040
  if (view === "page") return "This page";
7705
8041
  return [...views.categories, ...views.tags].find((v) => v.view === view)?.label ?? "All items";
@@ -7710,7 +8046,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
7710
8046
  { value: "all", label: "Every category", meta: String(allCount) },
7711
8047
  ...hasFavorites ? [{ value: "favorites", label: "Favorites", meta: views.favorites === void 0 ? "" : String(views.favorites) }] : [],
7712
8048
  ...hasRecents ? [{ value: "recent", label: "Recently opened", meta: views.recent === void 0 ? "" : String(views.recent) }] : [],
7713
- { value: "authenticator", label: "One-time passwords", meta: String(views.authenticator) },
8049
+ { value: "authenticator", label: AUTHENTICATOR_LABEL, meta: String(views.authenticator) },
7714
8050
  ...views.categories.map((v) => ({ value: v.view, label: v.label, meta: String(v.count) })),
7715
8051
  ...views.tags.map((v) => ({ value: v.view, label: `#${v.label}`, meta: String(v.count) })),
7716
8052
  { value: "trash", label: "Trash", meta: String(deletedCount) }
@@ -7718,7 +8054,7 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
7718
8054
  }
7719
8055
  function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
7720
8056
  const desktop = useLook2() === "desktop";
7721
- return /* @__PURE__ */ jsxs36(
8057
+ return /* @__PURE__ */ jsxs37(
7722
8058
  "button",
7723
8059
  {
7724
8060
  type: "button",
@@ -7726,62 +8062,62 @@ function Entry({ on, glyph: Icon, label, count: count2, onClick }) {
7726
8062
  onClick,
7727
8063
  className: cn15("flex h-8 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm", on ? desktop ? "bg-sidebar-accent text-primary" : "bg-sidebar-accent font-medium text-sidebar-accent-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent"),
7728
8064
  children: [
7729
- /* @__PURE__ */ jsx38(Icon, { className: "size-4 shrink-0" }),
7730
- /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate", children: label }),
7731
- count2 !== void 0 ? /* @__PURE__ */ jsx38("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) : null
8065
+ /* @__PURE__ */ jsx39(Icon, { className: "size-4 shrink-0" }),
8066
+ /* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: label }),
8067
+ count2 !== void 0 ? /* @__PURE__ */ jsx39("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) : null
7732
8068
  ]
7733
8069
  }
7734
8070
  );
7735
8071
  }
7736
8072
  function Group({ title, children }) {
7737
- return /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-0.5", children: [
7738
- /* @__PURE__ */ jsx38("div", { className: "px-2.5 pb-1 text-xs font-medium text-muted-foreground", children: title }),
8073
+ return /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
8074
+ /* @__PURE__ */ jsx39("div", { className: "px-2.5 pb-1 text-xs font-medium text-muted-foreground", children: title }),
7739
8075
  children
7740
8076
  ] });
7741
8077
  }
7742
8078
  function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false }) {
7743
- const [tagsOpen, setTagsOpen] = useState39(view.startsWith("tag:"));
7744
- return /* @__PURE__ */ jsxs36("nav", { "aria-label": "Vault", className: "flex h-full min-h-0 flex-col border-r border-sidebar-border bg-sidebar-background text-sidebar-foreground", children: [
7745
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
7746
- /* @__PURE__ */ jsx38(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
7747
- /* @__PURE__ */ jsx38("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx38(VaultSelect, { value: vault, choices, onChange: onVault }) })
8079
+ const [tagsOpen, setTagsOpen] = useState40(view.startsWith("tag:"));
8080
+ return /* @__PURE__ */ jsxs37("nav", { "aria-label": "Vault", className: "flex h-full min-h-0 flex-col border-r border-sidebar-border bg-sidebar-background text-sidebar-foreground", children: [
8081
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
8082
+ /* @__PURE__ */ jsx39(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
8083
+ /* @__PURE__ */ jsx39("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx39(VaultSelect, { value: vault, choices, onChange: onVault }) })
7748
8084
  ] }),
7749
- /* @__PURE__ */ jsxs36("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
7750
- /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-0.5", children: [
7751
- hasPage ? /* @__PURE__ */ jsx38(Entry, { on: view === "page", glyph: GlobeIcon5, label: "This page", onClick: () => onView("page") }) : null,
7752
- /* @__PURE__ */ jsx38(Entry, { on: view === "all", glyph: GridGlyph, label: "All items", count: allCount, onClick: () => onView("all") }),
7753
- hasFavorites ? /* @__PURE__ */ jsx38(Entry, { on: view === "favorites", glyph: StarGlyph, label: "Favorites", count: views.favorites, onClick: () => onView("favorites") }) : null,
7754
- hasRecents ? /* @__PURE__ */ jsx38(Entry, { on: view === "recent", glyph: ClockGlyph, label: "Recently opened", count: views.recent, onClick: () => onView("recent") }) : null,
7755
- /* @__PURE__ */ jsx38(Entry, { on: view === "authenticator", glyph: LockGlyph, label: "One-time passwords", count: views.authenticator, onClick: () => onView("authenticator") })
8085
+ /* @__PURE__ */ jsxs37("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
8086
+ /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
8087
+ hasPage ? /* @__PURE__ */ jsx39(Entry, { on: view === "page", glyph: GlobeIcon5, label: "This page", onClick: () => onView("page") }) : null,
8088
+ /* @__PURE__ */ jsx39(Entry, { on: view === "all", glyph: GridGlyph, label: "All items", count: allCount, onClick: () => onView("all") }),
8089
+ hasFavorites ? /* @__PURE__ */ jsx39(Entry, { on: view === "favorites", glyph: StarGlyph, label: "Favorites", count: views.favorites, onClick: () => onView("favorites") }) : null,
8090
+ hasRecents ? /* @__PURE__ */ jsx39(Entry, { on: view === "recent", glyph: ClockGlyph, label: "Recently opened", count: views.recent, onClick: () => onView("recent") }) : null,
8091
+ /* @__PURE__ */ jsx39(Entry, { on: view === "authenticator", glyph: LockGlyph, label: AUTHENTICATOR_LABEL, count: views.authenticator, onClick: () => onView("authenticator") })
7756
8092
  ] }),
7757
- views.categories.length > 0 ? /* @__PURE__ */ jsx38(Group, { title: "Categories", children: views.categories.map((e) => /* @__PURE__ */ jsx38(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) }) : null,
7758
- views.tags.length > 0 ? /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-0.5", children: [
7759
- /* @__PURE__ */ jsxs36("button", { type: "button", "aria-expanded": tagsOpen, onClick: () => setTagsOpen((o) => !o), className: "flex h-7 items-center gap-1 rounded-md px-2.5 text-left text-xs font-medium text-muted-foreground hover:text-foreground", children: [
7760
- tagsOpen ? /* @__PURE__ */ jsx38(ChevronDownGlyph, { className: "size-3.5" }) : /* @__PURE__ */ jsx38(ChevronRightGlyph, { className: "size-3.5" }),
8093
+ views.categories.length > 0 ? /* @__PURE__ */ jsx39(Group, { title: "Categories", children: views.categories.map((e) => /* @__PURE__ */ jsx39(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) }) : null,
8094
+ views.tags.length > 0 ? /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5", children: [
8095
+ /* @__PURE__ */ jsxs37("button", { type: "button", "aria-expanded": tagsOpen, onClick: () => setTagsOpen((o) => !o), className: "flex h-7 items-center gap-1 rounded-md px-2.5 text-left text-xs font-medium text-muted-foreground hover:text-foreground", children: [
8096
+ tagsOpen ? /* @__PURE__ */ jsx39(ChevronDownGlyph, { className: "size-3.5" }) : /* @__PURE__ */ jsx39(ChevronRightGlyph, { className: "size-3.5" }),
7761
8097
  "Tags",
7762
- /* @__PURE__ */ jsx38("span", { className: "ml-auto tabular-nums", children: views.tags.length })
8098
+ /* @__PURE__ */ jsx39("span", { className: "ml-auto tabular-nums", children: views.tags.length })
7763
8099
  ] }),
7764
- tagsOpen ? views.tags.map((e) => /* @__PURE__ */ jsx38(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) : null
8100
+ tagsOpen ? views.tags.map((e) => /* @__PURE__ */ jsx39(Entry, { on: view === e.view, glyph: e.glyph, label: e.label, count: e.count, onClick: () => onView(e.view) }, e.view)) : null
7765
8101
  ] }) : null
7766
8102
  ] }),
7767
- /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-0.5 border-t border-sidebar-border p-2", children: [
7768
- /* @__PURE__ */ jsx38(Entry, { on: view === "trash", glyph: TrashGlyph, label: "Trash", count: deletedCount, onClick: () => onView("trash") }),
7769
- /* @__PURE__ */ jsx38(Entry, { on: false, glyph: ImportGlyph, label: "Import", onClick: () => onPanel("import") }),
7770
- /* @__PURE__ */ jsx38(Entry, { on: false, glyph: ExportGlyph, label: "Export", onClick: () => onPanel("export") }),
7771
- /* @__PURE__ */ jsx38(Entry, { on: false, glyph: SafeGlyph, label: "Backup", onClick: () => onPanel("backup") }),
7772
- /* @__PURE__ */ jsx38(Entry, { on: false, glyph: ShieldGlyph, label: "Browsers that fill", onClick: () => onPanel("devices") }),
7773
- hasNativeImport ? /* @__PURE__ */ jsx38(Entry, { on: false, glyph: ImportGlyph, label: "Import passkeys", onClick: () => onPanel("import-passkeys") }) : null,
7774
- nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs36("button", { type: "button", onClick: nativeProvider.openSetup, className: "flex h-8 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm hover:bg-sidebar-accent", children: [
7775
- /* @__PURE__ */ jsx38(ShieldGlyph, { className: "size-4 shrink-0" }),
7776
- /* @__PURE__ */ jsx38("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
7777
- /* @__PURE__ */ jsx38("span", { className: cn15("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
8103
+ /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-0.5 border-t border-sidebar-border p-2", children: [
8104
+ /* @__PURE__ */ jsx39(Entry, { on: view === "trash", glyph: TrashGlyph, label: "Trash", count: deletedCount, onClick: () => onView("trash") }),
8105
+ /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ImportGlyph, label: "Import", onClick: () => onPanel("import") }),
8106
+ /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ExportGlyph, label: "Export", onClick: () => onPanel("export") }),
8107
+ /* @__PURE__ */ jsx39(Entry, { on: false, glyph: SafeGlyph, label: "Backup", onClick: () => onPanel("backup") }),
8108
+ /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ShieldGlyph, label: "Browsers that fill", onClick: () => onPanel("devices") }),
8109
+ hasNativeImport ? /* @__PURE__ */ jsx39(Entry, { on: false, glyph: ImportGlyph, label: "Import passkeys", onClick: () => onPanel("import-passkeys") }) : null,
8110
+ nativeProvider && nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs37("button", { type: "button", onClick: nativeProvider.openSetup, className: "flex h-8 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm hover:bg-sidebar-accent", children: [
8111
+ /* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4 shrink-0" }),
8112
+ /* @__PURE__ */ jsx39("span", { className: "min-w-0 flex-1 truncate", children: "System AutoFill" }),
8113
+ /* @__PURE__ */ jsx39("span", { className: cn15("text-xs", nativeProvider.status === "ready" ? "text-success" : "text-warning"), children: nativeProvider.status === "ready" ? "On" : "Set up" })
7778
8114
  ] }) : null
7779
8115
  ] })
7780
8116
  ] });
7781
8117
  }
7782
8118
 
7783
8119
  // src/VaultApp.tsx
7784
- import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
8120
+ import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
7785
8121
  var FULL_AT = 1120;
7786
8122
  var SPLIT_AT = 640;
7787
8123
  var NO_HOST = {};
@@ -7800,7 +8136,7 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
7800
8136
  } : void 0;
7801
8137
  function ImportWithLimits(props) {
7802
8138
  const { knobs, ...rest } = props;
7803
- const [state, setState] = useState40(null);
8139
+ const [state, setState] = useState41(null);
7804
8140
  useEffect23(() => {
7805
8141
  if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
7806
8142
  knobs().then(
@@ -7814,18 +8150,18 @@ function ImportWithLimits(props) {
7814
8150
  (e) => setState({ error: e instanceof Error ? e.message : "The import settings could not be read." })
7815
8151
  );
7816
8152
  }, [knobs]);
7817
- if (state && "limits" in state) return /* @__PURE__ */ jsx39(ImportPanel, { ...rest, limits: state.limits });
7818
- return /* @__PURE__ */ jsx39(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx39(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
8153
+ if (state && "limits" in state) return /* @__PURE__ */ jsx40(ImportPanel, { ...rest, limits: state.limits });
8154
+ return /* @__PURE__ */ jsx40(Panel, { title: "Import", onClose: rest.onClose, children: /* @__PURE__ */ jsx40(Empty, { children: state ? state.error : "Reading this organization\u2019s import settings\u2026" }) });
7819
8155
  }
7820
8156
  function VaultApp(props) {
7821
8157
  const lock = props.host?.lock;
7822
8158
  const locked = useLocked(lock);
7823
8159
  const port = useMemo6(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
7824
- return /* @__PURE__ */ jsx39(LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ jsx39("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx39(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ jsx39(LockedScreen, { lock }) : /* @__PURE__ */ jsx39(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ jsx39(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ jsx39(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx39(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx39(Workspace, { ...props, port }) }) }) }) }) }) }) });
8160
+ return /* @__PURE__ */ jsx40(LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ jsx40(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ jsx40(LockedScreen, { lock }) : /* @__PURE__ */ jsx40(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ jsx40(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ jsx40(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ jsx40(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ jsx40(Workspace, { ...props, port }) }) }) }) }) }) }) });
7825
8161
  }
7826
8162
  function LockedScreen({ lock }) {
7827
- const [busy, setBusy] = useState40(false);
7828
- const [error, setError] = useState40(null);
8163
+ const [busy, setBusy] = useState41(false);
8164
+ const [error, setError] = useState41(null);
7829
8165
  const unlock = async () => {
7830
8166
  setBusy(true);
7831
8167
  setError(null);
@@ -7837,28 +8173,29 @@ function LockedScreen({ lock }) {
7837
8173
  setBusy(false);
7838
8174
  }
7839
8175
  };
7840
- return /* @__PURE__ */ jsxs37("div", { role: "region", "aria-label": "Vault locked", className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 p-6 text-center", children: [
7841
- /* @__PURE__ */ jsx39(LockGlyph, { className: "size-8 text-muted-foreground" }),
7842
- /* @__PURE__ */ jsx39("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
7843
- /* @__PURE__ */ jsx39(Button33, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
7844
- error ? /* @__PURE__ */ jsx39("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
8176
+ return /* @__PURE__ */ jsxs38("div", { role: "region", "aria-label": "Vault locked", className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 p-6 text-center", children: [
8177
+ /* @__PURE__ */ jsx40(LockGlyph, { className: "size-8 text-muted-foreground" }),
8178
+ /* @__PURE__ */ jsx40("div", { className: "text-base font-medium text-foreground", children: "Vault locked" }),
8179
+ /* @__PURE__ */ jsx40(Button34, { variant: "primary", disabled: busy, onClick: () => void unlock(), children: lock.unlockLabel ?? "Unlock" }),
8180
+ error ? /* @__PURE__ */ jsx40("div", { role: "alert", className: "max-w-sm text-sm text-destructive", children: error }) : null
7845
8181
  ] });
7846
8182
  }
7847
- function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange }) {
8183
+ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
7848
8184
  const rootRef = useRef19(null);
7849
8185
  const width = useElementWidth(rootRef);
7850
8186
  const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
7851
8187
  const notify = useNotify();
7852
- const [snap, setSnap] = useState40(null);
7853
- const [items, setItems] = useState40([]);
7854
- const [deleted, setDeleted] = useState40([]);
7855
- const [favorites, setFavorites] = useState40(null);
7856
- const [recents, setRecents] = useState40(null);
7857
- const [error, setError] = useState40(null);
7858
- const [inner, setInner] = useState40(DEFAULT_LOCATION);
8188
+ const [snap, setSnap] = useState41(null);
8189
+ const [items, setItems] = useState41([]);
8190
+ const [deleted, setDeleted] = useState41([]);
8191
+ const [favorites, setFavorites] = useState41(null);
8192
+ const [recents, setRecents] = useState41(null);
8193
+ const [error, setError] = useState41(null);
8194
+ const [inner, setInner] = useState41(DEFAULT_LOCATION);
7859
8195
  const loc = location ?? inner;
7860
8196
  const dirty = useRef19(false);
7861
- const [notice, setNotice] = useState40(null);
8197
+ const [notice, setNotice] = useState41(null);
8198
+ const [firstCode, setFirstCode] = useState41(null);
7862
8199
  const move = useCallback5(
7863
8200
  (next, how) => {
7864
8201
  if (!location) setInner(next);
@@ -7878,7 +8215,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7878
8215
  move(next, how);
7879
8216
  };
7880
8217
  if (leaving && dirty.current) {
7881
- void confirm13({ title: "Discard your changes?", description: "What you changed in this item is not saved.", confirmLabel: "Discard", cancelLabel: "Keep editing", variant: "destructive" }).then((ok) => ok && proceed());
8218
+ void confirm14({ title: "Discard your changes?", description: "What you changed in this item is not saved.", confirmLabel: "Discard", cancelLabel: "Keep editing", variant: "destructive" }).then((ok) => ok && proceed());
7882
8219
  return;
7883
8220
  }
7884
8221
  proceed();
@@ -7911,7 +8248,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7911
8248
  }, []);
7912
8249
  const knobsRef = useRef19(host.knobs);
7913
8250
  knobsRef.current = host.knobs;
7914
- const [signedOut, setSignedOut] = useState40(false);
8251
+ const [signedOut, setSignedOut] = useState41(false);
7915
8252
  const load = useCallback5(() => {
7916
8253
  setError(null);
7917
8254
  port.load().then((s) => {
@@ -7931,6 +8268,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7931
8268
  port.lists.recents?.list().then(setRecents, () => void 0);
7932
8269
  }, [port]);
7933
8270
  useEffect23(load, [load]);
8271
+ const inventoryRef = useRef19(onInventory);
8272
+ inventoryRef.current = onInventory;
8273
+ useEffect23(() => {
8274
+ if (snap) inventoryRef.current?.({ items, definitions: snap.definitions });
8275
+ }, [snap, items]);
7934
8276
  useEffect23(() => {
7935
8277
  if (!loc.itemId || !port.lists.recents) return;
7936
8278
  const id = loc.itemId;
@@ -7950,7 +8292,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7950
8292
  return inView(i, loc.view);
7951
8293
  });
7952
8294
  if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
7953
- return sortItems(filtered, loc.sort);
8295
+ return sortItems(filtered, loc.sort, recents);
7954
8296
  }, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
7955
8297
  const choices = useMemo6(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
7956
8298
  const matchingIds = useMemo6(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
@@ -7977,70 +8319,86 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7977
8319
  });
7978
8320
  };
7979
8321
  if (error) {
7980
- return /* @__PURE__ */ jsxs37("div", { ref: rootRef, role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm", children: [
7981
- /* @__PURE__ */ jsx39(SafeGlyph, { className: "size-8 text-muted-foreground" }),
7982
- /* @__PURE__ */ jsx39("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
7983
- /* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
7984
- /* @__PURE__ */ jsxs37("div", { className: "flex gap-2", children: [
7985
- signedOut && host.signIn ? /* @__PURE__ */ jsx39(Button33, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
7986
- /* @__PURE__ */ jsx39(Button33, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
8322
+ return /* @__PURE__ */ jsxs38("div", { ref: rootRef, role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm", children: [
8323
+ /* @__PURE__ */ jsx40(SafeGlyph, { className: "size-8 text-muted-foreground" }),
8324
+ /* @__PURE__ */ jsx40("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
8325
+ /* @__PURE__ */ jsx40("div", { className: "max-w-xs text-muted-foreground", children: signedOut ? "You\u2019ve been signed out." : plainLoadError(error) }),
8326
+ /* @__PURE__ */ jsxs38("div", { className: "flex gap-2", children: [
8327
+ signedOut && host.signIn ? /* @__PURE__ */ jsx40(Button34, { variant: "primary", onClick: host.signIn, children: "Sign in" }) : null,
8328
+ /* @__PURE__ */ jsx40(Button34, { variant: signedOut && host.signIn ? "outline" : "primary", onClick: load, children: "Try again" })
7987
8329
  ] })
7988
8330
  ] });
7989
8331
  }
7990
8332
  if (!snap) {
7991
- return /* @__PURE__ */ jsx39("div", { ref: rootRef, className: "flex h-full bg-background", "aria-busy": "true", "aria-label": "Opening the vault", children: /* @__PURE__ */ jsx39("div", { className: "flex w-full max-w-sm flex-col gap-1 p-3", children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxs37("div", { className: "flex h-12 items-center gap-3 px-2", children: [
7992
- /* @__PURE__ */ jsx39("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
7993
- /* @__PURE__ */ jsxs37("div", { className: "flex flex-1 flex-col gap-1.5", children: [
7994
- /* @__PURE__ */ jsx39("div", { className: "h-3 w-2/3 animate-pulse rounded bg-muted" }),
7995
- /* @__PURE__ */ jsx39("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-muted" })
8333
+ return /* @__PURE__ */ jsx40("div", { ref: rootRef, className: "flex h-full bg-background", "aria-busy": "true", "aria-label": "Opening the vault", children: /* @__PURE__ */ jsx40("div", { className: "flex w-full max-w-sm flex-col gap-1 p-3", children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxs38("div", { className: "flex h-12 items-center gap-3 px-2", children: [
8334
+ /* @__PURE__ */ jsx40("div", { className: "size-8 animate-pulse rounded-lg bg-muted" }),
8335
+ /* @__PURE__ */ jsxs38("div", { className: "flex flex-1 flex-col gap-1.5", children: [
8336
+ /* @__PURE__ */ jsx40("div", { className: "h-3 w-2/3 animate-pulse rounded bg-muted" }),
8337
+ /* @__PURE__ */ jsx40("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-muted" })
7996
8338
  ] })
7997
8339
  ] }, n)) }) });
7998
8340
  }
7999
8341
  const hasFavorites = port.lists.favorites !== void 0;
8000
8342
  const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
8001
- const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs37("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto] gap-2", children: [
8002
- /* @__PURE__ */ jsx39(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8003
- /* @__PURE__ */ jsx39(Select11, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" }),
8004
- /* @__PURE__ */ jsxs37(DropdownMenu6, { children: [
8005
- /* @__PURE__ */ jsx39(DropdownMenuTrigger6, { asChild: true, children: /* @__PURE__ */ jsx39(Button33, { variant: "quiet", icon: /* @__PURE__ */ jsx39(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
8006
- /* @__PURE__ */ jsxs37(DropdownMenuContent6, { align: "end", children: [
8007
- /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => go({ panel: "import" }), children: [
8008
- /* @__PURE__ */ jsx39(ImportGlyph, { className: "size-4" }),
8343
+ const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs38("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2", children: [
8344
+ /* @__PURE__ */ jsx40(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8345
+ /* @__PURE__ */ jsx40(Select12, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0), "aria-label": "Show" }),
8346
+ /* @__PURE__ */ jsx40(
8347
+ Button34,
8348
+ {
8349
+ variant: loc.view === "authenticator" ? "outline" : "quiet",
8350
+ icon: /* @__PURE__ */ jsx40(LockGlyph, {}),
8351
+ "aria-label": AUTHENTICATOR_LABEL,
8352
+ "aria-pressed": loc.view === "authenticator",
8353
+ title: AUTHENTICATOR_LABEL,
8354
+ onClick: () => go({ view: loc.view === "authenticator" ? "all" : "authenticator", itemId: null, mode: "view", panel: null }),
8355
+ children: mode === "split" ? AUTHENTICATOR_LABEL : null
8356
+ }
8357
+ ),
8358
+ /* @__PURE__ */ jsxs38(DropdownMenu6, { children: [
8359
+ /* @__PURE__ */ jsx40(DropdownMenuTrigger6, { asChild: true, children: /* @__PURE__ */ jsx40(Button34, { variant: "quiet", icon: /* @__PURE__ */ jsx40(MoreGlyph, {}), "aria-label": "Vault actions" }) }),
8360
+ /* @__PURE__ */ jsxs38(DropdownMenuContent6, { align: "end", children: [
8361
+ /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "import" }), children: [
8362
+ /* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
8009
8363
  "Import"
8010
8364
  ] }),
8011
- /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => go({ panel: "export" }), children: [
8012
- /* @__PURE__ */ jsx39(ExportGlyph, { className: "size-4" }),
8365
+ /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "export" }), children: [
8366
+ /* @__PURE__ */ jsx40(ExportGlyph, { className: "size-4" }),
8013
8367
  "Export"
8014
8368
  ] }),
8015
- /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => go({ panel: "backup" }), children: [
8016
- /* @__PURE__ */ jsx39(SafeGlyph, { className: "size-4" }),
8369
+ /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "backup" }), children: [
8370
+ /* @__PURE__ */ jsx40(SafeGlyph, { className: "size-4" }),
8017
8371
  "Backup"
8018
8372
  ] }),
8019
- /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => go({ panel: "devices" }), children: [
8020
- /* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4" }),
8373
+ /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "devices" }), children: [
8374
+ /* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
8021
8375
  "Browsers that fill"
8022
8376
  ] }),
8023
- host.nativeImport ? /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => go({ panel: "import-passkeys" }), children: [
8024
- /* @__PURE__ */ jsx39(ImportGlyph, { className: "size-4" }),
8377
+ host.nativeImport ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => go({ panel: "import-passkeys" }), children: [
8378
+ /* @__PURE__ */ jsx40(ImportGlyph, { className: "size-4" }),
8025
8379
  "Import passkeys"
8026
8380
  ] }) : null,
8027
- host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: host.nativeProvider.openSetup, children: [
8028
- /* @__PURE__ */ jsx39(ShieldGlyph, { className: "size-4" }),
8381
+ host.nativeProvider && host.nativeProvider.status !== "unavailable" ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: host.nativeProvider.openSetup, children: [
8382
+ /* @__PURE__ */ jsx40(ShieldGlyph, { className: "size-4" }),
8029
8383
  "System AutoFill"
8030
8384
  ] }) : null,
8031
- host.lock?.lock ? /* @__PURE__ */ jsxs37(DropdownMenuItem5, { onSelect: () => void host.lock?.lock?.(), children: [
8032
- /* @__PURE__ */ jsx39(LockGlyph, { className: "size-4" }),
8385
+ host.lock?.lock ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: () => void host.lock?.lock?.(), children: [
8386
+ /* @__PURE__ */ jsx40(LockGlyph, { className: "size-4" }),
8033
8387
  "Lock"
8388
+ ] }) : null,
8389
+ host.openWebVault ? /* @__PURE__ */ jsxs38(DropdownMenuItem6, { onSelect: host.openWebVault, children: [
8390
+ /* @__PURE__ */ jsx40(ExternalGlyph, { className: "size-4" }),
8391
+ "Open on the web"
8034
8392
  ] }) : null
8035
8393
  ] })
8036
8394
  ] })
8037
8395
  ] });
8038
- const viewHeader = /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-2", children: [
8396
+ const viewHeader = /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
8039
8397
  compactHeader,
8040
- /* @__PURE__ */ jsx39(SearchField4, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
8398
+ /* @__PURE__ */ jsx40(SearchField4, { value: loc.q, onChange: (e) => go({ q: e.target.value }, "replace"), placeholder: `Search ${viewLabel(loc.view, views)}`, "aria-label": `Search ${viewLabel(loc.view, views)}` })
8041
8399
  ] });
8042
8400
  const viewProps = { port, host, items: inThisVault, deleted, definitions, query: loc.q, onOpen: (id) => go({ view: "all", itemId: id, mode: "view", panel: null }), onChanged: load, header: viewHeader };
8043
- const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx39(
8401
+ const pageView = loc.view === "page" && host.page && !loc.q ? /* @__PURE__ */ jsx40(
8044
8402
  PageView,
8045
8403
  {
8046
8404
  port,
@@ -8058,8 +8416,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8058
8416
  ...compactHeader ? { header: compactHeader } : {}
8059
8417
  }
8060
8418
  ) : null;
8061
- const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx39(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx39(TrashView, { ...viewProps }) : null);
8062
- const list = specialView ?? /* @__PURE__ */ jsx39(
8419
+ const specialView = pageView ?? (loc.view === "authenticator" ? /* @__PURE__ */ jsx40(AuthenticatorView, { ...viewProps }) : loc.view === "trash" ? /* @__PURE__ */ jsx40(TrashView, { ...viewProps }) : null);
8420
+ const list = specialView ?? /* @__PURE__ */ jsx40(
8063
8421
  ItemList,
8064
8422
  {
8065
8423
  title,
@@ -8073,6 +8431,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8073
8431
  onQuery: (q) => go({ q }, "replace"),
8074
8432
  sort: loc.sort,
8075
8433
  onSort: (sort) => go({ sort }, "replace"),
8434
+ canSortViewed: port.lists.recents !== void 0,
8076
8435
  onNew: () => go({ itemId: null, mode: "new", kind: null, panel: null }),
8077
8436
  ...matchingIds ? { matchingIds } : {},
8078
8437
  ...compactHeader ? { header: compactHeader } : {}
@@ -8086,9 +8445,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8086
8445
  const onPanel = (panel2) => go({ panel: panel2 }, "push");
8087
8446
  let detail;
8088
8447
  if (loc.mode === "new" && !kindDefinition) {
8089
- detail = /* @__PURE__ */ jsx39(NewItemFlow, { definitions, url: loc.url, onUrl: (url) => go({ url }, "replace"), onChoose: (kind, _name, url) => go({ kind, url }, "push"), onCancel: () => go({ mode: "view", kind: null, url: "", itemId: null }) });
8448
+ detail = /* @__PURE__ */ jsx40(NewItemFlow, { definitions, url: loc.url, onUrl: (url) => go({ url }, "replace"), onChoose: (kind, _name, url) => go({ kind, url }, "push"), onCancel: () => go({ mode: "view", kind: null, url: "", itemId: null }) });
8090
8449
  } else if (loc.mode === "new" && kindDefinition) {
8091
- detail = /* @__PURE__ */ jsx39(
8450
+ detail = /* @__PURE__ */ jsx40(
8092
8451
  ItemPane,
8093
8452
  {
8094
8453
  port,
@@ -8101,9 +8460,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8101
8460
  seed: { name: guess?.name ?? "", url: guess?.url ?? loc.url.trim() },
8102
8461
  onBack: () => go({ kind: null }),
8103
8462
  onMode: () => void 0,
8104
- onSaved: (item, _wasNew, n) => {
8463
+ onSaved: (item, _wasNew, n, enrolled) => {
8105
8464
  replaceItem(item);
8106
8465
  dirty.current = false;
8466
+ if (enrolled) setFirstCode(item);
8107
8467
  move({ ...loc, itemId: item.id, mode: "view", kind: null, url: "", panel: null }, "replace");
8108
8468
  setNotice(n);
8109
8469
  notify("Saved");
@@ -8119,7 +8479,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8119
8479
  `new-${kindDefinition.key}`
8120
8480
  );
8121
8481
  } else if (selected) {
8122
- detail = /* @__PURE__ */ jsx39(
8482
+ detail = /* @__PURE__ */ jsx40(
8123
8483
  ItemPane,
8124
8484
  {
8125
8485
  port,
@@ -8132,9 +8492,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8132
8492
  onBack: back,
8133
8493
  onMode: (m) => go({ mode: m, panel: null }),
8134
8494
  notice,
8135
- onSaved: (item, _wasNew, n) => {
8495
+ onSaved: (item, _wasNew, n, enrolled) => {
8136
8496
  replaceItem(item);
8137
8497
  dirty.current = false;
8498
+ if (enrolled) setFirstCode(item);
8138
8499
  move({ ...loc, mode: "view" }, "replace");
8139
8500
  setNotice(n);
8140
8501
  notify("Saved");
@@ -8162,23 +8523,23 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8162
8523
  selected.id
8163
8524
  );
8164
8525
  } else if (loc.itemId) {
8165
- detail = /* @__PURE__ */ jsx39(Blank, { children: "This item is not in your vault, or you cannot see it." });
8526
+ detail = /* @__PURE__ */ jsx40(Blank, { children: "This item is not in your vault, or you cannot see it." });
8166
8527
  } else {
8167
- detail = /* @__PURE__ */ jsx39(Blank, { children: visible.length === 0 ? "" : "Select an item" });
8528
+ detail = /* @__PURE__ */ jsx40(Blank, { children: visible.length === 0 ? "" : "Select an item" });
8168
8529
  }
8169
8530
  const [panelName, panelArg] = (loc.panel ?? "").split(/:(.*)/s);
8170
8531
  const closePanel = () => go({ panel: null }, "push");
8171
8532
  const vaultPanelProps = { port, host, items, definitions, organizations: orgs, onClose: closePanel, onChanged: load };
8172
8533
  let panel = null;
8173
- if (panelName === "import") panel = /* @__PURE__ */ jsx39(ImportWithLimits, { ...vaultPanelProps, knobs: host.knobs });
8174
- else if (panelName === "devices") panel = /* @__PURE__ */ jsx39(DevicesPanel, { ...vaultPanelProps });
8175
- else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */ jsx39(ApprovePanel, { ...vaultPanelProps, ...approvalFromParams(panelArg, new URLSearchParams(globalThis.location?.search ?? "")) });
8176
- else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */ jsx39(NativeImportPanel, { ...vaultPanelProps, bridge: host.nativeImport, readLimits: port.native.limits, activeOrganizationId: orgs[0]?.id ?? null });
8177
- else if (panelName === "export") panel = /* @__PURE__ */ jsx39(ExportPanel, { ...vaultPanelProps });
8178
- else if (panelName === "backup") panel = /* @__PURE__ */ jsx39(BackupPanel, { ...vaultPanelProps });
8534
+ if (panelName === "import") panel = /* @__PURE__ */ jsx40(ImportWithLimits, { ...vaultPanelProps, knobs: host.knobs });
8535
+ else if (panelName === "devices") panel = /* @__PURE__ */ jsx40(DevicesPanel, { ...vaultPanelProps });
8536
+ else if (panelName === "approve" && panelArg) panel = /* @__PURE__ */ jsx40(ApprovePanel, { ...vaultPanelProps, ...approvalFromParams(panelArg, new URLSearchParams(globalThis.location?.search ?? "")) });
8537
+ else if (panelName === "import-passkeys" && host.nativeImport) panel = /* @__PURE__ */ jsx40(NativeImportPanel, { ...vaultPanelProps, bridge: host.nativeImport, readLimits: port.native.limits, activeOrganizationId: orgs[0]?.id ?? null });
8538
+ else if (panelName === "export") panel = /* @__PURE__ */ jsx40(ExportPanel, { ...vaultPanelProps });
8539
+ else if (panelName === "backup") panel = /* @__PURE__ */ jsx40(BackupPanel, { ...vaultPanelProps });
8179
8540
  else if (panelName && selected && ITEM_PANELS[panelName]) {
8180
8541
  const P = ITEM_PANELS[panelName];
8181
- panel = /* @__PURE__ */ jsx39(
8542
+ panel = /* @__PURE__ */ jsx40(
8182
8543
  P,
8183
8544
  {
8184
8545
  item: selected,
@@ -8201,17 +8562,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8201
8562
  }
8202
8563
  const grid = mode === "full" ? "grid-cols-[15rem_21rem_minmax(0,1fr)]" : mode === "split" ? "grid-cols-[19rem_minmax(0,1fr)]" : "grid-cols-1";
8203
8564
  const shown = panesShown(mode, specialView !== null, showingDetail);
8204
- return /* @__PURE__ */ jsxs37("div", { ref: rootRef, className: "flex h-full min-h-0 w-full flex-col bg-background text-foreground", children: [
8205
- snap.unavailable.length > 0 ? /* @__PURE__ */ jsxs37("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
8206
- /* @__PURE__ */ jsxs37("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
8565
+ return /* @__PURE__ */ jsxs38("div", { ref: rootRef, className: "flex h-full min-h-0 w-full flex-col bg-background text-foreground", children: [
8566
+ snap.unavailable.length > 0 ? /* @__PURE__ */ jsxs38("div", { role: "status", className: "flex items-center gap-3 border-b border-border bg-muted px-4 py-2 text-sm", children: [
8567
+ /* @__PURE__ */ jsxs38("span", { className: "min-w-0 flex-1 truncate text-warning", children: [
8207
8568
  "Couldn\u2019t load ",
8208
8569
  snap.unavailable.join(", "),
8209
8570
  ". Showing the rest."
8210
8571
  ] }),
8211
- /* @__PURE__ */ jsx39("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: load, children: "Try again" })
8572
+ /* @__PURE__ */ jsx40("button", { type: "button", className: "shrink-0 text-primary hover:underline", onClick: load, children: "Try again" })
8212
8573
  ] }) : null,
8213
- /* @__PURE__ */ jsxs37("div", { className: `grid min-h-0 w-full flex-1 ${grid} overflow-hidden`, children: [
8214
- mode === "full" ? /* @__PURE__ */ jsx39(
8574
+ /* @__PURE__ */ jsxs38("div", { className: `grid min-h-0 w-full flex-1 ${grid} overflow-hidden`, children: [
8575
+ mode === "full" ? /* @__PURE__ */ jsx40(
8215
8576
  VaultSidebar,
8216
8577
  {
8217
8578
  vault: loc.vault,
@@ -8230,9 +8591,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8230
8591
  hasPage: host.page !== void 0
8231
8592
  }
8232
8593
  ) : null,
8233
- shown.list ? /* @__PURE__ */ jsx39("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
8594
+ shown.list ? /* @__PURE__ */ jsx40("div", { className: specialView && mode !== "stack" ? "col-span-2 min-h-0" : "min-h-0", children: list }) : null,
8234
8595
  shown.detail ? detail : null,
8235
- panel
8596
+ panel,
8597
+ firstCode ? /* @__PURE__ */ jsx40(FirstCodePanel, { port, item: firstCode, onClose: () => setFirstCode(null), onDone: () => setFirstCode(null) }) : null
8236
8598
  ] })
8237
8599
  ] });
8238
8600
  }
@@ -8240,8 +8602,8 @@ function plainLoadError(message2) {
8240
8602
  return /load failed|failed to fetch|network|timed? ?out/i.test(message2) ? "The connection dropped. Check you\u2019re online, then try again." : message2;
8241
8603
  }
8242
8604
  function Blank({ children }) {
8243
- return /* @__PURE__ */ jsxs37("div", { className: "flex h-full flex-col items-center justify-center gap-3 bg-background text-sm text-muted-foreground", children: [
8244
- /* @__PURE__ */ jsx39(SafeGlyph, { className: "size-10 text-disabled-foreground" }),
8605
+ return /* @__PURE__ */ jsxs38("div", { className: "flex h-full flex-col items-center justify-center gap-3 bg-background text-sm text-muted-foreground", children: [
8606
+ /* @__PURE__ */ jsx40(SafeGlyph, { className: "size-10 text-disabled-foreground" }),
8245
8607
  children
8246
8608
  ] });
8247
8609
  }
@@ -8611,6 +8973,20 @@ function createListsPort(ctx, door) {
8611
8973
 
8612
8974
  // src/sharing/api.ts
8613
8975
  import * as account6 from "@ai-matrx/api/account";
8976
+
8977
+ // src/secret-field-in.ts
8978
+ function secretFieldIn(s) {
8979
+ const envKey = s.envKey?.trim() || null;
8980
+ return {
8981
+ field_key: fieldKeyOf(s.label),
8982
+ value: s.value,
8983
+ handling: s.handling ?? "revealable",
8984
+ ...envKey ? { env_key: envKey } : {},
8985
+ ...envKey && s.injectIntoSandbox ? { inject_into_sandbox: true } : {}
8986
+ };
8987
+ }
8988
+
8989
+ // src/sharing/api.ts
8614
8990
  function grantOf(w) {
8615
8991
  const org = Boolean(w.organization_id);
8616
8992
  return {
@@ -8710,7 +9086,7 @@ function createSharingPort(ctx, options = {}) {
8710
9086
  non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
8711
9087
  fields: [
8712
9088
  ...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
8713
- ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map((s) => ({ field_key: fieldKeyOf(s.label), value: s.value, handling: "revealable" }))
9089
+ ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn)
8714
9090
  ]
8715
9091
  }
8716
9092
  });
@@ -8996,14 +9372,16 @@ function createApiVaultPort(api, options = {}) {
8996
9372
  login_urls: draft.loginUrls,
8997
9373
  // A login a person saves with its website is offered on that website (the server's own
8998
9374
  // default is off, which made "Save a login" on a page answer "No saved login" there).
8999
- ...draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
9375
+ ...draft.browser ? { uri_match_mode: draft.browser.uriMatchMode, browser_fill_enabled: draft.browser.browserFillEnabled } : draft.loginUrls.length > 0 ? { browser_fill_enabled: true } : {},
9000
9376
  notes: draft.notes || null,
9001
9377
  principal: organizationId ? { type: "organization", organization_id: organizationId } : { type: "user" },
9002
9378
  initiation: "user",
9003
9379
  non_secret_fields: [...meta.map((f) => ({ key: f.key, label: f.label, value: draft.values[f.key] ?? "" })), ...draft.custom.filter((c) => c.label.trim() !== "").map((c) => ({ key: c.key || fieldKeyOf(c.label), label: c.label, value: c.value }))],
9004
9380
  fields: [
9005
9381
  ...encrypted.map((f) => ({ field_key: f.key, value: draft.values[f.key] ?? "", handling: f.handling })),
9006
- ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map((s) => ({ field_key: fieldKeyOf(s.label), value: s.value, handling: "revealable" }))
9382
+ ...draft.secrets.filter((s) => s.label.trim() !== "" && s.value !== "").map(secretFieldIn),
9383
+ // Backup codes on a type that does not declare them (a website login): their own encrypted field.
9384
+ ...!declared.some((f) => f.key === RECOVERY_CODES_KEY) && (draft.values[RECOVERY_CODES_KEY] ?? "").trim() !== "" ? [{ field_key: RECOVERY_CODES_KEY, value: parseRecoveryCodes(draft.values[RECOVERY_CODES_KEY] ?? "").join("\n"), handling: "revealable", description: "One-time account recovery codes" }] : []
9007
9385
  ]
9008
9386
  }
9009
9387
  }, organizationId ? { organizationId } : void 0);
@@ -9041,7 +9419,7 @@ function createApiVaultPort(api, options = {}) {
9041
9419
  }
9042
9420
  for (const s of draft.secrets) {
9043
9421
  if (s.label.trim() === "" || s.value === "") continue;
9044
- await account9.addField(api, { path: { item_id: item.id }, body: { field_key: fieldKeyOf(s.label), value: s.value, handling: "revealable" } }, opts);
9422
+ await account9.addField(api, { path: { item_id: item.id }, body: secretFieldIn(s) }, opts);
9045
9423
  }
9046
9424
  for (const id of draft.removed) await account9.deleteField(api, { path: { item_id: item.id, field_id: id } }, opts);
9047
9425
  return { item: await refetch(item.id, item.owner), notice: null };
@@ -9066,6 +9444,44 @@ function createVaultKnobs(client, address) {
9066
9444
  return snap.resolved;
9067
9445
  };
9068
9446
  }
9447
+
9448
+ // src/agent-context.ts
9449
+ var hostOf = (url) => {
9450
+ try {
9451
+ return new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`).host || null;
9452
+ } catch {
9453
+ return null;
9454
+ }
9455
+ };
9456
+ function providerOf(item, definitions) {
9457
+ return definitions.find((d) => d.key === item.definitionKey)?.providerKey ?? null;
9458
+ }
9459
+ function vaultItemFacts(item, definitions) {
9460
+ const provider = providerOf(item, definitions);
9461
+ const hosts = item.loginUrls.map(hostOf).filter((h) => Boolean(h));
9462
+ const keys = item.fields.map((f) => f.key).filter((k) => !isAuthenticatorStorage(k));
9463
+ return [
9464
+ `Name: ${item.name}`,
9465
+ ...item.definitionLabel ? [`Type: ${item.definitionLabel}`] : [],
9466
+ ...provider ? [`Provider: ${provider}`] : [],
9467
+ ...hosts.length ? [`Sites: ${hosts.join(", ")}`] : [],
9468
+ `Owner: ${item.owner.label}`,
9469
+ `Status: ${item.turnedOff ? "turned off" : "active"}`,
9470
+ ...item.accessMode ? [`Access: ${item.accessMode}`] : [],
9471
+ ...item.tags.length ? [`Tags: ${item.tags.join(", ")}`] : [],
9472
+ ...keys.length ? [`Fields: ${keys.join(", ")}`] : [],
9473
+ ...item.authenticator ? ["Has a one-time password"] : []
9474
+ ];
9475
+ }
9476
+ function vaultInventoryScope(inventory, clicked = null) {
9477
+ const { items, definitions } = inventory;
9478
+ const providers = [...new Set(items.map((i) => providerOf(i, definitions)).filter((p) => Boolean(p)))];
9479
+ const content = clicked ? vaultItemFacts(clicked, definitions) : [`Vault \u2014 ${items.length} ${items.length === 1 ? "item" : "items"}`, ...items.map((i) => `\u2022 ${i.name}${i.definitionLabel ? ` \u2014 ${i.definitionLabel}` : ""}`)];
9480
+ return { content: content.join("\n"), credential_count: items.length, credential_labels: items.map((i) => i.name), credential_providers: providers };
9481
+ }
9482
+ function itemIdAt(target) {
9483
+ return target?.closest("[data-item]")?.getAttribute("data-item") ?? null;
9484
+ }
9069
9485
  export {
9070
9486
  CATEGORIES,
9071
9487
  CONFIRM_RETURN_KEY,
@@ -9084,15 +9500,19 @@ export {
9084
9500
  guardPort,
9085
9501
  inferFromUrl,
9086
9502
  isHiddenItem,
9503
+ itemIdAt,
9087
9504
  locationFromParams,
9088
9505
  locationToParams,
9089
9506
  loginSiteOf,
9090
9507
  matchesQuery,
9091
9508
  needsRecentSignIn,
9092
9509
  parseDefinitions,
9510
+ providerOf,
9093
9511
  siteDomainOf,
9094
9512
  sortItems,
9095
9513
  useConfirmed,
9514
+ vaultInventoryScope,
9515
+ vaultItemFacts,
9096
9516
  wasCancelled
9097
9517
  };
9098
9518
  //# sourceMappingURL=index.js.map