@ai-matrx/vault 0.1.11 → 0.1.13

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
@@ -324,9 +324,20 @@ var FingerprintGlyph = glyph(/* @__PURE__ */ jsxs2(Fragment, { children: [
324
324
  var SendGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "M14.5 21.7a.5.5 0 0 0 .9 0L22 3a.5.5 0 0 0-.6-.6L2.3 9.1a.5.5 0 0 0 0 .9l7.9 3.2a2 2 0 0 1 1.1 1.1zM21.9 2.1 10.9 13.1" }), [1, 1]);
325
325
 
326
326
  // src/auth/identity.ts
327
+ var CONFIRM_RETURN_KEY = "matrx-vault:confirming-as";
328
+ var RETURN_WINDOW_MS = 15 * 6e4;
327
329
  var SAME_PERSON = "That signed in a different account. Use the account this vault belongs to.";
328
330
  function createSupabaseIdentity(auth, options = {}) {
329
331
  let me = null;
332
+ const now = options.now ?? Date.now;
333
+ const store = () => {
334
+ if (options.store) return options.store;
335
+ try {
336
+ return globalThis.sessionStorage ?? null;
337
+ } catch {
338
+ return null;
339
+ }
340
+ };
330
341
  const who = async () => {
331
342
  const { data } = await auth.getUser();
332
343
  if (!data.user) throw new Error("You are signed out. Sign in again.");
@@ -343,10 +354,35 @@ function createSupabaseIdentity(auth, options = {}) {
343
354
  return { email: u.email ?? null, providers: [...names].filter((p) => p !== "email" && p !== "phone"), hasPassword: names.has("email") };
344
355
  },
345
356
  async withProvider(provider) {
346
- await who();
357
+ const u = await who();
358
+ store()?.setItem(CONFIRM_RETURN_KEY, JSON.stringify({ id: u.id, email: u.email ?? null, at: now() }));
347
359
  const redirectTo = options.redirectTo?.() ?? globalThis.location?.href;
348
360
  const { error } = await auth.signInWithOAuth({ provider, ...redirectTo ? { options: { redirectTo } } : {} });
349
- if (error) throw new Error(error.message);
361
+ if (error) {
362
+ store()?.removeItem(CONFIRM_RETURN_KEY);
363
+ throw new Error(error.message);
364
+ }
365
+ },
366
+ async checkReturn() {
367
+ const s = store();
368
+ const raw = s?.getItem(CONFIRM_RETURN_KEY) ?? null;
369
+ if (!s || raw === null) return null;
370
+ s.removeItem(CONFIRM_RETURN_KEY);
371
+ let expected;
372
+ try {
373
+ expected = JSON.parse(raw);
374
+ } catch {
375
+ return null;
376
+ }
377
+ if (typeof expected.id !== "string" || typeof expected.at !== "number" || now() - expected.at > RETURN_WINDOW_MS) return null;
378
+ const { data } = await auth.getUser();
379
+ if (!data.user || data.user.id === expected.id) return null;
380
+ const email = typeof expected.email === "string" && expected.email ? expected.email : null;
381
+ const message2 = `That signed in a different account, so it was signed out here.${email ? ` Sign in again as ${email}.` : " Sign in again."}`;
382
+ me = null;
383
+ if (options.onDifferentPerson) await options.onDifferentPerson(message2);
384
+ else await auth.signOut?.({ scope: "local" });
385
+ return message2;
350
386
  },
351
387
  async withPassword(password) {
352
388
  const u = await who();
@@ -392,6 +428,18 @@ var providerLabel = (p) => PROVIDER_LABEL[p] ?? p.charAt(0).toUpperCase() + p.sl
392
428
  function IdentityGate({ identity, children }) {
393
429
  const [asking, setAsking] = useState2(false);
394
430
  const waiters = useRef2([]);
431
+ const [returnProblem, setReturnProblem] = useState2(null);
432
+ useEffect2(() => {
433
+ if (!identity?.checkReturn) return;
434
+ let live = true;
435
+ identity.checkReturn().then(
436
+ (problem) => live && problem && setReturnProblem(problem),
437
+ (e) => live && setReturnProblem(e instanceof Error ? e.message : "The account that came back could not be checked.")
438
+ );
439
+ return () => {
440
+ live = false;
441
+ };
442
+ }, [identity]);
395
443
  const confirmed = async (run) => {
396
444
  try {
397
445
  return await run();
@@ -412,7 +460,14 @@ function IdentityGate({ identity, children }) {
412
460
  };
413
461
  return /* @__PURE__ */ jsxs3(Ctx2.Provider, { value: confirmed, children: [
414
462
  children,
415
- identity ? /* @__PURE__ */ jsx3(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null
463
+ identity ? /* @__PURE__ */ jsx3(ConfirmIdentityDialog, { open: asking, identity, onDone: () => settle(true), onCancel: () => settle(false) }) : null,
464
+ /* @__PURE__ */ jsx3(Dialog, { open: returnProblem !== null, onOpenChange: (o) => o ? void 0 : setReturnProblem(null), children: /* @__PURE__ */ jsxs3(DialogContent, { size: "sm", children: [
465
+ /* @__PURE__ */ jsxs3(DialogHeader, { children: [
466
+ /* @__PURE__ */ jsx3(DialogTitle, { children: "Different account" }),
467
+ /* @__PURE__ */ jsx3(DialogDescription, { children: returnProblem })
468
+ ] }),
469
+ /* @__PURE__ */ jsx3("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx3(Button, { variant: "primary", onClick: () => setReturnProblem(null), children: "OK" }) })
470
+ ] }) })
416
471
  ] });
417
472
  }
418
473
  var wasCancelled = (e) => e instanceof Error && e.message === CANCELLED;
@@ -476,7 +531,7 @@ function ConfirmIdentityDialog({ open, identity, onDone, onCancel }) {
476
531
  e.preventDefault();
477
532
  if (password) void attempt(() => identity.withPassword(password));
478
533
  }, children: [
479
- /* @__PURE__ */ jsx3(Field, { className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "Your password", "aria-label": "Your password", value: password, onChange: (e) => setPassword(e.target.value) }),
534
+ /* @__PURE__ */ jsx3(Field, { className: "min-w-0 flex-1", type: "password", autoComplete: "current-password", placeholder: "Your password", "aria-label": "Your password", value: password, onChange: (e) => setPassword(e.target.value), autoFocus: true }),
480
535
  /* @__PURE__ */ jsx3(Button, { variant: "outline", type: "submit", disabled: busy || !password, children: "Confirm" })
481
536
  ] }) : null,
482
537
  account10?.email ? codeSent ? /* @__PURE__ */ jsxs3("form", { className: "flex gap-2", onSubmit: (e) => {
@@ -604,6 +659,12 @@ function Panel({ title, open = true, onClose, children, footer, size = "lg" }) {
604
659
  footer ? /* @__PURE__ */ jsx4(DialogFooter, { children: footer }) : null
605
660
  ] }) });
606
661
  }
662
+ function PanelFooter({ status, children }) {
663
+ return /* @__PURE__ */ jsxs4("div", { className: "flex w-full flex-wrap items-center justify-end gap-2", children: [
664
+ status ? /* @__PURE__ */ jsx4("div", { className: "min-w-0 flex-1 basis-full sm:basis-0", children: status }) : null,
665
+ children
666
+ ] });
667
+ }
607
668
  var DAY_FORMAT = { year: "numeric", month: "short", day: "numeric" };
608
669
 
609
670
  // src/FieldRows.tsx
@@ -614,7 +675,7 @@ function SecretText({ value, multiline }) {
614
675
  return /* @__PURE__ */ jsx5("span", { className: "break-all font-mono text-sm tracking-wide", children: [...value].map((ch, i) => /* @__PURE__ */ jsx5("span", { className: /[0-9]/.test(ch) ? "text-primary" : /[^A-Za-z0-9]/.test(ch) ? "text-warning" : void 0, children: ch }, i)) });
615
676
  }
616
677
  var quietError = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
617
- function SecretRow({ port, item, field, extra }) {
678
+ function SecretRow({ port, item, field, extra, onTurnOn }) {
618
679
  const confirmed = useConfirmed();
619
680
  const copyValue2 = useCopy();
620
681
  const secret = useTransientSecret();
@@ -623,7 +684,7 @@ function SecretRow({ port, item, field, extra }) {
623
684
  const [error, setError] = useState5(null);
624
685
  const sealed = field.handling === "sealed";
625
686
  const visible = field.handling === "visible";
626
- const off = field.active === false;
687
+ const off = field.active === false || item.turnedOff === true;
627
688
  const canSee = !sealed && !off && (visible ? item.capabilities.canUse : item.capabilities.canReveal);
628
689
  useEffect5(() => {
629
690
  if (!visible || !canSee) return;
@@ -668,10 +729,27 @@ function SecretRow({ port, item, field, extra }) {
668
729
  top: multiline && shown !== null,
669
730
  actions: /* @__PURE__ */ jsxs5(Fragment2, { children: [
670
731
  extra,
732
+ off && onTurnOn ? /* @__PURE__ */ jsx5(TurnOnButton, { label: field.label, onTurnOn }) : null,
671
733
  canSee && !visible ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: secret.value !== null ? /* @__PURE__ */ jsx5(EyeOffGlyph, {}) : /* @__PURE__ */ jsx5(EyeGlyph, {}), "aria-label": secret.value !== null ? `Hide ${field.label}` : `Show ${field.label}`, disabled: busy, onClick: () => void toggle2() }) : null,
672
734
  canSee ? /* @__PURE__ */ jsx5(Button2, { variant: "quiet", icon: /* @__PURE__ */ jsx5(CopyIcon, {}), "aria-label": `Copy ${field.label}`, disabled: busy, onClick: () => void copy() }) : null
673
735
  ] }),
674
- children: sealed ? /* @__PURE__ */ jsx5(Badge, { icon: /* @__PURE__ */ jsx5(LockGlyph, {}), children: "Sealed" }) : off ? /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: "Turned off" }) : error ? /* @__PURE__ */ jsx5("span", { className: "truncate text-destructive", title: error, children: error }) : shown !== null ? visible ? /* @__PURE__ */ jsx5("span", { className: cn3("block", multiline ? "whitespace-pre-wrap break-words" : "truncate"), children: shown || "\u2014" }) : /* @__PURE__ */ jsx5(SecretText, { value: shown, multiline }) : /* @__PURE__ */ jsx5("span", { className: cn3("block truncate text-muted-foreground", !visible && "tracking-widest"), children: visible ? "\u2026" : MASK })
736
+ children: sealed ? /* @__PURE__ */ jsx5(Badge, { icon: /* @__PURE__ */ jsx5(LockGlyph, {}), children: "Never shown" }) : off ? /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: "Turned off" }) : error ? /* @__PURE__ */ jsx5("span", { className: "truncate text-destructive", title: error, children: error }) : shown !== null ? visible ? /* @__PURE__ */ jsx5("span", { className: cn3("block", multiline ? "whitespace-pre-wrap break-words" : "truncate"), children: shown || "\u2014" }) : /* @__PURE__ */ jsx5(SecretText, { value: shown, multiline }) : /* @__PURE__ */ jsx5("span", { className: cn3("block truncate text-muted-foreground", !visible && "tracking-widest"), children: visible ? "\u2026" : MASK })
737
+ }
738
+ );
739
+ }
740
+ function TurnOnButton({ label, onTurnOn }) {
741
+ const [busy, setBusy] = useState5(false);
742
+ return /* @__PURE__ */ jsx5(
743
+ Button2,
744
+ {
745
+ variant: "outline",
746
+ "aria-label": `Turn on ${label}`,
747
+ disabled: busy,
748
+ onClick: () => {
749
+ setBusy(true);
750
+ void onTurnOn().finally(() => setBusy(false));
751
+ },
752
+ children: "Turn on"
675
753
  }
676
754
  );
677
755
  }
@@ -810,14 +888,27 @@ function loginSiteOf(item) {
810
888
  return raw.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? "";
811
889
  }
812
890
  }
891
+ var TWO_PART_SUFFIX = /* @__PURE__ */ new Set(["co", "com", "org", "net", "gov", "edu", "ac", "ne", "or"]);
892
+ function siteDomainOf(host) {
893
+ const h = host.toLowerCase().replace(/\.$/, "");
894
+ if (!h || /^[\d.]+$/.test(h) || h.includes(":")) return h;
895
+ const labels = h.split(".").filter(Boolean);
896
+ if (labels.length <= 2) return labels.join(".");
897
+ const sld = labels[labels.length - 2] ?? "";
898
+ const tld = labels[labels.length - 1] ?? "";
899
+ const keep = TWO_PART_SUFFIX.has(sld) && tld.length <= 3 ? 3 : 2;
900
+ return labels.slice(-keep).join(".");
901
+ }
813
902
  function sortItems(items, sort) {
814
903
  const out = [...items];
815
904
  const byName = (a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
816
905
  if (sort === "name") return out.sort(byName);
817
- if (sort === "website") return out.sort((a, b) => {
818
- const x = loginSiteOf(a), y = loginSiteOf(b);
819
- return x && y ? x.localeCompare(y) || byName(a, b) : x ? -1 : y ? 1 : byName(a, b);
820
- });
906
+ if (sort === "website")
907
+ return out.sort((a, b) => {
908
+ const x = loginSiteOf(a), y = loginSiteOf(b);
909
+ if (!x || !y) return x ? -1 : y ? 1 : byName(a, b);
910
+ return siteDomainOf(x).localeCompare(siteDomainOf(y)) || x.localeCompare(y) || byName(a, b);
911
+ });
821
912
  if (sort === "updated") return out.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
822
913
  return out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
823
914
  }
@@ -1208,7 +1299,7 @@ import { useEffect as useEffect6, useRef as useRef4, useState as useState6 } fro
1208
1299
  import { Button as Button3 } from "@ai-matrx/design-system/controls";
1209
1300
  import { cn as cn4 } from "@ai-matrx/design-system";
1210
1301
  import { formatAbsoluteDate } from "@ai-matrx/kit/format";
1211
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1302
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1212
1303
  var PAGE = 50;
1213
1304
  var MAX = 500;
1214
1305
  function ActivityPanel({ item, port, onClose }) {
@@ -1237,7 +1328,10 @@ function ActivityPanel({ item, port, onClose }) {
1237
1328
  {
1238
1329
  title: "Activity",
1239
1330
  onClose,
1240
- footer: hasMore ? /* @__PURE__ */ jsx6(Button3, { variant: "outline", disabled: loading, onClick: () => setLimit((n) => Math.min(MAX, n * 2)), children: loading ? "Loading\u2026" : "Show more" }) : void 0,
1331
+ footer: /* @__PURE__ */ jsxs6(Fragment3, { children: [
1332
+ hasMore ? /* @__PURE__ */ jsx6(Button3, { variant: "outline", disabled: loading, onClick: () => setLimit((n) => Math.min(MAX, n * 2)), children: loading ? "Loading\u2026" : "Show more" }) : null,
1333
+ /* @__PURE__ */ jsx6(Button3, { variant: "primary", onClick: onClose, children: "Done" })
1334
+ ] }),
1241
1335
  children: [
1242
1336
  error ? /* @__PURE__ */ jsx6("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
1243
1337
  entries === null ? loading ? /* @__PURE__ */ jsx6(Empty, { children: "Reading activity\u2026" }) : null : entries.length === 0 ? /* @__PURE__ */ jsx6(Empty, { children: "Nothing has happened yet." }) : groupByDay(entries, now).map((day) => /* @__PURE__ */ jsx6(VaultSection, { title: day.label, children: collapseRuns(
@@ -1260,7 +1354,7 @@ function ActivityPanel({ item, port, onClose }) {
1260
1354
  }
1261
1355
 
1262
1356
  // src/activity/HistoryPanel.tsx
1263
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1357
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1264
1358
  var MASK2 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
1265
1359
  var messageOf = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
1266
1360
  function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
@@ -1320,8 +1414,11 @@ function ItemHistoryPanel({ item, port, arg, onClose, onChanged }) {
1320
1414
  {
1321
1415
  title: "Password history",
1322
1416
  onClose,
1323
- footer: page?.nextBefore ? /* @__PURE__ */ jsx7(Button4, { variant: "outline", disabled: more, onClick: () => void loadMore(), children: more ? "Loading\u2026" : "Show earlier" }) : void 0,
1324
- children: !eligible ? /* @__PURE__ */ jsx7(Empty, { children: "History is kept only for your own items." }) : loading && !page ? /* @__PURE__ */ jsx7(Empty, { children: "Reading history\u2026" }) : /* @__PURE__ */ jsxs7(Fragment3, { children: [
1417
+ footer: /* @__PURE__ */ jsxs7(Fragment4, { children: [
1418
+ page?.nextBefore ? /* @__PURE__ */ jsx7(Button4, { variant: "outline", disabled: more, onClick: () => void loadMore(), children: more ? "Loading\u2026" : "Show earlier" }) : null,
1419
+ /* @__PURE__ */ jsx7(Button4, { variant: "primary", onClick: onClose, children: "Done" })
1420
+ ] }),
1421
+ children: !eligible ? /* @__PURE__ */ jsx7(Empty, { children: "History is kept only for your own items." }) : loading && !page ? /* @__PURE__ */ jsx7(Empty, { children: "Reading history\u2026" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
1325
1422
  error ? /* @__PURE__ */ jsx7("p", { role: "alert", className: "px-1 text-sm text-destructive", children: error }) : null,
1326
1423
  notice ? /* @__PURE__ */ jsx7("p", { role: "status", className: "px-1 text-sm text-success", children: notice }) : null,
1327
1424
  page && groups.length === 0 ? /* @__PURE__ */ jsx7(Empty, { children: "No earlier values yet." }) : null,
@@ -1389,7 +1486,7 @@ function HistoryRow({ item, port, page, entry, label, onRestored, onConflict, on
1389
1486
  VaultRow,
1390
1487
  {
1391
1488
  label: when,
1392
- actions: entry.available ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
1489
+ actions: entry.available ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
1393
1490
  /* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: secret.value !== null ? /* @__PURE__ */ jsx7(EyeOffGlyph, {}) : /* @__PURE__ */ jsx7(EyeGlyph, {}), "aria-label": secret.value !== null ? "Hide" : "Show", disabled: busy, onClick: () => void toggle2() }),
1394
1491
  /* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(CopyIcon2, {}), "aria-label": "Copy", disabled: busy, onClick: () => void copy() }),
1395
1492
  canRestore(page, entry) ? /* @__PURE__ */ jsx7(Button4, { variant: "quiet", icon: /* @__PURE__ */ jsx7(RestoreGlyph, {}), "aria-label": "Restore", disabled: busy, onClick: () => void restore() }) : null
@@ -1723,7 +1820,7 @@ function imageFrom(data) {
1723
1820
  }
1724
1821
 
1725
1822
  // src/authenticator/Setup.tsx
1726
- import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1823
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1727
1824
  function useCanScan() {
1728
1825
  const [ok, setOk] = useState10(false);
1729
1826
  useEffect10(() => {
@@ -1856,7 +1953,7 @@ function OtpSetupRow({ value, onChange, label = "One-time password", placeholder
1856
1953
  VaultRow,
1857
1954
  {
1858
1955
  label,
1859
- actions: /* @__PURE__ */ jsxs9(Fragment4, { children: [
1956
+ actions: /* @__PURE__ */ jsxs9(Fragment5, { children: [
1860
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() }),
1861
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
1862
1959
  ] }),
@@ -1925,13 +2022,14 @@ import { confirm as confirm2 } from "@ai-matrx/kit/confirm-opener";
1925
2022
 
1926
2023
  // src/authenticator/port.ts
1927
2024
  var MFA_METHOD_KEY = "mfa_method";
2025
+ var OTP_SEED_KEY = "totp_seed";
1928
2026
  function mfaMethodOf(item) {
1929
2027
  const v = item.custom.find((c) => c.key === MFA_METHOD_KEY)?.value;
1930
2028
  return v === "sms" ? "sms" : v ? "push_or_other" : null;
1931
2029
  }
1932
2030
 
1933
2031
  // src/authenticator/TotpRows.tsx
1934
- import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2032
+ import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1935
2033
  function otpActionError(e, what) {
1936
2034
  const status = e?.status;
1937
2035
  if (status === 404) return "There is no one-time password here.";
@@ -2006,7 +2104,7 @@ function TotpRow({ port, item, onChanged }) {
2006
2104
  VaultRow,
2007
2105
  {
2008
2106
  label: "One-time password",
2009
- actions: /* @__PURE__ */ jsxs10(Fragment5, { children: [
2107
+ actions: /* @__PURE__ */ jsxs10(Fragment6, { children: [
2010
2108
  a.enabled ? /* @__PURE__ */ jsx10(CopyCodeButton, { live, label: item.name }) : null,
2011
2109
  menu
2012
2110
  ] }),
@@ -2089,7 +2187,7 @@ function TwoFactorMethodRow({ port, item, onChanged }) {
2089
2187
  }
2090
2188
 
2091
2189
  // src/authenticator/AddOtpPanel.tsx
2092
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2190
+ import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2093
2191
  var NEW = "__new__";
2094
2192
  var LOGIN_KEYS = ["website_login", "username_password"];
2095
2193
  function normalizeWebsite(raw) {
@@ -2172,7 +2270,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2172
2270
  title: "Add one-time password",
2173
2271
  size: "md",
2174
2272
  onClose,
2175
- footer: /* @__PURE__ */ jsxs11(Fragment6, { children: [
2273
+ footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
2176
2274
  /* @__PURE__ */ jsx11(Button8, { variant: "quiet", onClick: onClose, disabled: busy, children: "Cancel" }),
2177
2275
  /* @__PURE__ */ jsx11(Button8, { variant: "primary", disabled: !ready, onClick: () => void save(), children: busy ? "Adding\u2026" : "Add" })
2178
2276
  ] }),
@@ -2212,7 +2310,7 @@ function AddOtpPanel({ port, items, definitions, itemId = null, onClose, onChang
2212
2310
  }
2213
2311
  }
2214
2312
  ) }),
2215
- isNew ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
2313
+ isNew ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
2216
2314
  /* @__PURE__ */ jsx11(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx11(
2217
2315
  Field4,
2218
2316
  {
@@ -2244,7 +2342,7 @@ function AddedPanel({ port, item, onClose, onDone }) {
2244
2342
  }
2245
2343
 
2246
2344
  // src/authenticator/AuthenticatorView.tsx
2247
- import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2345
+ import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2248
2346
  function matchesEntry(entry, q) {
2249
2347
  if (!entry || !q) return false;
2250
2348
  return [entry.issuer, entry.account].some((v) => v?.toLowerCase().includes(q));
@@ -2283,7 +2381,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2283
2381
  const total = items.filter((i) => i.authenticator && !i.deletion && !hidden.has(i.id)).length;
2284
2382
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
2285
2383
  return /* @__PURE__ */ jsxs12("section", { "aria-label": "One-time passwords", className: "flex h-full min-h-0 flex-col bg-background", children: [
2286
- header,
2384
+ header ? /* @__PURE__ */ jsx12("div", { className: "mx-auto w-full max-w-3xl px-3 pt-3 sm:px-4", children: header }) : null,
2287
2385
  /* @__PURE__ */ jsxs12("div", { className: "flex min-h-12 items-center justify-between gap-2 px-4 pb-1 pt-3", children: [
2288
2386
  /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 items-baseline gap-2", children: [
2289
2387
  /* @__PURE__ */ jsx12("h2", { className: "truncate text-sm font-semibold text-foreground", children: "One-time passwords" }),
@@ -2295,7 +2393,7 @@ function AuthenticatorView({ port, items, definitions, query, onOpen, onChanged,
2295
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" }) }),
2296
2394
  /* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: "No one-time passwords yet" }),
2297
2395
  /* @__PURE__ */ jsx12(Button9, { variant: "primary", icon: /* @__PURE__ */ jsx12(PlusGlyph, {}), onClick: () => setAdding(true), children: "Add one-time password" })
2298
- ] }) : 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, { ...groups.length > 1 ? { title: g.label } : {}, className: "[&>div]:px-1", children: g.items.map((item) => /* @__PURE__ */ jsx12(
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(
2299
2397
  OtpListRow,
2300
2398
  {
2301
2399
  port,
@@ -2392,7 +2490,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onRename, onChanged, on
2392
2490
  /* @__PURE__ */ jsx12(CopyIcon4, { className: "size-4" }),
2393
2491
  "Copy code"
2394
2492
  ] }) : null,
2395
- canManage ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
2493
+ canManage ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
2396
2494
  /* @__PURE__ */ jsxs12(DropdownMenuItem2, { onSelect: onRename, children: [
2397
2495
  /* @__PURE__ */ jsx12(PencilGlyph, { className: "size-4" }),
2398
2496
  "Rename"
@@ -2432,9 +2530,9 @@ function sandboxBlocker(envKeyDraft, savedEnvKey) {
2432
2530
  return null;
2433
2531
  }
2434
2532
  var HANDLING_WORDS = {
2435
- visible: { label: "Anyone", hint: "Anyone who can use it can show or copy it" },
2436
- revealable: { label: "On request", hint: "Showing or copying it needs reveal access" },
2437
- sealed: { label: "Sealed", hint: "No one can see it. Automation can still use it." }
2533
+ visible: { label: "Always shown", hint: "Anyone who can use it can show or copy it" },
2534
+ revealable: { label: "Hidden", hint: "Showing or copying it needs reveal access" },
2535
+ sealed: { label: "Never shown", hint: "No one can see it. Automation can still use it." }
2438
2536
  };
2439
2537
  function handlingChoices(current) {
2440
2538
  return current === "sealed" ? ["sealed"] : ["visible", "revealable", "sealed"];
@@ -2616,7 +2714,7 @@ function FieldSettings({ item, port, field, onClose, onChanged }) {
2616
2714
  }
2617
2715
  ) }),
2618
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 }) }) }),
2619
- /* @__PURE__ */ jsx13(VaultRow, { label: "Active", hint: quietHint(field.active ? "In use" : "Kept, but nothing uses it"), children: /* @__PURE__ */ jsx13(Switch, { "aria-label": "Active", checked: field.active, disabled: locked, onCheckedChange: (v) => void update("active", { active: 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 }) }) })
2620
2718
  ] }),
2621
2719
  error ? /* @__PURE__ */ jsx13(Problem, { children: error }) : null
2622
2720
  ] });
@@ -2684,7 +2782,7 @@ function ItemSettingsPanel({ item, port, onClose, onChanged, onPanel }) {
2684
2782
  f.envKey
2685
2783
  ] }) : null,
2686
2784
  f.injectIntoSandbox ? /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: " \xB7 Sandbox" }) : null,
2687
- !f.active ? /* @__PURE__ */ jsx13("span", { className: "text-disabled-foreground", children: " \xB7 Off" }) : null
2785
+ !f.active ? /* @__PURE__ */ jsx13("span", { className: "text-warning", children: " \xB7 Turned off" }) : null
2688
2786
  ] })
2689
2787
  },
2690
2788
  f.id
@@ -3080,7 +3178,7 @@ function startNewRestoreRun(preview) {
3080
3178
  import { useState as useState16 } from "react";
3081
3179
  import { Checkbox } from "@ai-matrx/design-system";
3082
3180
  import { Badge as Badge4, Button as Button12, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
3083
- import { Fragment as Fragment8, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
3181
+ import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
3084
3182
  function PickLine({ checked, onChange, disabled = false, title, detail, badge, tone }) {
3085
3183
  return /* @__PURE__ */ jsxs15("label", { className: "flex min-h-11 items-center gap-3 px-4 py-1", "data-clickable": disabled ? void 0 : "", children: [
3086
3184
  /* @__PURE__ */ jsx15(Checkbox, { checked, disabled, onCheckedChange: (v) => onChange(v === true), "aria-label": title }),
@@ -3092,7 +3190,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
3092
3190
  function Windowed({ items, size = 150, render }) {
3093
3191
  const [all, setAll] = useState16(false);
3094
3192
  const shown = all ? items : items.slice(0, size);
3095
- return /* @__PURE__ */ jsxs15(Fragment8, { children: [
3193
+ return /* @__PURE__ */ jsxs15(Fragment9, { children: [
3096
3194
  shown.map(render),
3097
3195
  items.length > shown.length ? /* @__PURE__ */ jsx15("div", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs15(Button12, { variant: "quiet", onClick: () => setAll(true), children: [
3098
3196
  "Show all ",
@@ -3113,7 +3211,7 @@ function ErrorLine({ message: message2 }) {
3113
3211
  var plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
3114
3212
 
3115
3213
  // src/io/BackupPanel.tsx
3116
- import { Fragment as Fragment9, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
3214
+ import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
3117
3215
  var RECORD_STATUS = {
3118
3216
  created: "Restored",
3119
3217
  replayed: "Already restored",
@@ -3241,13 +3339,13 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3241
3339
  const retryable = (result?.retryable_failure ?? 0) > 0;
3242
3340
  const mismatch = repeat !== "" && repeat !== passphrase;
3243
3341
  const names = new Map(restorePreview?.records.map((r) => [r.source_item_id, r.display_name]) ?? []);
3244
- const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
3342
+ const footer = mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3245
3343
  /* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: "Close" }),
3246
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: [
3247
3345
  "Review ",
3248
3346
  selected.size
3249
3347
  ] })
3250
- ] }) : /* @__PURE__ */ jsxs16(Fragment9, { children: [
3348
+ ] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
3251
3349
  /* @__PURE__ */ jsx16(Button13, { variant: "quiet", onClick: onClose, children: result && !retryable ? "Done" : "Close" }),
3252
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: [
3253
3351
  "Restore ",
@@ -3268,12 +3366,12 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3268
3366
  ]
3269
3367
  }
3270
3368
  ),
3271
- mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
3369
+ mode === "backup" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3272
3370
  /* @__PURE__ */ jsx16(
3273
3371
  VaultSection,
3274
3372
  {
3275
3373
  title: `${selected.size} of ${plural(items.length, "credential")}`,
3276
- actions: /* @__PURE__ */ jsxs16(Fragment9, { children: [
3374
+ actions: /* @__PURE__ */ jsxs16(Fragment10, { children: [
3277
3375
  /* @__PURE__ */ jsx16(Button13, { variant: "quiet", disabled: busy || items.length === 0, onClick: () => {
3278
3376
  setBackup(null);
3279
3377
  setSelected(new Set(items.map((i) => i.id)));
@@ -3286,7 +3384,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3286
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) })
3287
3385
  }
3288
3386
  ),
3289
- backup ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
3387
+ backup ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
3290
3388
  /* @__PURE__ */ jsx16(Summary, { value: backup }),
3291
3389
  /* @__PURE__ */ jsx16(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
3292
3390
  /* @__PURE__ */ jsxs16(VaultSection, { children: [
@@ -3294,7 +3392,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3294
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) }) })
3295
3393
  ] })
3296
3394
  ] }) : null
3297
- ] }) : /* @__PURE__ */ jsx16(Fragment9, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
3395
+ ] }) : /* @__PURE__ */ jsx16(Fragment10, { children: !restorePreview ? /* @__PURE__ */ jsxs16(VaultSection, { children: [
3298
3396
  /* @__PURE__ */ jsxs16(VaultRow, { label: "File", ...file ? { hint: file.name } : {}, children: [
3299
3397
  /* @__PURE__ */ jsx16(Button13, { variant: "outline", disabled: busy, onClick: () => fileInput.current?.click(), children: "Choose a backup" }),
3300
3398
  /* @__PURE__ */ jsx16(
@@ -3312,7 +3410,7 @@ function BackupPanel({ port, items, onClose, onChanged }) {
3312
3410
  )
3313
3411
  ] }),
3314
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) }) })
3315
- ] }) : /* @__PURE__ */ jsxs16(Fragment9, { children: [
3413
+ ] }) : /* @__PURE__ */ jsxs16(Fragment10, { children: [
3316
3414
  /* @__PURE__ */ jsx16(Summary, { value: restorePreview }),
3317
3415
  !result ? /* @__PURE__ */ jsx16(Omissions, { omissions: restorePreview.omissions, accepted, onAccepted: setAccepted, verb: "Restore" }) : null,
3318
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: [
@@ -3329,7 +3427,7 @@ import { useMemo, useState as useState18 } from "react";
3329
3427
  import { Button as Button14, Select as Select5 } from "@ai-matrx/design-system/controls";
3330
3428
  import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
3331
3429
  import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
3332
- import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
3430
+ import { Fragment as Fragment11, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
3333
3431
  var FORMATS = [
3334
3432
  { value: "matrx_login_csv_v1", label: "Matrx", hint: "Website logins, all common fields" },
3335
3433
  { value: "firefox_csv_v1", label: "Firefox", hint: "Address, username and password" },
@@ -3409,7 +3507,7 @@ function ExportPanel({ port, items, onClose }) {
3409
3507
  title: "Export logins",
3410
3508
  size: "lg",
3411
3509
  onClose,
3412
- footer: /* @__PURE__ */ jsxs17(Fragment10, { children: [
3510
+ footer: /* @__PURE__ */ jsxs17(Fragment11, { children: [
3413
3511
  /* @__PURE__ */ jsx17(Button14, { variant: "quiet", onClick: onClose, children: "Close" }),
3414
3512
  preview ? /* @__PURE__ */ jsxs17(Button14, { variant: "primary", icon: /* @__PURE__ */ jsx17(ExportGlyph, { className: "size-4" }), disabled: busy || eligible === 0, onClick: () => void download(), children: [
3415
3513
  "Download ",
@@ -3436,7 +3534,7 @@ function ExportPanel({ port, items, onClose }) {
3436
3534
  VaultSection,
3437
3535
  {
3438
3536
  title: `${selected.size} of ${plural(logins.length, "login")}`,
3439
- actions: /* @__PURE__ */ jsxs17(Fragment10, { children: [
3537
+ actions: /* @__PURE__ */ jsxs17(Fragment11, { children: [
3440
3538
  /* @__PURE__ */ jsx17(Button14, { variant: "quiet", disabled: busy || logins.length === 0, onClick: () => {
3441
3539
  changed();
3442
3540
  setSelected(new Set(logins.map((l) => l.id)));
@@ -4318,7 +4416,7 @@ async function parseImportFile(source, file, limits, signal) {
4318
4416
  }
4319
4417
 
4320
4418
  // src/io/ImportPanel.tsx
4321
- import { Fragment as Fragment11, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
4419
+ import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
4322
4420
  var ROLE_OPTIONS = [
4323
4421
  { value: "keep", label: "Keep encrypted" },
4324
4422
  { value: "title", label: "Name" },
@@ -4493,13 +4591,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4493
4591
  const help = EXPORT_HELP[source];
4494
4592
  const stage = done ? "done" : draft ? "review" : "choose";
4495
4593
  const busy = running !== null || reading;
4496
- const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment11, { children: [
4594
+ const footer = stage === "choose" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4497
4595
  /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: onClose, children: "Close" }),
4498
4596
  source === "env" ? /* @__PURE__ */ jsx18(Button15, { variant: "primary", icon: /* @__PURE__ */ jsx18(ImportGlyph, { className: "size-4" }), disabled: !envText.trim(), onClick: () => reviewEnv(envText), children: "Review" }) : null
4499
- ] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment11, { children: [
4597
+ ] }) : stage === "review" ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4500
4598
  running ? /* @__PURE__ */ jsx18(Button15, { variant: "outline", onClick: () => stop.current = true, children: "Stop" }) : /* @__PURE__ */ jsx18(Button15, { variant: "quiet", onClick: reset, children: "Back" }),
4501
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}` })
4502
- ] }) : /* @__PURE__ */ jsxs18(Fragment11, { children: [
4600
+ ] }) : /* @__PURE__ */ jsxs18(Fragment12, { children: [
4503
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,
4504
4602
  /* @__PURE__ */ jsx18(Button15, { variant: "primary", onClick: onClose, children: "Done" })
4505
4603
  ] });
@@ -4529,13 +4627,13 @@ function ImportPanel({ port, host, items, organizations, onClose, onChanged, lim
4529
4627
  ] }),
4530
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
4531
4629
  ] }) : null,
4532
- stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment11, { children: [
4630
+ stage === "review" && draft ? /* @__PURE__ */ jsxs18(Fragment12, { children: [
4533
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,
4534
4632
  /* @__PURE__ */ jsx18(
4535
4633
  VaultSection,
4536
4634
  {
4537
4635
  title: draft.kind === "env" ? plural(envKeys.length, "value") : summary(counts, lines.length),
4538
- actions: /* @__PURE__ */ jsxs18(Fragment11, { children: [
4636
+ actions: /* @__PURE__ */ jsxs18(Fragment12, { children: [
4539
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" }),
4540
4638
  /* @__PURE__ */ jsx18(Button15, { variant: "quiet", disabled: busy, onClick: () => setSelected(/* @__PURE__ */ new Set()), children: "None" })
4541
4639
  ] }),
@@ -4629,7 +4727,7 @@ import { jsx as jsx19 } from "react/jsx-runtime";
4629
4727
  function ItemIcon({ definitionKey, family, site, size = "md", inverted = false }) {
4630
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";
4631
4729
  const tone = inverted ? "bg-primary-foreground text-primary" : "bg-muted text-foreground";
4632
- const initial = site.replace(/^(app|my|login|accounts|signin|auth|console|portal|admin|www)\./, "").charAt(0).toUpperCase();
4730
+ const initial = siteDomainOf(site).charAt(0).toUpperCase();
4633
4731
  if (initial && /[A-Z0-9]/.test(initial)) {
4634
4732
  return /* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn8("flex shrink-0 items-center justify-center font-semibold", box, tone), children: initial });
4635
4733
  }
@@ -4652,13 +4750,13 @@ import { cn as cn9 } from "@ai-matrx/design-system";
4652
4750
  import { confirm as confirm6 } from "@ai-matrx/kit/confirm-opener";
4653
4751
  import { downloadFile as downloadFile3 } from "@ai-matrx/kit/download";
4654
4752
  import { DownloadIcon } from "@ai-matrx/design-system/icons";
4655
- import { Fragment as Fragment12, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
4753
+ import { Fragment as Fragment13, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
4656
4754
  var messageOf2 = (e, fallback) => wasCancelled(e) ? null : e instanceof Error ? e.message : fallback;
4657
4755
  var TOO_BIG = "Files over 25 MB can't be stored.";
4658
4756
  var PROTECTION = [
4659
4757
  { value: "visible", label: "Open", title: "Anyone who can use the item can download it" },
4660
4758
  { value: "revealable", label: "Protected", title: "Downloading needs a recent sign-in" },
4661
- { value: "sealed", label: "Sealed", title: "Only automation can use it, never a person" }
4759
+ { value: "sealed", label: "Never shown", title: "Only automation can use it, never a person" }
4662
4760
  ];
4663
4761
  function FilesSection({ item, port, editing, onChanged }) {
4664
4762
  const confirmed = useConfirmed();
@@ -4725,7 +4823,7 @@ function FilesSection({ item, port, editing, onChanged }) {
4725
4823
  {
4726
4824
  label: a.label,
4727
4825
  hint: a.description || void 0,
4728
- actions: a.handling === "sealed" ? /* @__PURE__ */ jsx20(Badge5, { icon: /* @__PURE__ */ jsx20(LockGlyph, {}), children: "Sealed" }) : canDownload(item, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: busy !== null, onClick: () => void download(a) }) : null,
4826
+ actions: a.handling === "sealed" ? /* @__PURE__ */ jsx20(Badge5, { icon: /* @__PURE__ */ jsx20(LockGlyph, {}), children: "Never shown" }) : canDownload(item, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: busy !== null, onClick: () => void download(a) }) : null,
4729
4827
  children: /* @__PURE__ */ jsx20(FileName, { file: a })
4730
4828
  },
4731
4829
  a.id
@@ -4749,13 +4847,13 @@ function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, o
4749
4847
  const yes = await confirm6({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
4750
4848
  if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
4751
4849
  }
4752
- return /* @__PURE__ */ jsxs19(Fragment12, { children: [
4850
+ return /* @__PURE__ */ jsxs19(Fragment13, { children: [
4753
4851
  /* @__PURE__ */ jsx20(
4754
4852
  VaultRow,
4755
4853
  {
4756
4854
  label: a.label,
4757
4855
  hint: a.description || void 0,
4758
- actions: /* @__PURE__ */ jsxs19(Fragment12, { children: [
4856
+ actions: /* @__PURE__ */ jsxs19(Fragment13, { children: [
4759
4857
  canDownload(it, a) ? /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(DownloadIcon, {}), "aria-label": `Download ${a.fileName}`, disabled: b !== null, onClick: onDownload }) : null,
4760
4858
  /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(PencilGlyph, {}), "aria-label": `Edit ${a.label}`, pressed: open, disabled: b !== null, onClick: () => setOpen((o) => !o) }),
4761
4859
  /* @__PURE__ */ jsx20(Button16, { variant: "quiet", icon: /* @__PURE__ */ jsx20(UploadGlyph, {}), "aria-label": `Replace ${a.fileName}`, disabled: b !== null, onClick: () => replacer.current?.click() }),
@@ -4809,7 +4907,7 @@ function NewFile({ file, busy, onAdd, onCancel }) {
4809
4907
  if (handling === "sealed" && !await confirmSeal(label)) return;
4810
4908
  await onAdd({ label: label.trim(), description: description.trim() || null, handling });
4811
4909
  }
4812
- return /* @__PURE__ */ jsxs19(Fragment12, { children: [
4910
+ return /* @__PURE__ */ jsxs19(Fragment13, { children: [
4813
4911
  /* @__PURE__ */ jsx20(VaultRow, { label: "New file", children: /* @__PURE__ */ jsxs19("span", { className: "flex min-w-0 items-center gap-2", children: [
4814
4912
  /* @__PURE__ */ jsx20("span", { className: "truncate", children: file.name }),
4815
4913
  /* @__PURE__ */ jsx20("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize2(file.size) })
@@ -4833,7 +4931,7 @@ function FileDetailsRows({ file, busy, onSave, onCancel }) {
4833
4931
  if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
4834
4932
  await onSave({ label: label.trim(), description: description.trim() || null, fileName: fileName.trim(), handling });
4835
4933
  }
4836
- return /* @__PURE__ */ jsxs19(Fragment12, { children: [
4934
+ return /* @__PURE__ */ jsxs19(Fragment13, { children: [
4837
4935
  /* @__PURE__ */ jsx20(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "Name", value: label, onChange: (e) => setLabel(e.target.value) }) }),
4838
4936
  /* @__PURE__ */ jsx20(VaultRow, { label: "Purpose", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "Purpose", placeholder: "What it is for", value: description, onChange: (e) => setDescription(e.target.value) }) }),
4839
4937
  /* @__PURE__ */ jsx20(VaultRow, { label: "File name", children: /* @__PURE__ */ jsx20(Field7, { "aria-label": "File name", value: fileName, onChange: (e) => setFileName(e.target.value) }) }),
@@ -4857,7 +4955,7 @@ function confirmSeal(label) {
4857
4955
  import { useState as useState21 } from "react";
4858
4956
  import { Badge as Badge6, Button as Button17, Textarea as Textarea3 } from "@ai-matrx/design-system/controls";
4859
4957
  import { CopyIcon as CopyIcon6 } from "@ai-matrx/design-system/icons";
4860
- import { Fragment as Fragment13, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
4958
+ import { Fragment as Fragment14, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
4861
4959
  var MASK4 = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
4862
4960
  var say2 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
4863
4961
  function RecoveryCodesRow({ item, field, port, onChanged }) {
@@ -4901,7 +4999,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
4901
4999
  {
4902
5000
  label: "Recovery codes",
4903
5001
  top: true,
4904
- actions: /* @__PURE__ */ jsxs20(Fragment13, { children: [
5002
+ actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
4905
5003
  /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CheckGlyph, {}), "aria-label": "Save codes", disabled: busy || !draft.trim(), onClick: () => void saveDraft() }),
4906
5004
  /* @__PURE__ */ jsx21(Button17, { variant: "quiet", removes: true, icon: /* @__PURE__ */ jsx21(XGlyph, {}), "aria-label": "Cancel", disabled: busy, onClick: () => {
4907
5005
  setDraft(null);
@@ -4943,11 +5041,11 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
4943
5041
  {
4944
5042
  label: "Recovery codes",
4945
5043
  top: codes !== null,
4946
- actions: /* @__PURE__ */ jsxs20(Fragment13, { children: [
5044
+ actions: /* @__PURE__ */ jsxs20(Fragment14, { children: [
4947
5045
  canSee ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: codes ? /* @__PURE__ */ jsx21(EyeOffGlyph, {}) : /* @__PURE__ */ jsx21(EyeGlyph, {}), "aria-label": codes ? "Hide codes" : "Show codes", disabled: busy, onClick: () => void toggle2() }) : null,
4948
5046
  canEdit && !sealed ? /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(PencilGlyph, {}), "aria-label": "Replace all codes", disabled: busy, onClick: () => setDraft("") }) : null
4949
5047
  ] }),
4950
- children: sealed ? /* @__PURE__ */ jsx21(Badge6, { icon: /* @__PURE__ */ jsx21(LockGlyph, {}), children: "Sealed" }) : codes ? /* @__PURE__ */ jsxs20("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
5048
+ children: sealed ? /* @__PURE__ */ jsx21(Badge6, { icon: /* @__PURE__ */ jsx21(LockGlyph, {}), children: "Never shown" }) : codes ? /* @__PURE__ */ jsxs20("ul", { className: "flex flex-col gap-0.5", "aria-label": "Recovery codes", children: [
4951
5049
  codes.map((code, i) => /* @__PURE__ */ jsxs20("li", { className: "flex min-h-7 items-center gap-1", children: [
4952
5050
  /* @__PURE__ */ jsx21("code", { className: "min-w-0 flex-1 break-all font-mono text-sm text-foreground", children: code }),
4953
5051
  /* @__PURE__ */ jsx21(Button17, { variant: "quiet", icon: /* @__PURE__ */ jsx21(CopyIcon6, {}), "aria-label": `Copy code ${i + 1}`, onClick: () => void copyValue2(code, "Recovery code") }),
@@ -5270,10 +5368,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5270
5368
  title: "Move or copy",
5271
5369
  size: "md",
5272
5370
  onClose,
5273
- footer: /* @__PURE__ */ jsxs22("div", { className: "flex w-full items-center gap-2", children: [
5274
- /* @__PURE__ */ jsx24(StatusLine, { error, notice }),
5275
- /* @__PURE__ */ jsx24(Button19, { variant: "outline", className: "ml-auto", onClick: onClose, children: "Close" })
5276
- ] }),
5371
+ footer: /* @__PURE__ */ jsx24(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx24(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx24(Button19, { variant: "primary", onClick: onClose, children: "Done" }) }),
5277
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: [
5278
5373
  canMove && moves.length > 0 ? /* @__PURE__ */ jsx24(
5279
5374
  VaultRow,
@@ -5305,7 +5400,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5305
5400
  }
5306
5401
 
5307
5402
  // src/sharing/SharePanel.tsx
5308
- import { Fragment as Fragment14, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5403
+ import { Fragment as Fragment15, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5309
5404
  function useGrants(port, item) {
5310
5405
  const [grants, setGrants] = useState25(null);
5311
5406
  const [loadError, setLoadError] = useState25(null);
@@ -5388,10 +5483,7 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5388
5483
  title: "Share",
5389
5484
  size: "md",
5390
5485
  onClose,
5391
- footer: /* @__PURE__ */ jsxs23("div", { className: "flex w-full items-center gap-2", children: [
5392
- /* @__PURE__ */ jsx25(StatusLine, { error, notice }),
5393
- /* @__PURE__ */ jsx25(Button20, { variant: "primary", className: "ml-auto", onClick: onClose, children: "Done" })
5394
- ] }),
5486
+ footer: /* @__PURE__ */ jsx25(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx25(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx25(Button20, { variant: "primary", onClick: onClose, children: "Done" }) }),
5395
5487
  children: [
5396
5488
  /* @__PURE__ */ jsxs23(VaultSection, { title: "Who has access", children: [
5397
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" }) }),
@@ -5456,7 +5548,7 @@ function IntoOrganization({ item, port, organizations, grants, onShared }) {
5456
5548
  const [level, setLevel] = useState25("use");
5457
5549
  const chosen = open.find((o) => o.id === target);
5458
5550
  if (item.owner.kind !== "me") return null;
5459
- return /* @__PURE__ */ jsx25(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs23(Fragment14, { children: [
5551
+ return /* @__PURE__ */ jsx25(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs23(Fragment15, { children: [
5460
5552
  /* @__PURE__ */ jsxs23("div", { className: "flex min-h-11 items-center gap-2 px-3 sm:px-4", children: [
5461
5553
  /* @__PURE__ */ jsx25(BuildingGlyph, { className: "size-4 shrink-0 text-muted-foreground" }),
5462
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 }))] }),
@@ -5542,7 +5634,7 @@ function SharingSummary({ item, port, className }) {
5542
5634
 
5543
5635
  // src/ItemPane.tsx
5544
5636
  import { formatAbsoluteDate as formatAbsoluteDate3 } from "@ai-matrx/kit/format";
5545
- import { Fragment as Fragment15, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
5637
+ import { Fragment as Fragment16, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
5546
5638
  var USERNAME_KEYS = /^(username|user_name|email|login|username_or_email|account_email)$/;
5547
5639
  function ItemPane(props) {
5548
5640
  const { port, item, definition, mode, host, organizations, defaultOwner, seed, onBack, onMode, onSaved, onDeleted, onDirty, onCancelNew, onPanel, onChanged, favorite, notice, refreshKey } = props;
@@ -5677,6 +5769,27 @@ function ItemPane(props) {
5677
5769
  if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "The value could not be read.");
5678
5770
  }
5679
5771
  }
5772
+ const offFields = item ? item.fields.filter((f) => !f.active) : [];
5773
+ const itemOff = item?.turnedOff === true;
5774
+ const seedField = item?.fields.find((f) => f.key === OTP_SEED_KEY) ?? null;
5775
+ const canTurnOn = Boolean(item && canEdit);
5776
+ async function turnOn(fields) {
5777
+ if (!item) return;
5778
+ setError(null);
5779
+ try {
5780
+ if (item.turnedOff) await confirmed(() => port.fields.updateItem(item, { active: true }));
5781
+ for (const f of fields) await confirmed(() => port.fields.updateField(item, f.id, { active: true }));
5782
+ if (fields.some((f) => f.key === OTP_SEED_KEY)) {
5783
+ const codes = await port.authenticator.get(item);
5784
+ if (codes && !codes.enabled) await confirmed(() => port.authenticator.setEnabled(item, true));
5785
+ }
5786
+ onChanged();
5787
+ } catch (e) {
5788
+ if (!wasCancelled(e)) setError(e instanceof Error ? e.message : "It could not be turned on.");
5789
+ onChanged();
5790
+ }
5791
+ }
5792
+ const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
5680
5793
  const declaredKeys = new Set(declared.map((f) => f.key));
5681
5794
  const extraFields = (item?.fields ?? []).filter((f) => !declaredKeys.has(f.key) && !draft.removed.includes(f.id) && !isAuthenticatorStorage(f.key));
5682
5795
  const metaValue = (key) => draft.values[key] ?? item?.custom.find((c) => c.key === key)?.value ?? "";
@@ -5685,6 +5798,10 @@ function ItemPane(props) {
5685
5798
  const isLogin = (item?.definitionKey ?? definition?.key) === "website_login" || (item?.definitionKey ?? definition?.key) === "username_password";
5686
5799
  const typeLabel = definition?.label ?? item?.definitionLabel ?? "";
5687
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;
5801
+ const sameNamed = (id) => {
5802
+ const name = organizations.find((o) => o.id === id)?.name.trim().toLowerCase();
5803
+ return Boolean(name) && organizations.filter((o) => o.name.trim().toLowerCase() === name).length > 1;
5804
+ };
5688
5805
  const tagsVisible = showTags || draft.tags.length > 0 || tagsText !== "";
5689
5806
  const descriptionVisible = showDescription || draft.description !== "";
5690
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: [
@@ -5752,7 +5869,7 @@ function ItemPane(props) {
5752
5869
  /* @__PURE__ */ jsx26(SettingsIcon, { className: "size-4" }),
5753
5870
  "Settings"
5754
5871
  ] }) : null,
5755
- canManage ? /* @__PURE__ */ jsxs24(Fragment15, { children: [
5872
+ canManage ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5756
5873
  /* @__PURE__ */ jsx26(DropdownMenuSeparator3, {}),
5757
5874
  /* @__PURE__ */ jsxs24(DropdownMenuItem3, { className: "text-destructive", disabled: busy, onSelect: () => void remove(), children: [
5758
5875
  /* @__PURE__ */ jsx26(TrashGlyph, { className: "size-4" }),
@@ -5768,7 +5885,11 @@ function ItemPane(props) {
5768
5885
  header,
5769
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,
5770
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,
5771
- /* @__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(Fragment15, { children: [
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
5891
+ ] }) : 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: [
5772
5893
  /* @__PURE__ */ jsxs24(VaultSection, { children: [
5773
5894
  mode === "new" ? /* @__PURE__ */ jsx26(VaultRow, { label: "Save to", children: /* @__PURE__ */ jsx26(
5774
5895
  OptionCombobox,
@@ -5780,16 +5901,16 @@ function ItemPane(props) {
5780
5901
  searchPlaceholder: "Find an organization",
5781
5902
  groups: [
5782
5903
  { heading: "Just you", options: ["me"] },
5783
- ...organizations.length > 0 ? [{ heading: "Organizations", options: organizations.map((o) => o.id) }] : [],
5904
+ ...organizations.length > 0 ? [{ heading: "Organizations", options: [...organizations].sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }) || a.id.localeCompare(b.id)).map((o) => o.id) }] : [],
5784
5905
  { heading: "Send", options: ["person"] }
5785
5906
  ],
5786
5907
  getLabel: (v) => v === "me" ? "Personal" : v === "person" ? "Someone else" : organizations.find((o) => o.id === v)?.name ?? v,
5787
- getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : null,
5908
+ getHint: (v) => v === "me" ? "Only you" : v === "person" ? "Sent by email" : sameNamed(v) ? `ID ${v.slice(0, 8)}` : null,
5788
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" })
5789
5910
  }
5790
5911
  ) }) : null,
5791
5912
  /* @__PURE__ */ jsx26(EditRow, { label: "Name", value: draft.name, onChange: (v) => patch({ name: v }), placeholder: "Name", autoFocus: mode === "new" }),
5792
- mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(Fragment15, { children: [
5913
+ mode === "new" && owner === "person" ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5793
5914
  /* @__PURE__ */ jsx26(EditRow, { label: "Their email", value: recipient, placeholder: "name@company.com", inputMode: "email", onChange: setRecipient }),
5794
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
5795
5916
  ] }) : null,
@@ -5808,7 +5929,7 @@ function ItemPane(props) {
5808
5929
  multiline: f.kind === "multiline",
5809
5930
  inputMode: f.kind === "url" ? "url" : USERNAME_KEYS.test(f.key) ? "email" : "text",
5810
5931
  onChange: (v) => setValue(f.key, v),
5811
- actions: /* @__PURE__ */ jsxs24(Fragment15, { children: [
5932
+ actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
5812
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,
5813
5934
  secretKind ? /* @__PURE__ */ jsx26(GenerateButton, { onUse: (v) => setValue(f.key, v) }) : null,
5814
5935
  existing ? /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${existing.id}`) }) : null
@@ -5827,7 +5948,7 @@ function ItemPane(props) {
5827
5948
  onChange: (v) => setValue(f.key, v),
5828
5949
  onRemove: () => patch({ removed: [...draft.removed, f.id] }),
5829
5950
  removeLabel: `Delete ${f.label}`,
5830
- actions: /* @__PURE__ */ jsxs24(Fragment15, { children: [
5951
+ actions: /* @__PURE__ */ jsxs24(Fragment16, { children: [
5831
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,
5832
5953
  /* @__PURE__ */ jsx26(Button21, { variant: "quiet", icon: /* @__PURE__ */ jsx26(SettingsIcon, {}), "aria-label": `${f.label} settings`, onClick: () => onPanel(`field:${f.id}`) })
5833
5954
  ] })
@@ -5859,7 +5980,7 @@ function ItemPane(props) {
5859
5980
  i
5860
5981
  )),
5861
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" }),
5862
- /* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator), item, port, onEnrolled: onChanged }),
5983
+ /* @__PURE__ */ jsx26(TotpEditRow, { value: draft.authenticator, onChange: (v) => patch({ authenticator: v }), hasExisting: Boolean(item?.authenticator || seedField), item, port, onEnrolled: onChanged }),
5863
5984
  item && isLogin && !item.authenticator ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
5864
5985
  ] }),
5865
5986
  /* @__PURE__ */ jsx26(VaultSection, { children: /* @__PURE__ */ jsx26(EditRow, { label: "Notes", value: draft.notes, multiline: true, placeholder: "Anything worth remembering", onChange: (v) => patch({ notes: v }) }) }),
@@ -5892,12 +6013,12 @@ function ItemPane(props) {
5892
6013
  ) : null,
5893
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}`)),
5894
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)),
5895
- !descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "Fields, tags", onAdd: null, children: "None" }) : null
6016
+ !descriptionVisible && !tagsVisible && draft.secrets.length === 0 && extraCustom.length === 0 ? /* @__PURE__ */ jsx26(AddRow, { label: "Tags", onAdd: () => setShowTags(true), children: "Add tags" }) : null
5896
6017
  ]
5897
6018
  }
5898
6019
  ),
5899
6020
  filesProps ? /* @__PURE__ */ jsx26(FilesSection, { ...filesProps, editing: true }) : null
5900
- ] }) : item ? /* @__PURE__ */ jsxs24(Fragment15, { children: [
6021
+ ] }) : item ? /* @__PURE__ */ jsxs24(Fragment16, { children: [
5901
6022
  /* @__PURE__ */ jsxs24(VaultSection, { children: [
5902
6023
  declared.map((f) => {
5903
6024
  if (f.storage === "metadata") {
@@ -5906,11 +6027,15 @@ function ItemPane(props) {
5906
6027
  }
5907
6028
  const field = item.fields.find((x) => x.key === f.key);
5908
6029
  if (isRecoveryCodesField(f)) return /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field, port, onChanged }, f.key);
5909
- return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field }, field.id) : null;
6030
+ return field ? /* @__PURE__ */ jsx26(SecretRow, { port, item, field, onTurnOn: turnOnOne(field) }, field.id) : null;
5910
6031
  }),
5911
- extraFields.map((f) => isRecoveryCodesField(f) ? /* @__PURE__ */ jsx26(RecoveryCodesRow, { item, field: f, port, onChanged }, f.id) : /* @__PURE__ */ jsx26(SecretRow, { port, item, field: f }, f.id)),
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)),
5912
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" }),
5913
- item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) : /* @__PURE__ */ jsx26(AddRow, { label: "One-time password", onAdd: canEdit ? () => onMode("edit") : null, children: "Set up" }),
6034
+ item.authenticator ? /* @__PURE__ */ jsx26(TotpRow, { port, item, onChanged }) : seedField && !seedField.active ? (
6035
+ // The secret is still there, only off: turning it on brings the codes back. Never "Set up",
6036
+ // 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" }),
5914
6039
  !item.authenticator && item.custom.some((c) => c.key === MFA_METHOD_KEY && c.value) ? /* @__PURE__ */ jsx26(TwoFactorMethodRow, { port, item, onChanged }) : null
5915
6040
  ] }),
5916
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" }) }),
@@ -5942,7 +6067,7 @@ function subtitleOf(item, withOwner) {
5942
6067
  const what = loginSiteOf(item) || item.definitionLabel;
5943
6068
  return withOwner ? `${what} \xB7 ${item.owner.label}` : what;
5944
6069
  }
5945
- function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header }) {
6070
+ function ItemList({ title, items, definitions, port, selectedId, onSelect, query, onQuery, sort, onSort, onNew, matchingIds, header, showOwner }) {
5946
6071
  const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
5947
6072
  const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
5948
6073
  const ordered = [...pinned, ...rest];
@@ -5961,7 +6086,7 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
5961
6086
  listRef.current?.querySelector(`[data-item="${next.id}"]`)?.scrollIntoView({ block: "nearest" });
5962
6087
  }
5963
6088
  };
5964
- const mixedOwners = new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
6089
+ const mixedOwners = showOwner ?? new Set(items.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
5965
6090
  const row = (i) => /* @__PURE__ */ jsx27(ListRow, { item: i, family: familyOf2(i.definitionKey), port, on: i.id === selectedId, onSelect, withOwner: mixedOwners }, i.id);
5966
6091
  const sortLabel = SORTS2.find((s) => s.value === sort)?.label ?? "Name";
5967
6092
  return /* @__PURE__ */ jsxs25("section", { "aria-label": title, className: "flex h-full min-h-0 flex-col border-r border-border bg-background", children: [
@@ -6114,7 +6239,7 @@ function refusalText(reason) {
6114
6239
  // src/lists/RestorePanel.tsx
6115
6240
  import { useEffect as useEffect18, useState as useState28 } from "react";
6116
6241
  import { Button as Button23 } from "@ai-matrx/design-system/controls";
6117
- import { Fragment as Fragment16, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
6242
+ import { Fragment as Fragment17, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
6118
6243
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
6119
6244
  function RestorePanel({ lists, item, restore, onClose }) {
6120
6245
  const [preview, setPreview] = useState28(null);
@@ -6159,7 +6284,7 @@ function RestorePanel({ lists, item, restore, onClose }) {
6159
6284
  title: `Restore "${item.name}"`,
6160
6285
  size: "md",
6161
6286
  onClose,
6162
- footer: /* @__PURE__ */ jsxs26(Fragment16, { children: [
6287
+ footer: /* @__PURE__ */ jsxs26(Fragment17, { children: [
6163
6288
  /* @__PURE__ */ jsx28(Button23, { variant: "quiet", onClick: onClose, children: refused ? "Close" : "Cancel" }),
6164
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" })
6165
6290
  ] }),
@@ -6179,6 +6304,9 @@ function RestorePanel({ lists, item, restore, onClose }) {
6179
6304
 
6180
6305
  // src/lists/TrashView.tsx
6181
6306
  import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6307
+ function trashLineOf(item) {
6308
+ return [item.definitionLabel || null, item.owner.label, item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null].filter(Boolean).join(" \xB7 ");
6309
+ }
6182
6310
  function TrashView({ port, deleted, query, header, onChanged }) {
6183
6311
  const confirmed = useConfirmed();
6184
6312
  const [busyId, setBusyId] = useState29(null);
@@ -6190,7 +6318,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6190
6318
  setMessage(null);
6191
6319
  try {
6192
6320
  const r = await confirmed(() => port.lists.restore(item, deletionId));
6193
- setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files. It is turned off.` });
6321
+ setMessage({ tone: "ok", text: r.alreadyRestored ? `"${item.name}" was already restored.` : `Restored "${item.name}" with ${r.restoredFields} fields and ${r.restoredAttachments} files. Turn its fields on from the item.` });
6194
6322
  onChanged();
6195
6323
  return r;
6196
6324
  } catch (e) {
@@ -6208,7 +6336,7 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6208
6336
  /* @__PURE__ */ jsxs27("div", { className: "flex min-h-12 items-center gap-3 px-3 py-1.5 sm:px-4", children: [
6209
6337
  /* @__PURE__ */ jsxs27("span", { className: "flex min-w-0 flex-1 flex-col leading-tight", children: [
6210
6338
  /* @__PURE__ */ jsx29("span", { className: "truncate text-sm text-foreground", children: item.name }),
6211
- /* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: [item.deletion?.deletedAt ? `Deleted ${formatAbsoluteDate4(item.deletion.deletedAt, DAY_FORMAT, "")}` : null, item.owner.kind !== "me" ? item.owner.label : null].filter(Boolean).join(" \xB7 ") })
6339
+ /* @__PURE__ */ jsx29("span", { className: "truncate text-xs text-muted-foreground", children: trashLineOf(item) })
6212
6340
  ] }),
6213
6341
  /* @__PURE__ */ jsx29(Button24, { variant: "outline", icon: /* @__PURE__ */ jsx29(RestoreGlyph, {}), disabled: busyId !== null || !item.deletion, onClick: () => setRestoring(item), children: "Restore" })
6214
6342
  ] }, item.id)
@@ -6499,10 +6627,9 @@ function SecureLinkPanel({ item, port, onClose }) {
6499
6627
  title: "Send securely",
6500
6628
  size: "md",
6501
6629
  onClose,
6502
- footer: /* @__PURE__ */ jsxs29("div", { className: "flex w-full flex-wrap items-center gap-2", children: [
6503
- /* @__PURE__ */ jsx31("div", { className: "w-full sm:w-auto sm:min-w-0 sm:flex-1", children: /* @__PURE__ */ jsx31(StatusLine, { error, notice }) }),
6630
+ footer: /* @__PURE__ */ jsxs29(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx31(StatusLine, { error, notice }) : null, children: [
6504
6631
  sameChannelSent && !error ? /* @__PURE__ */ jsx31(Badge8, { tone: "warning", children: "Both by email" }) : null,
6505
- /* @__PURE__ */ jsx31(Button26, { variant: "quiet", className: "ml-auto", onClick: onClose, children: "Close" }),
6632
+ /* @__PURE__ */ jsx31(Button26, { variant: "quiet", onClick: onClose, children: "Close" }),
6506
6633
  /* @__PURE__ */ jsx31(Button26, { variant: "primary", disabled: !canSend, onClick: () => void send(), children: busy === "send" ? "Sending\u2026" : "Send link" })
6507
6634
  ] }),
6508
6635
  children: [
@@ -6655,7 +6782,7 @@ function addPasskeyFailure(message2) {
6655
6782
  var isRevoked = (d) => d.revokedAt !== null;
6656
6783
 
6657
6784
  // src/devices/DevicesPanel.tsx
6658
- import { Fragment as Fragment17, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
6785
+ import { Fragment as Fragment18, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
6659
6786
  var messageOf3 = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
6660
6787
  function ErrorLine2({ text }) {
6661
6788
  return text ? /* @__PURE__ */ jsx32("p", { role: "alert", className: "px-1 text-sm text-destructive", children: text }) : null;
@@ -6786,7 +6913,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6786
6913
  };
6787
6914
  const canApprove = Boolean(key && passkeys && here && methods?.passkey && !approvedUntil);
6788
6915
  const title = isMac ? "Approve this Mac" : name ? `Approve ${name}` : "Approve this browser";
6789
- const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(Fragment17, { children: [
6916
+ const footer = approvedUntil ? /* @__PURE__ */ jsx32(Button27, { variant: "primary", onClick: onClose, children: "Done" }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
6790
6917
  /* @__PURE__ */ jsx32(Button27, { variant: "quiet", disabled: busy !== null, onClick: refuse, children: key ? "Refuse" : "Close" }),
6791
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
6792
6919
  ] });
@@ -6794,7 +6921,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
6794
6921
  "This link names no key. Start again from ",
6795
6922
  where,
6796
6923
  "."
6797
- ] }) }) : /* @__PURE__ */ jsxs30(Fragment17, { children: [
6924
+ ] }) }) : /* @__PURE__ */ jsxs30(Fragment18, { children: [
6798
6925
  /* @__PURE__ */ jsxs30(VaultSection, { title: "What is asking", children: [
6799
6926
  /* @__PURE__ */ jsx32(VaultRow, { label: "Asking", hint: "Approve only if you just asked", children: asker }),
6800
6927
  name ? /* @__PURE__ */ jsx32(VaultRow, { label: "Name", children: /* @__PURE__ */ jsx32("span", { className: "block truncate", children: name }) }) : null,
@@ -7094,7 +7221,7 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7094
7221
  }
7095
7222
 
7096
7223
  // src/native/NativeImportPanel.tsx
7097
- import { Fragment as Fragment18, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7224
+ import { Fragment as Fragment19, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7098
7225
  var TONE = {
7099
7226
  eligible: "success",
7100
7227
  committed: "success",
@@ -7138,16 +7265,16 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
7138
7265
  const yes = await confirm12({ title: `Add ${plural2(ready, "passkey")} to ${orgName}?`, description: "Passkeys already there are skipped.", confirmLabel: "Import" });
7139
7266
  if (yes) await flow.confirm();
7140
7267
  };
7141
- const footer = preview ? /* @__PURE__ */ jsxs31(Fragment18, { children: [
7268
+ const footer = preview ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
7142
7269
  /* @__PURE__ */ jsx33(Button28, { variant: "quiet", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel" }),
7143
7270
  /* @__PURE__ */ jsxs31(Button28, { variant: "primary", icon: /* @__PURE__ */ jsx33(ImportGlyph, { className: "size-4" }), disabled: busy || ready === 0, onClick: () => void importNow(), children: [
7144
7271
  "Import ",
7145
7272
  ready
7146
7273
  ] })
7147
- ] }) : status ? active ? /* @__PURE__ */ jsxs31(Fragment18, { children: [
7274
+ ] }) : status ? active ? /* @__PURE__ */ jsxs31(Fragment19, { children: [
7148
7275
  /* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.refresh(), children: "Refresh" }),
7149
7276
  /* @__PURE__ */ jsx33(Button28, { variant: "outline", disabled: busy, onClick: () => void flow.cancel(), children: "Cancel import" })
7150
- ] }) : /* @__PURE__ */ jsxs31(Fragment18, { children: [
7277
+ ] }) : /* @__PURE__ */ jsxs31(Fragment19, { children: [
7151
7278
  /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: flow.reset, children: "New file" }),
7152
7279
  /* @__PURE__ */ jsx33(Button28, { variant: "primary", onClick: onClose, children: "Done" })
7153
7280
  ] }) : /* @__PURE__ */ jsx33(Button28, { variant: "quiet", onClick: onClose, children: "Close" });
@@ -7186,7 +7313,7 @@ import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
7186
7313
  // src/extension/CaptureCard.tsx
7187
7314
  import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
7188
7315
  import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
7189
- import { Fragment as Fragment19, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7316
+ import { Fragment as Fragment20, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
7190
7317
  var SEARCH_FROM = 4;
7191
7318
  function CaptureCard({ capture, onChanged }) {
7192
7319
  const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
@@ -7219,7 +7346,7 @@ function CaptureCard({ capture, onChanged }) {
7219
7346
  ] }),
7220
7347
  /* @__PURE__ */ jsx34(Button29, { variant: "quiet", icon: /* @__PURE__ */ jsx34(XGlyph, {}), "aria-label": "Not now", disabled: busy, onClick: () => void decide({ action: "dismiss" }) })
7221
7348
  ] }),
7222
- prompt.unavailable ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground", children: "Save it by hand with Save a login." }) : /* @__PURE__ */ jsxs32(Fragment19, { children: [
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: [
7223
7350
  existing.length > 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1", children: [
7224
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,
7225
7352
  /* @__PURE__ */ jsxs32("ul", { className: "flex max-h-36 flex-col gap-px overflow-y-auto", children: [
@@ -7325,7 +7452,7 @@ import { useState as useState37 } from "react";
7325
7452
  import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
7326
7453
  import { Button as Button31 } from "@ai-matrx/design-system/controls";
7327
7454
  import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
7328
- import { Fragment as Fragment20, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
7455
+ import { Fragment as Fragment21, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
7329
7456
  var HOLD_MS = 6e4;
7330
7457
  function PageGenerator({ fields }) {
7331
7458
  const limits = useGeneratorLimitsSource();
@@ -7376,12 +7503,12 @@ function PageGenerator({ fields }) {
7376
7503
  }
7377
7504
  };
7378
7505
  const value = held.value;
7379
- return /* @__PURE__ */ jsxs34(Fragment20, { children: [
7506
+ return /* @__PURE__ */ jsxs34(Fragment21, { children: [
7380
7507
  /* @__PURE__ */ jsx36(
7381
7508
  VaultRow,
7382
7509
  {
7383
7510
  label: "New password",
7384
- actions: /* @__PURE__ */ jsxs34(Fragment20, { children: [
7511
+ actions: /* @__PURE__ */ jsxs34(Fragment21, { children: [
7385
7512
  value ? /* @__PURE__ */ jsx36(Button31, { variant: "quiet", icon: /* @__PURE__ */ jsx36(CopyIcon7, {}), "aria-label": "Copy password", onClick: () => void copy(value, "Password") }) : null,
7386
7513
  /* @__PURE__ */ jsxs34(Popover2, { open, onOpenChange: setOpen, children: [
7387
7514
  /* @__PURE__ */ jsx36(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsx36(Button31, { variant: "outline", icon: /* @__PURE__ */ jsx36(KeyGlyph, {}), disabled: busy, children: "Generate" }) }),
@@ -7758,8 +7885,33 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7758
7885
  },
7759
7886
  [loc, move]
7760
7887
  );
7888
+ const keyState = useRef19({ loc, go });
7889
+ keyState.current = { loc, go };
7890
+ useEffect23(() => {
7891
+ const onKey = (e) => {
7892
+ if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
7893
+ const root = rootRef.current;
7894
+ const at = document.activeElement;
7895
+ if (!root || at && at !== document.body && !root.contains(at)) return;
7896
+ if (at instanceof HTMLElement && (at.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(at.tagName))) return;
7897
+ if (document.querySelector('[role="dialog"], [role="alertdialog"]')) return;
7898
+ const { loc: here, go: to } = keyState.current;
7899
+ if (e.key === "/") {
7900
+ const search = root.querySelector('input[aria-label^="Search"]');
7901
+ if (!search) return;
7902
+ e.preventDefault();
7903
+ search.focus();
7904
+ } else if (e.key === "Escape" && here.itemId && here.mode === "view" && !here.panel) {
7905
+ e.preventDefault();
7906
+ to({ itemId: null, mode: "view", panel: null });
7907
+ }
7908
+ };
7909
+ document.addEventListener("keydown", onKey);
7910
+ return () => document.removeEventListener("keydown", onKey);
7911
+ }, []);
7761
7912
  const knobsRef = useRef19(host.knobs);
7762
7913
  knobsRef.current = host.knobs;
7914
+ const [signedOut, setSignedOut] = useState40(false);
7763
7915
  const load = useCallback5(() => {
7764
7916
  setError(null);
7765
7917
  port.load().then((s) => {
@@ -7770,7 +7922,10 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7770
7922
  (rows) => setDeleted([...s.deleted, ...rows.filter((r) => !s.deleted.some((d) => d.id === r.id))]),
7771
7923
  () => void 0
7772
7924
  );
7773
- }).catch((e) => setError(e instanceof Error ? e.message : "The vault could not be loaded."));
7925
+ }).catch((e) => {
7926
+ setSignedOut(e?.status === 401);
7927
+ setError(e instanceof Error ? e.message : "The vault could not be loaded.");
7928
+ });
7774
7929
  port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
7775
7930
  knobsRef.current?.().catch(() => void 0);
7776
7931
  port.lists.recents?.list().then(setRecents, () => void 0);
@@ -7784,6 +7939,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7784
7939
  const orgs = snap?.organizations ?? [];
7785
7940
  const definitions = snap?.definitions ?? [];
7786
7941
  const inThisVault = useMemo6(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
7942
+ const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
7787
7943
  const views = useMemo6(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
7788
7944
  const visible = useMemo6(() => {
7789
7945
  const filtered = inThisVault.filter((i) => {
@@ -7824,8 +7980,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7824
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: [
7825
7981
  /* @__PURE__ */ jsx39(SafeGlyph, { className: "size-8 text-muted-foreground" }),
7826
7982
  /* @__PURE__ */ jsx39("div", { className: "font-medium", children: "The vault couldn\u2019t open" }),
7827
- /* @__PURE__ */ jsx39("div", { className: "max-w-xs text-muted-foreground", children: plainLoadError(error) }),
7828
- /* @__PURE__ */ jsx39("button", { type: "button", className: "text-primary hover:underline", onClick: load, children: "Try again" })
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" })
7987
+ ] })
7829
7988
  ] });
7830
7989
  }
7831
7990
  if (!snap) {
@@ -7905,6 +8064,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
7905
8064
  {
7906
8065
  title,
7907
8066
  items: visible,
8067
+ showOwner: vaultMixesOwners,
7908
8068
  definitions,
7909
8069
  port,
7910
8070
  selectedId: loc.itemId,
@@ -8306,6 +8466,7 @@ function createFieldsPort(ctx) {
8306
8466
  if (patch.uriMatchMode !== void 0) body.uri_match_mode = patch.uriMatchMode;
8307
8467
  if (patch.browserFillEnabled !== void 0) body.browser_fill_enabled = patch.browserFillEnabled;
8308
8468
  if (patch.loginUrls !== void 0) body.login_urls = patch.loginUrls;
8469
+ if (patch.active !== void 0) body.status = patch.active ? "active" : "disabled";
8309
8470
  await account3.updateItem(api, { path: { item_id: item.id }, body }, ctx.optsFor(item));
8310
8471
  return reread(item);
8311
8472
  },
@@ -8677,6 +8838,7 @@ async function readNativeImportLimits(api, organizationId) {
8677
8838
  var recoveryOf = (w) => w.lifecycle?.vault_recovery;
8678
8839
  var isDeleted = (w) => recoveryOf(w)?.state === "deleted";
8679
8840
  var MATCH_MODES2 = ["host", "domain", "exact", "never"];
8841
+ var FIELD_WORDS = { totp_seed: "One-time password key", authenticator_last_time_step: "Last code used" };
8680
8842
  var handlingOf = (v) => v === "visible" || v === "sealed" ? v : "revealable";
8681
8843
  function fieldOf(w, def) {
8682
8844
  const declared = def?.fields.find((f) => f.key === w.field_key);
@@ -8684,7 +8846,7 @@ function fieldOf(w, def) {
8684
8846
  return {
8685
8847
  id: w.id,
8686
8848
  key: w.field_key,
8687
- label: declared?.label ?? humanize(w.field_key),
8849
+ label: declared?.label ?? FIELD_WORDS[w.field_key] ?? humanize(w.field_key),
8688
8850
  kind: declared?.kind ?? (handling === "visible" ? "text" : "secret"),
8689
8851
  handling,
8690
8852
  editable: w.editable ?? true,
@@ -8717,6 +8879,7 @@ function itemOf(w, owner, defs, auth) {
8717
8879
  uriMatchMode: MATCH_MODES2.find((m) => m === w.uri_match_mode) ?? "host",
8718
8880
  browserFillEnabled: w.browser_fill_enabled ?? true,
8719
8881
  accessMode: w.access_mode ?? null,
8882
+ turnedOff: w.status === "disabled",
8720
8883
  ownerUserId: w.user_id ?? null,
8721
8884
  deletion: recovery?.state === "deleted" ? { deletionId: typeof recovery.deletion_id === "string" ? recovery.deletion_id : null, deletedAt: typeof recovery.deleted_at === "string" ? recovery.deleted_at : null } : null,
8722
8885
  updatedAt: w.updated_at,
@@ -8776,9 +8939,12 @@ function createApiVaultPort(api, options = {}) {
8776
8939
  const authP = retrying(() => apps2.listAuthenticators(api));
8777
8940
  const userP = retrying(() => account9.listItems(api, { query: { principal_type: "user" } }));
8778
8941
  const sharedP = retrying(() => account9.sharedWithMe(api));
8942
+ const quiet = (p) => void p.catch(() => void 0);
8943
+ [catalogP, authP, userP, sharedP].forEach(quiet);
8779
8944
  const org = options.organizations ? null : await retrying(() => platform.listMyOrganizations(api));
8780
8945
  orgs = [...new Map((options.organizations ?? (org?.organizations ?? []).filter((o) => !o.archived_at).map((o) => ({ id: o.id, name: o.name }))).map((o) => [o.id, o])).values()];
8781
8946
  const orgListsP = orgs.map((o) => retrying(() => account9.listItems(api, { query: { principal_type: "organization", organization_id: o.id } }, { organizationId: o.id })));
8947
+ orgListsP.forEach(quiet);
8782
8948
  const [catalog, mine] = await Promise.all([catalogP, userP]);
8783
8949
  const [authSettled, sharedSettled, ...orgSettled] = await Promise.allSettled([authP, sharedP, ...orgListsP]);
8784
8950
  const unavailable = [];
@@ -8902,9 +9068,11 @@ function createVaultKnobs(client, address) {
8902
9068
  }
8903
9069
  export {
8904
9070
  CATEGORIES,
9071
+ CONFIRM_RETURN_KEY,
8905
9072
  DEFAULT_LOCATION,
8906
9073
  GenerateButton,
8907
9074
  HIDDEN_ITEM_TAG,
9075
+ IdentityGate,
8908
9076
  LOCKED_MESSAGE,
8909
9077
  VaultApp,
8910
9078
  VaultLockedError,
@@ -8922,6 +9090,9 @@ export {
8922
9090
  matchesQuery,
8923
9091
  needsRecentSignIn,
8924
9092
  parseDefinitions,
8925
- sortItems
9093
+ siteDomainOf,
9094
+ sortItems,
9095
+ useConfirmed,
9096
+ wasCancelled
8926
9097
  };
8927
9098
  //# sourceMappingURL=index.js.map