@ai-matrx/vault 0.1.35 → 0.1.37

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
@@ -58,7 +58,7 @@ import {
58
58
  } from "./chunk-B5TOAIY6.js";
59
59
 
60
60
  // src/VaultApp.tsx
61
- import { useCallback as useCallback4, useEffect as useEffect21, useMemo as useMemo6, useRef as useRef17, useState as useState39, useSyncExternalStore as useSyncExternalStore5 } from "react";
61
+ import { useCallback as useCallback4, useEffect as useEffect22, useMemo as useMemo6, useRef as useRef18, useState as useState40, useSyncExternalStore as useSyncExternalStore5 } from "react";
62
62
  import { DropdownMenu as DropdownMenu5, DropdownMenuContent as DropdownMenuContent5, DropdownMenuItem as DropdownMenuItem5, DropdownMenuTrigger as DropdownMenuTrigger5, LookScope } from "@ai-matrx/design-system";
63
63
  import { Button as Button33, SearchField as SearchField4, Select as Select12 } from "@ai-matrx/design-system/controls";
64
64
  import { confirm as confirm14 } from "@ai-matrx/kit/confirm-opener";
@@ -881,11 +881,11 @@ function whenInDay(iso, now = /* @__PURE__ */ new Date()) {
881
881
  if (dayKey(d) === dayKey(now)) return formatRelativeTime(iso, { now: now.getTime() });
882
882
  return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
883
883
  }
884
- function collapseRuns(rows, keyOf) {
884
+ function collapseRuns(rows, keyOf2) {
885
885
  const out = [];
886
886
  const at = /* @__PURE__ */ new Map();
887
887
  for (const row of rows) {
888
- const k = keyOf(row);
888
+ const k = keyOf2(row);
889
889
  const seen = at.get(k);
890
890
  if (seen) seen.times += 1;
891
891
  else {
@@ -1293,14 +1293,12 @@ function CodeButton({ live, digits, size = "md", label }) {
1293
1293
  disabled: !live.code,
1294
1294
  onClick: () => live.code && void copy(live.code),
1295
1295
  "aria-label": live.code ? `Copy ${label} code` : `Getting ${label} code`,
1296
+ ...live.code ? { tooltip: "Copy code" } : {},
1296
1297
  variant: "quiet",
1297
1298
  layout: "row",
1298
- title: "Copy code",
1299
- end: /* @__PURE__ */ jsxs5("span", { className: cn5("inline-flex shrink-0 items-center", size === "lg" ? "gap-4" : "gap-3"), children: [
1300
- /* @__PURE__ */ jsx6("span", { className: cn5("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
1301
- copied ? /* @__PURE__ */ jsx6("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ jsx6(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ jsx6(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1302
- ] }),
1303
- className: "max-w-full shrink-0"
1299
+ fit: true,
1300
+ title: /* @__PURE__ */ jsx6("span", { className: cn5("whitespace-nowrap font-mono font-medium tabular-nums tracking-[0.08em]", size === "lg" ? "text-2xl" : "text-[1.0625rem]", live.code ? "text-foreground" : "text-disabled-foreground"), children: shown }),
1301
+ end: copied ? /* @__PURE__ */ jsx6("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ jsx6(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ jsx6(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1304
1302
  }
1305
1303
  );
1306
1304
  }
@@ -1410,6 +1408,14 @@ function canDecodeQrLocally() {
1410
1408
  function hasCamera() {
1411
1409
  return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
1412
1410
  }
1411
+ async function hasCameraDevice() {
1412
+ if (!hasCamera() || typeof navigator.mediaDevices?.enumerateDevices !== "function") return false;
1413
+ try {
1414
+ return (await navigator.mediaDevices.enumerateDevices()).some((d) => d.kind === "videoinput");
1415
+ } catch {
1416
+ return false;
1417
+ }
1418
+ }
1413
1419
  async function decodeQr(source) {
1414
1420
  return decodeQrFromElement(source);
1415
1421
  }
@@ -1441,17 +1447,15 @@ function useCanScan() {
1441
1447
  }, []);
1442
1448
  return ok;
1443
1449
  }
1444
- function QrScanPanel({ open, onResult, onClose }) {
1450
+ function QrScanInline({ onResult, onClose }) {
1445
1451
  const video = useRef6(null);
1446
1452
  const [error, setError] = useState8(null);
1447
1453
  const done = useRef6(onResult);
1448
1454
  done.current = onResult;
1449
1455
  useEffect8(() => {
1450
- if (!open) return;
1451
1456
  let stream = null;
1452
1457
  let live = true;
1453
1458
  let timer2 = null;
1454
- setError(null);
1455
1459
  const stop = () => {
1456
1460
  if (timer2) clearTimeout(timer2);
1457
1461
  stream?.getTracks().forEach((t) => t.stop());
@@ -1494,13 +1498,26 @@ function QrScanPanel({ open, onResult, onClose }) {
1494
1498
  live = false;
1495
1499
  stop();
1496
1500
  };
1497
- }, [open]);
1498
- return /* @__PURE__ */ jsxs6(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ jsx7(Button5, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
1499
- /* @__PURE__ */ jsxs6("div", { className: "relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl bg-muted", children: [
1501
+ }, []);
1502
+ if (error) {
1503
+ return /* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-2 px-1 pt-1 text-xs text-muted-foreground", role: "status", "data-camera-note": "", children: [
1504
+ /* @__PURE__ */ jsx7(CameraGlyph, { className: "size-3.5 shrink-0", "aria-hidden": true }),
1505
+ /* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1 truncate", children: [
1506
+ error,
1507
+ " Paste the setup key or choose a QR image."
1508
+ ] }),
1509
+ /* @__PURE__ */ jsx7(Button5, { variant: "quiet", onClick: onClose, children: "Dismiss" })
1510
+ ] });
1511
+ }
1512
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-1.5 pt-2", role: "region", "aria-label": "Scan QR code", "data-camera-preview": "", children: [
1513
+ /* @__PURE__ */ jsxs6("div", { className: "relative aspect-square w-full max-w-56 overflow-hidden rounded-xl bg-muted", children: [
1500
1514
  /* @__PURE__ */ jsx7("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
1501
- error ? /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ jsx7("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1515
+ /* @__PURE__ */ jsx7("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1502
1516
  ] }),
1503
- /* @__PURE__ */ jsx7("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
1517
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
1518
+ /* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: "Point at the site's QR code" }),
1519
+ /* @__PURE__ */ jsx7(Button5, { variant: "quiet", onClick: onClose, children: "Stop camera" })
1520
+ ] })
1504
1521
  ] });
1505
1522
  }
1506
1523
  function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status, autoStartCamera = false }) {
@@ -1510,8 +1527,15 @@ function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "
1510
1527
  const autoStarted = useRef6(false);
1511
1528
  useEffect8(() => {
1512
1529
  if (!autoStartCamera || !canScan || disabled || autoStarted.current || value) return;
1513
- autoStarted.current = true;
1514
- setScanning(true);
1530
+ let live = true;
1531
+ void hasCameraDevice().then((has) => {
1532
+ if (!live || !has || autoStarted.current) return;
1533
+ autoStarted.current = true;
1534
+ setScanning(true);
1535
+ });
1536
+ return () => {
1537
+ live = false;
1538
+ };
1515
1539
  }, [autoStartCamera, canScan, disabled, value]);
1516
1540
  const [reading, setReading] = useState8(false);
1517
1541
  const [imageError, setImageError] = useState8(null);
@@ -1613,10 +1637,9 @@ function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "
1613
1637
  ]
1614
1638
  }
1615
1639
  ),
1616
- canScan ? /* @__PURE__ */ jsx7(
1617
- QrScanPanel,
1640
+ canScan && scanning ? /* @__PURE__ */ jsx7(
1641
+ QrScanInline,
1618
1642
  {
1619
- open: scanning,
1620
1643
  onClose: () => setScanning(false),
1621
1644
  onResult: (text) => {
1622
1645
  setScanning(false);
@@ -2102,7 +2125,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRenam
2102
2125
  const canManage = item.capabilities.canManage || item.capabilities.canEdit;
2103
2126
  if (a.removed) return null;
2104
2127
  const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
2105
- return /* @__PURE__ */ jsxs9("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-3 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
2128
+ return /* @__PURE__ */ jsxs9("div", { className: "grid min-h-14 grid-cols-[2rem_minmax(0,1fr)_auto_auto] items-center gap-x-1 rounded-lg px-2 py-1.5 transition-colors hover:bg-accent/50", children: [
2106
2129
  /* @__PURE__ */ jsx10(
2107
2130
  Button8,
2108
2131
  {
@@ -2123,6 +2146,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRenam
2123
2146
  onClick: onOpen,
2124
2147
  title: /* @__PURE__ */ jsx10("span", { className: a.enabled ? "text-foreground" : "text-muted-foreground", children: item.name }),
2125
2148
  line: sub ? /* @__PURE__ */ jsx10("span", { className: a.error ? "text-destructive" : "text-muted-foreground", title: sub, children: sub }) : void 0,
2149
+ oneLine: true,
2126
2150
  className: "min-w-0"
2127
2151
  }
2128
2152
  ),
@@ -2729,12 +2753,56 @@ function createVaultKnobs(client, address) {
2729
2753
  }
2730
2754
  var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
2731
2755
  var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
2756
+ var ORGANIZATION_SEARCH_AT_KNOB = "vault.organization_search_at";
2757
+ var ORGANIZATION_SEARCH_AT_UNREAD = 8;
2732
2758
  function positiveKnob(resolved, key) {
2733
2759
  const v = resolved[key];
2734
2760
  const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
2735
2761
  return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
2736
2762
  }
2737
2763
 
2764
+ // src/organizations.ts
2765
+ import { shortUuid } from "@ai-matrx/design-system/record-id-format";
2766
+ function orderOrganizations(orgs, items, recentItemIds) {
2767
+ const counts = /* @__PURE__ */ new Map();
2768
+ for (const i of items) if (i.owner.organizationId) counts.set(i.owner.organizationId, (counts.get(i.owner.organizationId) ?? 0) + 1);
2769
+ const byId = new Map(items.map((i) => [i.id, i]));
2770
+ const recent = /* @__PURE__ */ new Map();
2771
+ for (const id of recentItemIds ?? []) {
2772
+ const org = byId.get(id)?.owner.organizationId;
2773
+ if (org && !recent.has(org)) recent.set(org, recent.size);
2774
+ }
2775
+ const group = (o) => recent.has(o.id) ? 0 : (counts.get(o.id) ?? 0) > 0 ? 1 : 2;
2776
+ return [...orgs].sort((a, b) => group(a) - group(b) || (recent.get(a.id) ?? 0) - (recent.get(b.id) ?? 0) || a.name.localeCompare(b.name, void 0, { sensitivity: "base" }) || a.id.localeCompare(b.id));
2777
+ }
2778
+ function organizationHints(orgs) {
2779
+ const seen = /* @__PURE__ */ new Map();
2780
+ for (const o of orgs) seen.set(o.name.trim().toLowerCase(), (seen.get(o.name.trim().toLowerCase()) ?? 0) + 1);
2781
+ return new Map(orgs.filter((o) => (seen.get(o.name.trim().toLowerCase()) ?? 0) > 1).map((o) => [o.id, shortUuid(o.id)]));
2782
+ }
2783
+
2784
+ // src/shown-until-move.ts
2785
+ import { useEffect as useEffect11, useRef as useRef9, useState as useState14 } from "react";
2786
+ var keyOf = (loc) => `${String(loc.vault)}|${loc.view}|${loc.itemId ?? ""}|${loc.mode}|${loc.panel ?? ""}|${loc.kind ?? ""}`;
2787
+ function useShownUntilMove(loc) {
2788
+ const [shown, setShown] = useState14(null);
2789
+ const home = useRef9(null);
2790
+ const key = keyOf(loc);
2791
+ useEffect11(() => {
2792
+ if (!shown) {
2793
+ home.current = null;
2794
+ return;
2795
+ }
2796
+ if (home.current?.id !== shown.id) home.current = { id: shown.id, key: null };
2797
+ if (home.current.key === null) {
2798
+ if (loc.itemId === shown.id && loc.mode === "view") home.current.key = key;
2799
+ return;
2800
+ }
2801
+ if (key !== home.current.key) setShown(null);
2802
+ }, [shown, key, loc.itemId, loc.mode]);
2803
+ return [shown, setShown];
2804
+ }
2805
+
2738
2806
  // src/lock.ts
2739
2807
  import { useSyncExternalStore as useSyncExternalStore2 } from "react";
2740
2808
  var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
@@ -2776,7 +2844,7 @@ function useLocked(lock) {
2776
2844
 
2777
2845
  // src/io/BackupPanel.tsx
2778
2846
  import { formatFileSize } from "@ai-matrx/kit/format";
2779
- import { useEffect as useEffect11, useRef as useRef9, useState as useState15 } from "react";
2847
+ import { useEffect as useEffect12, useRef as useRef10, useState as useState16 } from "react";
2780
2848
  import { Button as Button12, Field as Field5, SegmentedControl as SegmentedControl3, Switch as Switch3 } from "@ai-matrx/design-system/controls";
2781
2849
  import { downloadFile } from "@ai-matrx/kit/download";
2782
2850
  import { confirm as confirm4 } from "@ai-matrx/kit/confirm-opener";
@@ -2869,7 +2937,7 @@ function startNewRestoreRun(preview) {
2869
2937
  }
2870
2938
 
2871
2939
  // src/io/lines.tsx
2872
- import { useState as useState14 } from "react";
2940
+ import { useState as useState15 } from "react";
2873
2941
  import { Checkbox } from "@ai-matrx/design-system";
2874
2942
  import { Badge as Badge4, Button as Button11, DisclosureHeader as DisclosureHeader2 } from "@ai-matrx/design-system/controls";
2875
2943
  import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
@@ -2882,7 +2950,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
2882
2950
  ] });
2883
2951
  }
2884
2952
  function Windowed({ items, size = 150, render }) {
2885
- const [all, setAll] = useState14(false);
2953
+ const [all, setAll] = useState15(false);
2886
2954
  const shown = all ? items : items.slice(0, size);
2887
2955
  return /* @__PURE__ */ jsxs12(Fragment8, { children: [
2888
2956
  shown.map(render),
@@ -2893,7 +2961,7 @@ function Windowed({ items, size = 150, render }) {
2893
2961
  ] });
2894
2962
  }
2895
2963
  function More({ title = "More", children }) {
2896
- const [open, setOpen] = useState14(false);
2964
+ const [open, setOpen] = useState15(false);
2897
2965
  return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-2", children: [
2898
2966
  /* @__PURE__ */ jsx13(DisclosureHeader2, { open, title, onClick: () => setOpen((o) => !o) }),
2899
2967
  open ? children : null
@@ -2933,21 +3001,21 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
2933
3001
  function BackupPanel({ port, host, items, onClose, onChanged }) {
2934
3002
  const minLength = passphraseMinimum(host.backupPassphraseMinLength);
2935
3003
  const confirmed = useConfirmed();
2936
- const fileInput = useRef9(null);
2937
- const abort = useRef9(null);
2938
- const [mode, setMode] = useState15("backup");
2939
- const [busy, setBusy] = useState15(false);
2940
- const [error, setError] = useState15(null);
2941
- const [passphrase, setPassphrase] = useState15("");
2942
- const [repeat, setRepeat] = useState15("");
2943
- const [accepted, setAccepted] = useState15(false);
2944
- const [selected, setSelected] = useState15(/* @__PURE__ */ new Set());
2945
- const [backup, setBackup] = useState15(null);
2946
- const [file, setFile] = useState15(null);
2947
- const [restorePreview, setRestorePreview] = useState15(null);
2948
- const [runId, setRunId] = useState15(null);
2949
- const [result, setResult] = useState15(null);
2950
- useEffect11(() => () => abort.current?.abort(), []);
3004
+ const fileInput = useRef10(null);
3005
+ const abort = useRef10(null);
3006
+ const [mode, setMode] = useState16("backup");
3007
+ const [busy, setBusy] = useState16(false);
3008
+ const [error, setError] = useState16(null);
3009
+ const [passphrase, setPassphrase] = useState16("");
3010
+ const [repeat, setRepeat] = useState16("");
3011
+ const [accepted, setAccepted] = useState16(false);
3012
+ const [selected, setSelected] = useState16(/* @__PURE__ */ new Set());
3013
+ const [backup, setBackup] = useState16(null);
3014
+ const [file, setFile] = useState16(null);
3015
+ const [restorePreview, setRestorePreview] = useState16(null);
3016
+ const [runId, setRunId] = useState16(null);
3017
+ const [result, setResult] = useState16(null);
3018
+ useEffect12(() => () => abort.current?.abort(), []);
2951
3019
  const switchMode = (next) => {
2952
3020
  abort.current?.abort();
2953
3021
  setMode(next);
@@ -3084,7 +3152,7 @@ function BackupPanel({ port, host, items, onClose, onChanged }) {
3084
3152
  /* @__PURE__ */ jsx14(Summary, { value: backup }),
3085
3153
  /* @__PURE__ */ jsx14(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
3086
3154
  /* @__PURE__ */ jsxs13(VaultSection, { children: [
3087
- /* @__PURE__ */ jsx14(VaultRow, { label: "Passphrase", hint: minLength ? `At least ${minLength} characters. Not saved.` : "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx14(Field5, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
3155
+ /* @__PURE__ */ jsx14(VaultRow, { label: "Passphrase", hint: minLength ? `At least ${minLength} characters. Not saved. It can't be recovered.` : "Not saved. It can't be recovered.", children: /* @__PURE__ */ jsx14(Field5, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
3088
3156
  short ? /* @__PURE__ */ jsxs13("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
3089
3157
  "Use at least ",
3090
3158
  minLength,
@@ -3132,7 +3200,7 @@ function tooShort(passphrase, minLength) {
3132
3200
  }
3133
3201
 
3134
3202
  // src/io/ExportPanel.tsx
3135
- import { useMemo, useState as useState16 } from "react";
3203
+ import { useMemo, useState as useState17 } from "react";
3136
3204
  import { Button as Button13, Select as Select5 } from "@ai-matrx/design-system/controls";
3137
3205
  import { downloadFile as downloadFile2 } from "@ai-matrx/kit/download";
3138
3206
  import { confirm as confirm5 } from "@ai-matrx/kit/confirm-opener";
@@ -3157,11 +3225,11 @@ function omissionText2(omissions) {
3157
3225
  function ExportPanel({ port, items, onClose }) {
3158
3226
  const confirmed = useConfirmed();
3159
3227
  const logins = useMemo(() => items.filter((i) => i.definitionKey === WEBSITE_LOGIN), [items]);
3160
- const [profile, setProfile] = useState16("matrx_login_csv_v1");
3161
- const [selected, setSelected] = useState16(/* @__PURE__ */ new Set());
3162
- const [preview, setPreview] = useState16(null);
3163
- const [busy, setBusy] = useState16(false);
3164
- const [error, setError] = useState16(null);
3228
+ const [profile, setProfile] = useState17("matrx_login_csv_v1");
3229
+ const [selected, setSelected] = useState17(/* @__PURE__ */ new Set());
3230
+ const [preview, setPreview] = useState17(null);
3231
+ const [busy, setBusy] = useState17(false);
3232
+ const [error, setError] = useState17(null);
3165
3233
  const format = FORMATS.find((f) => f.value === profile);
3166
3234
  const reasons = new Map(preview?.items.map((p) => [p.item_id, p]) ?? []);
3167
3235
  const eligible = preview?.items.filter((p) => p.eligible).length ?? 0;
@@ -3286,7 +3354,7 @@ function ExportPanel({ port, items, onClose }) {
3286
3354
  }
3287
3355
 
3288
3356
  // src/io/ImportPanel.tsx
3289
- import { useEffect as useEffect12, useMemo as useMemo2, useRef as useRef10, useState as useState17 } from "react";
3357
+ import { useEffect as useEffect13, useMemo as useMemo2, useRef as useRef11, useState as useState18 } from "react";
3290
3358
  import { Button as Button14, Select as Select6, Switch as Switch4, Textarea as Textarea2 } from "@ai-matrx/design-system/controls";
3291
3359
 
3292
3360
  // src/io/csv-import.ts
@@ -4148,25 +4216,25 @@ var STATE_BADGE = {
4148
4216
  var ME = "me";
4149
4217
  function ImportPanel({ port, host, items, definitions, organizations, onClose, onChanged, limits }) {
4150
4218
  const confirmed = useConfirmed();
4151
- const [otpFor, setOtpFor] = useState17(null);
4152
- const fileInput = useRef10(null);
4153
- const abort = useRef10(null);
4154
- const stop = useRef10(false);
4155
- const keys = useRef10(/* @__PURE__ */ new Map());
4156
- const [source, setSource] = useState17("auto");
4157
- const [envText, setEnvText] = useState17("");
4158
- const [injectSandbox, setInjectSandbox] = useState17(false);
4159
- const [fileName, setFileName] = useState17(null);
4160
- const [reading, setReading] = useState17(false);
4161
- const [draft, setDraft] = useState17(null);
4162
- const [destination, setDestination] = useState17(ME);
4163
- const [browserFill, setBrowserFill] = useState17(false);
4164
- const [approvedVisible, setApprovedVisible] = useState17(false);
4165
- const [selected, setSelected] = useState17(/* @__PURE__ */ new Set());
4166
- const [running, setRunning] = useState17(null);
4167
- const [done, setDone] = useState17(null);
4168
- const [error, setError] = useState17(null);
4169
- useEffect12(
4219
+ const [otpFor, setOtpFor] = useState18(null);
4220
+ const fileInput = useRef11(null);
4221
+ const abort = useRef11(null);
4222
+ const stop = useRef11(false);
4223
+ const keys = useRef11(/* @__PURE__ */ new Map());
4224
+ const [source, setSource] = useState18("auto");
4225
+ const [envText, setEnvText] = useState18("");
4226
+ const [injectSandbox, setInjectSandbox] = useState18(false);
4227
+ const [fileName, setFileName] = useState18(null);
4228
+ const [reading, setReading] = useState18(false);
4229
+ const [draft, setDraft] = useState18(null);
4230
+ const [destination, setDestination] = useState18(ME);
4231
+ const [browserFill, setBrowserFill] = useState18(false);
4232
+ const [approvedVisible, setApprovedVisible] = useState18(false);
4233
+ const [selected, setSelected] = useState18(/* @__PURE__ */ new Set());
4234
+ const [running, setRunning] = useState18(null);
4235
+ const [done, setDone] = useState18(null);
4236
+ const [error, setError] = useState18(null);
4237
+ useEffect13(
4170
4238
  () => () => {
4171
4239
  abort.current?.abort();
4172
4240
  stop.current = true;
@@ -4453,14 +4521,14 @@ function Notices({ draft }) {
4453
4521
  }
4454
4522
 
4455
4523
  // src/ItemList.tsx
4456
- import { useEffect as useEffect15, useRef as useRef13, useState as useState26 } from "react";
4524
+ import { useEffect as useEffect16, useRef as useRef14, useState as useState27 } from "react";
4457
4525
  import { DropdownMenu as DropdownMenu4, DropdownMenuContent as DropdownMenuContent4, DropdownMenuItem as DropdownMenuItem4, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator as DropdownMenuSeparator4, DropdownMenuTrigger as DropdownMenuTrigger4 } from "@ai-matrx/design-system";
4458
4526
  import { cn as cn11 } from "@ai-matrx/design-system";
4459
4527
  import { Button as Button22, SearchField, Tile as Tile3 } from "@ai-matrx/design-system/controls";
4460
4528
  import { CopyIcon as CopyIcon7 } from "@ai-matrx/design-system/icons";
4461
4529
 
4462
4530
  // src/ItemPane.tsx
4463
- import { Fragment as Fragment16, useEffect as useEffect14, useMemo as useMemo3, useRef as useRef12, useState as useState25 } from "react";
4531
+ import { Fragment as Fragment16, useEffect as useEffect15, useMemo as useMemo3, useRef as useRef13, useState as useState26 } from "react";
4464
4532
  import { DropdownMenu as DropdownMenu3, DropdownMenuContent as DropdownMenuContent3, DropdownMenuItem as DropdownMenuItem3, DropdownMenuSeparator as DropdownMenuSeparator3, DropdownMenuTrigger as DropdownMenuTrigger3 } from "@ai-matrx/design-system";
4465
4533
  import { cn as cn10 } from "@ai-matrx/design-system";
4466
4534
  import { Badge as Badge7, Button as Button21, CONTROLS_CONTAINER_CLASS, OptionCombobox, Switch as Switch6 } from "@ai-matrx/design-system/controls";
@@ -4468,7 +4536,7 @@ import { confirm as confirm10 } from "@ai-matrx/kit/confirm-opener";
4468
4536
 
4469
4537
  // src/activity/FilesSection.tsx
4470
4538
  import { formatFileSize as formatFileSize2 } from "@ai-matrx/kit/format";
4471
- import { useRef as useRef11, useState as useState18 } from "react";
4539
+ import { useRef as useRef12, useState as useState19 } from "react";
4472
4540
  import { Badge as Badge5, Button as Button15, Field as Field6, SegmentedControl as SegmentedControl4 } from "@ai-matrx/design-system/controls";
4473
4541
  import { cn as cn7 } from "@ai-matrx/design-system";
4474
4542
  import { confirm as confirm6 } from "@ai-matrx/kit/confirm-opener";
@@ -4486,11 +4554,11 @@ function FilesSection({ item, port, editing, onChanged }) {
4486
4554
  const confirmed = useConfirmed();
4487
4555
  const canEdit = editing && item.capabilities.canEdit;
4488
4556
  const canAdd = item.capabilities.canEdit;
4489
- const [busy, setBusy] = useState18(null);
4490
- const [error, setError] = useState18(null);
4491
- const [pending, setPending] = useState18(null);
4492
- const [dragging, setDragging] = useState18(false);
4493
- const picker = useRef11(null);
4557
+ const [busy, setBusy] = useState19(null);
4558
+ const [error, setError] = useState19(null);
4559
+ const [pending, setPending] = useState19(null);
4560
+ const [dragging, setDragging] = useState19(false);
4561
+ const picker = useRef12(null);
4494
4562
  if (!canAdd && item.attachments.length === 0) return null;
4495
4563
  async function run(key, work, fallback) {
4496
4564
  setBusy(key);
@@ -4567,8 +4635,8 @@ function FilesSection({ item, port, editing, onChanged }) {
4567
4635
  );
4568
4636
  }
4569
4637
  function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, onTooBig }) {
4570
- const [open, setOpen] = useState18(false);
4571
- const replacer = useRef11(null);
4638
+ const [open, setOpen] = useState19(false);
4639
+ const replacer = useRef12(null);
4572
4640
  async function remove() {
4573
4641
  const yes = await confirm6({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
4574
4642
  if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
@@ -4626,9 +4694,9 @@ function Protection({ value, locked, onChange }) {
4626
4694
  );
4627
4695
  }
4628
4696
  function NewFile({ file, busy, onAdd, onCancel }) {
4629
- const [label, setLabel] = useState18(file.name);
4630
- const [description, setDescription] = useState18("");
4631
- const [handling, setHandling] = useState18("revealable");
4697
+ const [label, setLabel] = useState19(file.name);
4698
+ const [description, setDescription] = useState19("");
4699
+ const [handling, setHandling] = useState19("revealable");
4632
4700
  async function add() {
4633
4701
  if (handling === "sealed" && !await confirmSeal(label)) return;
4634
4702
  await onAdd({ label: label.trim(), description: description.trim() || null, handling });
@@ -4648,10 +4716,10 @@ function NewFile({ file, busy, onAdd, onCancel }) {
4648
4716
  ] });
4649
4717
  }
4650
4718
  function FileDetailsRows({ file, busy, onSave, onCancel }) {
4651
- const [label, setLabel] = useState18(file.label);
4652
- const [description, setDescription] = useState18(file.description);
4653
- const [fileName, setFileName] = useState18(file.fileName);
4654
- const [handling, setHandling] = useState18(file.handling);
4719
+ const [label, setLabel] = useState19(file.label);
4720
+ const [description, setDescription] = useState19(file.description);
4721
+ const [fileName, setFileName] = useState19(file.fileName);
4722
+ const [handling, setHandling] = useState19(file.handling);
4655
4723
  const changed = label !== file.label || description !== file.description || fileName !== file.fileName || handling !== file.handling;
4656
4724
  async function save() {
4657
4725
  if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
@@ -4677,10 +4745,10 @@ function confirmSeal(label) {
4677
4745
  });
4678
4746
  }
4679
4747
  function DraftFilesSection({ files, onFiles }) {
4680
- const [pending, setPending] = useState18(null);
4681
- const [error, setError] = useState18(null);
4682
- const [dragging, setDragging] = useState18(false);
4683
- const picker = useRef11(null);
4748
+ const [pending, setPending] = useState19(null);
4749
+ const [error, setError] = useState19(null);
4750
+ const [dragging, setDragging] = useState19(false);
4751
+ const picker = useRef12(null);
4684
4752
  const choose = (file) => {
4685
4753
  if (!file) return;
4686
4754
  if (fileTooBig(file.size)) return setError(TOO_BIG);
@@ -4729,7 +4797,7 @@ function DraftFilesSection({ files, onFiles }) {
4729
4797
  }
4730
4798
 
4731
4799
  // src/fields/RecoveryCodesRow.tsx
4732
- import { useState as useState19 } from "react";
4800
+ import { useState as useState20 } from "react";
4733
4801
  import { Badge as Badge6, Button as Button16, Textarea as Textarea3 } from "@ai-matrx/design-system/controls";
4734
4802
  import { CopyIcon as CopyIcon6 } from "@ai-matrx/design-system/icons";
4735
4803
  import { Fragment as Fragment13, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -4739,9 +4807,9 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
4739
4807
  const confirmed = useConfirmed();
4740
4808
  const copyValue2 = useCopy();
4741
4809
  const secret = useTransientSecret();
4742
- const [busy, setBusy] = useState19(false);
4743
- const [error, setError] = useState19(null);
4744
- const [draft, setDraft] = useState19(null);
4810
+ const [busy, setBusy] = useState20(false);
4811
+ const [error, setError] = useState20(null);
4812
+ const [draft, setDraft] = useState20(null);
4745
4813
  const canEdit = item.capabilities.canEdit;
4746
4814
  const run = async (step) => {
4747
4815
  setBusy(true);
@@ -4836,7 +4904,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
4836
4904
  }
4837
4905
 
4838
4906
  // src/fields/DraftRows.tsx
4839
- import { useState as useState20 } from "react";
4907
+ import { useState as useState21 } from "react";
4840
4908
  import { Button as Button17, Field as Field7, SegmentedControl as SegmentedControl5, Select as Select7, Switch as Switch5 } from "@ai-matrx/design-system/controls";
4841
4909
  import { RecordId } from "@ai-matrx/design-system";
4842
4910
  import { confirm as confirm7 } from "@ai-matrx/kit/confirm-opener";
@@ -4891,7 +4959,7 @@ function FieldSettingsRows({ name, value, defaultHandling = "revealable", onChan
4891
4959
  var hasSecretSettings = (s) => saysMore(s, "revealable");
4892
4960
  var hasDeclaredSettings = (s, defaultHandling) => Boolean(s && saysMore(s, defaultHandling));
4893
4961
  function SecretBuilderRow({ field, onChange, onRemove }) {
4894
- const [open, setOpen] = useState20(hasSecretSettings(field));
4962
+ const [open, setOpen] = useState21(hasSecretSettings(field));
4895
4963
  const handling = field.handling ?? "revealable";
4896
4964
  const name = field.label.trim() || "Secret";
4897
4965
  return /* @__PURE__ */ jsxs18(Fragment14, { children: [
@@ -5132,7 +5200,7 @@ function targetLabel(t) {
5132
5200
  }
5133
5201
 
5134
5202
  // src/extension/UseOnSiteButton.tsx
5135
- import { useState as useState21 } from "react";
5203
+ import { useState as useState22 } from "react";
5136
5204
  import { Button as Button18 } from "@ai-matrx/design-system/controls";
5137
5205
  import { jsx as jsx20 } from "react/jsx-runtime";
5138
5206
  function canUseOnSite(item, pageUrl) {
@@ -5140,7 +5208,7 @@ function canUseOnSite(item, pageUrl) {
5140
5208
  }
5141
5209
  function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5142
5210
  const notify = useNotify();
5143
- const [busy, setBusy] = useState21(false);
5211
+ const [busy, setBusy] = useState22(false);
5144
5212
  if (!canUseOnSite(item, pageUrl)) return null;
5145
5213
  const site = pageSite(pageUrl);
5146
5214
  const run = async () => {
@@ -5159,7 +5227,7 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5159
5227
  }
5160
5228
 
5161
5229
  // src/sharing/SharePanel.tsx
5162
- import { useEffect as useEffect13, useState as useState24 } from "react";
5230
+ import { useEffect as useEffect14, useState as useState25 } from "react";
5163
5231
  import { confirm as confirm9 } from "@ai-matrx/kit/confirm-opener";
5164
5232
  import { Button as Button20, DisclosureHeader as DisclosureHeader3, Field as Field9, RegionSkeleton, Select as Select9 } from "@ai-matrx/design-system/controls";
5165
5233
  import { cn as cn9 } from "@ai-matrx/design-system";
@@ -5182,14 +5250,17 @@ function isEmail(value) {
5182
5250
  }
5183
5251
  var PERSONAL = "personal";
5184
5252
  var destinationOf = (key) => key === PERSONAL ? null : key;
5253
+ var orgChoice = (o, hints) => ({ value: o.id, label: o.name, ...hints.has(o.id) ? { hint: hints.get(o.id) } : {} });
5185
5254
  function moveDestinations(item, orgs) {
5186
5255
  if (item.owner.kind === "shared") return [];
5187
5256
  const here = item.owner.organizationId;
5188
- return [...here ? [{ value: PERSONAL, label: "Personal" }] : [], ...orgs.filter((o) => o.id !== here).map((o) => ({ value: o.id, label: o.name }))];
5257
+ const hints = organizationHints(orgs);
5258
+ return [...here ? [{ value: PERSONAL, label: "Personal" }] : [], ...orgs.filter((o) => o.id !== here).map((o) => orgChoice(o, hints))];
5189
5259
  }
5190
5260
  function copyDestinations(orgs, item) {
5191
5261
  const here = item ? item.owner.kind === "me" ? PERSONAL : item.owner.organizationId : void 0;
5192
- return [{ value: PERSONAL, label: "Personal" }, ...orgs.map((o) => ({ value: o.id, label: o.name }))].filter((d) => d.value !== here);
5262
+ const hints = organizationHints(orgs);
5263
+ return [{ value: PERSONAL, label: "Personal" }, ...orgs.map((o) => orgChoice(o, hints))].filter((d) => d.value !== here);
5193
5264
  }
5194
5265
  function copyRefusal(message2) {
5195
5266
  return /duplicate/i.test(message2) ? "There is already a copy of this item there." : null;
@@ -5217,7 +5288,7 @@ function shareSummary(grants) {
5217
5288
  var MEMBER_CHOICE_DEFAULT = "default";
5218
5289
 
5219
5290
  // src/sharing/parts.tsx
5220
- import { useState as useState22 } from "react";
5291
+ import { useState as useState23 } from "react";
5221
5292
  import { cn as cn8 } from "@ai-matrx/design-system";
5222
5293
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
5223
5294
  var message = (e, fallback) => {
@@ -5226,9 +5297,9 @@ var message = (e, fallback) => {
5226
5297
  };
5227
5298
  function useConfirmedChange() {
5228
5299
  const confirmed = useConfirmed();
5229
- const [busy, setBusy] = useState22(null);
5230
- const [error, setError] = useState22(null);
5231
- const [notice, setNotice] = useState22(null);
5300
+ const [busy, setBusy] = useState23(null);
5301
+ const [error, setError] = useState23(null);
5302
+ const [notice, setNotice] = useState23(null);
5232
5303
  async function run(key, fn, done) {
5233
5304
  setBusy(key);
5234
5305
  setError(null);
@@ -5262,18 +5333,20 @@ function StatusLine({ error, notice }) {
5262
5333
  }
5263
5334
 
5264
5335
  // src/sharing/MovePanel.tsx
5265
- import { useState as useState23 } from "react";
5336
+ import { useState as useState24 } from "react";
5266
5337
  import { confirm as confirm8 } from "@ai-matrx/kit/confirm-opener";
5267
5338
  import { Button as Button19, Field as Field8, Select as Select8 } from "@ai-matrx/design-system/controls";
5268
5339
  import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
5269
5340
  var NONE = "__none__";
5270
- function MovePanel({ item, port, organizations, onClose, onChanged }) {
5341
+ function MovePanel({ item, port, host, organizations, onClose, onChanged, onOpenItem }) {
5271
5342
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
5272
5343
  const moves = moveDestinations(item, organizations);
5273
5344
  const copies = copyDestinations(organizations, item);
5274
- const [moveTo, setMoveTo] = useState23("");
5275
- const [copyTo, setCopyTo] = useState23("");
5276
- const [email, setEmail] = useState23("");
5345
+ const [moveTo, setMoveTo] = useState24("");
5346
+ const [copyTo, setCopyTo] = useState24("");
5347
+ const [email, setEmail] = useState24("");
5348
+ const [made, setMade] = useState24(null);
5349
+ const searchAt = host.organizationSearchAt ?? ORGANIZATION_SEARCH_AT_UNREAD;
5277
5350
  const passkey = isPasskey(item);
5278
5351
  const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
5279
5352
  const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
@@ -5307,8 +5380,10 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5307
5380
  };
5308
5381
  const copy = async () => {
5309
5382
  if (!copyChoice) return;
5310
- const made = await run("copy", () => port.sharing.copy(item, destinationOf(copyChoice.value)), `Copy made in ${copyChoice.label}`);
5311
- if (made) onChanged();
5383
+ const copied = await run("copy", () => port.sharing.copy(item, destinationOf(copyChoice.value)), `Copy made in ${copyChoice.label}`);
5384
+ if (!copied) return;
5385
+ setMade(copied);
5386
+ onChanged();
5312
5387
  };
5313
5388
  const nothing = !canMove && !canGive && !canCopy;
5314
5389
  return /* @__PURE__ */ jsx22(
@@ -5317,7 +5392,10 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5317
5392
  title: "Move or copy",
5318
5393
  size: "md",
5319
5394
  onClose,
5320
- footer: /* @__PURE__ */ jsx22(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx22(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ jsx22(Button19, { variant: "primary", onClick: onClose, children: "Done" }) }),
5395
+ footer: /* @__PURE__ */ jsxs20(PanelFooter, { status: error || notice ? /* @__PURE__ */ jsx22(StatusLine, { error, notice }) : null, children: [
5396
+ made && onOpenItem ? /* @__PURE__ */ jsx22(Button19, { variant: "outline", onClick: () => onOpenItem(made), children: "Open copy" }) : null,
5397
+ /* @__PURE__ */ jsx22(Button19, { variant: "primary", onClick: onClose, children: "Done" })
5398
+ ] }),
5321
5399
  children: nothing ? /* @__PURE__ */ jsx22(VaultSection, { children: /* @__PURE__ */ jsx22(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ jsxs20(VaultSection, { children: [
5322
5400
  canMove && moves.length > 0 ? /* @__PURE__ */ jsx22(
5323
5401
  VaultRow,
@@ -5325,7 +5403,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5325
5403
  label: "Move to",
5326
5404
  hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
5327
5405
  actions: /* @__PURE__ */ jsx22(Button19, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
5328
- children: /* @__PURE__ */ jsx22(Select8, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5406
+ children: /* @__PURE__ */ jsx22(Select8, { className: "w-full", "aria-label": "Move to", searchAt, value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5329
5407
  }
5330
5408
  ) : null,
5331
5409
  canGive ? /* @__PURE__ */ jsx22(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ jsx22(Button19, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ jsx22(
@@ -5342,7 +5420,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5342
5420
  onChange: (e) => setEmail(e.target.value)
5343
5421
  }
5344
5422
  ) }) : null,
5345
- canCopy && copies.length > 0 ? /* @__PURE__ */ jsx22(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ jsx22(Button19, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ jsx22(Select8, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
5423
+ canCopy && copies.length > 0 ? /* @__PURE__ */ jsx22(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ jsx22(Button19, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ jsx22(Select8, { className: "w-full", "aria-label": "Copy to", searchAt, value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
5346
5424
  ] })
5347
5425
  }
5348
5426
  );
@@ -5351,11 +5429,11 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5351
5429
  // src/sharing/SharePanel.tsx
5352
5430
  import { Fragment as Fragment15, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
5353
5431
  function useGrants(port, item) {
5354
- const [grants, setGrants] = useState24(null);
5355
- const [loadError, setLoadError] = useState24(null);
5356
- const [nonce, setNonce] = useState24(0);
5432
+ const [grants, setGrants] = useState25(null);
5433
+ const [loadError, setLoadError] = useState25(null);
5434
+ const [nonce, setNonce] = useState25(0);
5357
5435
  const allowed = item.capabilities.canManage;
5358
- useEffect13(() => {
5436
+ useEffect14(() => {
5359
5437
  if (!allowed) return;
5360
5438
  let live = true;
5361
5439
  setLoadError(null);
@@ -5372,9 +5450,9 @@ function useGrants(port, item) {
5372
5450
  function SharePanel({ item, port, organizations, onClose, onChanged }) {
5373
5451
  const { grants, setGrants, loadError, reload } = useGrants(port, item);
5374
5452
  const { busy, error, notice, run } = useConfirmedChange();
5375
- const [email, setEmail] = useState24("");
5376
- const [level, setLevel] = useState24("use");
5377
- const [more, setMore] = useState24(false);
5453
+ const [email, setEmail] = useState25("");
5454
+ const [level, setLevel] = useState25("use");
5455
+ const [more, setMore] = useState25(false);
5378
5456
  const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
5379
5457
  const orgName = item.owner.label;
5380
5458
  const people = (grants ?? []).filter((g) => g.kind === "person");
@@ -5493,8 +5571,8 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5493
5571
  function IntoOrganization({ item, port, organizations, grants, onShared }) {
5494
5572
  const { busy, error, notice, run } = useConfirmedChange();
5495
5573
  const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
5496
- const [target, setTarget] = useState24("");
5497
- const [level, setLevel] = useState24("use");
5574
+ const [target, setTarget] = useState25("");
5575
+ const [level, setLevel] = useState25("use");
5498
5576
  const chosen = open.find((o) => o.id === target);
5499
5577
  if (item.owner.kind !== "me") return null;
5500
5578
  return /* @__PURE__ */ jsx23(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ jsxs21(Fragment15, { children: [
@@ -5529,10 +5607,10 @@ var CHOICES = [
5529
5607
  { value: "editor", label: "Can edit", meta: "See and change" }
5530
5608
  ];
5531
5609
  function MemberAccess({ port, organizationId, organizationName }) {
5532
- const [list, setList] = useState24(null);
5533
- const [loadError, setLoadError] = useState24(null);
5610
+ const [list, setList] = useState25(null);
5611
+ const [loadError, setLoadError] = useState25(null);
5534
5612
  const { busy, error, run } = useConfirmedChange();
5535
- useEffect13(() => {
5613
+ useEffect14(() => {
5536
5614
  let live = true;
5537
5615
  port.sharing.memberAccess(organizationId).then(
5538
5616
  (l) => live && setList(l),
@@ -5564,9 +5642,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
5564
5642
  ] });
5565
5643
  }
5566
5644
  function SharingSummary({ item, port, className }) {
5567
- const [text, setText] = useState24("");
5645
+ const [text, setText] = useState25("");
5568
5646
  const allowed = item.capabilities.canManage;
5569
- useEffect13(() => {
5647
+ useEffect14(() => {
5570
5648
  if (!allowed) return;
5571
5649
  let live = true;
5572
5650
  port.sharing.grants(item).then(
@@ -5597,7 +5675,7 @@ function ItemPane(props) {
5597
5675
  const editing = mode !== "view";
5598
5676
  const seedName = seed?.name ?? "";
5599
5677
  const seedUrl = seed?.url ?? "";
5600
- const [loaded, setLoaded] = useState25({});
5678
+ const [loaded, setLoaded] = useState26({});
5601
5679
  const base = useMemo3(() => {
5602
5680
  const b = draftOf(item);
5603
5681
  if (!item) {
@@ -5607,28 +5685,28 @@ function ItemPane(props) {
5607
5685
  b.values = { ...loaded };
5608
5686
  return b;
5609
5687
  }, [item, seedName, seedUrl, loaded]);
5610
- const [draft, setDraft] = useState25(base);
5611
- const [tagsText, setTagsText] = useState25(base.tags.join(", "));
5612
- const [showTags, setShowTags] = useState25(false);
5613
- const [showDescription, setShowDescription] = useState25(false);
5614
- const [showRecovery, setShowRecovery] = useState25(false);
5615
- const [settingUpOtp, setSettingUpOtp] = useState25(false);
5616
- const [owner, setOwner] = useState25(defaultOwner ?? "me");
5617
- const [recipient, setRecipient] = useState25("");
5618
- const [generatePrivately, setGeneratePrivately] = useState25(false);
5619
- const [busy, setBusy] = useState25(false);
5620
- const [sent, setSent] = useState25(null);
5621
- const [queuedFiles, setQueuedFiles] = useState25([]);
5622
- const [showBrowser, setShowBrowser] = useState25(false);
5623
- const [error, setError] = useState25(null);
5624
- const [destinations, setDestinations] = useState25({});
5625
- const [savedNew, setSavedNew] = useState25(false);
5688
+ const [draft, setDraft] = useState26(base);
5689
+ const [tagsText, setTagsText] = useState26(base.tags.join(", "));
5690
+ const [showTags, setShowTags] = useState26(false);
5691
+ const [showDescription, setShowDescription] = useState26(false);
5692
+ const [showRecovery, setShowRecovery] = useState26(false);
5693
+ const [settingUpOtp, setSettingUpOtp] = useState26(false);
5694
+ const [owner, setOwner] = useState26(defaultOwner ?? "me");
5695
+ const [recipient, setRecipient] = useState26("");
5696
+ const [generatePrivately, setGeneratePrivately] = useState26(false);
5697
+ const [busy, setBusy] = useState26(false);
5698
+ const [sent, setSent] = useState26(null);
5699
+ const [queuedFiles, setQueuedFiles] = useState26([]);
5700
+ const [showBrowser, setShowBrowser] = useState26(false);
5701
+ const [error, setError] = useState26(null);
5702
+ const [destinations, setDestinations] = useState26({});
5703
+ const [savedNew, setSavedNew] = useState26(false);
5626
5704
  const dirty = editing && !savedNew && isDirty(base, draft);
5627
5705
  const declared = definition?.fields ?? [];
5628
- const prev = useRef12(null);
5629
- const paneRef = useRef12(null);
5706
+ const prev = useRef13(null);
5707
+ const paneRef = useRef13(null);
5630
5708
  const room = useRoomOf(paneRef);
5631
- useEffect14(() => {
5709
+ useEffect15(() => {
5632
5710
  const was = prev.current;
5633
5711
  const id = item?.id ?? null;
5634
5712
  if (was && was.id === id && was.mode === mode && editing) {
@@ -5641,22 +5719,22 @@ function ItemPane(props) {
5641
5719
  }
5642
5720
  prev.current = { base, id, mode };
5643
5721
  }, [base, mode, item?.id, editing]);
5644
- useEffect14(() => {
5722
+ useEffect15(() => {
5645
5723
  setLoaded({});
5646
5724
  setShowTags(false);
5647
5725
  setShowDescription(false);
5648
5726
  setShowRecovery(false);
5649
5727
  setSavedNew(false);
5650
5728
  }, [item?.id, mode]);
5651
- const onDirtyRef = useRef12(onDirty);
5729
+ const onDirtyRef = useRef13(onDirty);
5652
5730
  onDirtyRef.current = onDirty;
5653
- useEffect14(() => onDirtyRef.current(dirty), [dirty]);
5731
+ useEffect15(() => onDirtyRef.current(dirty), [dirty]);
5654
5732
  const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
5655
- useEffect14(() => {
5733
+ useEffect15(() => {
5656
5734
  if (editing && dirty) keepDraft(keepKey, keptFieldsOf(draft), { basedOn: item?.updatedAt ?? "new" });
5657
5735
  else if (!editing) dropKeptDraft(keepKey);
5658
5736
  }, [editing, dirty, draft, keepKey, item?.updatedAt]);
5659
- useEffect14(() => {
5737
+ useEffect15(() => {
5660
5738
  if (!editing || !item) return;
5661
5739
  let live = true;
5662
5740
  for (const f of item.fields) {
@@ -5781,7 +5859,7 @@ function ItemPane(props) {
5781
5859
  const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
5782
5860
  const declaredKeys = new Set(declared.map((f) => f.key));
5783
5861
  const hasSecureNote = declaredKeys.has(SECURE_NOTE_KEY) || Boolean(item?.fields.some((f) => f.key === SECURE_NOTE_KEY)) || draft.secrets.some((x) => x.key === SECURE_NOTE_KEY);
5784
- const [settingsToggled, setSettingsToggled] = useState25(/* @__PURE__ */ new Set());
5862
+ const [settingsToggled, setSettingsToggled] = useState26(/* @__PURE__ */ new Set());
5785
5863
  const settingsOpen = (f) => settingsToggled.has(f.key) !== (definition?.key === ENV_VALUE_KEY || hasDeclaredSettings(draft.fieldSettings?.[f.key], f.handling));
5786
5864
  const toggleSettings = (key) => setSettingsToggled((cur) => {
5787
5865
  const next = new Set(cur);
@@ -6158,8 +6236,8 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
6158
6236
  const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
6159
6237
  const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
6160
6238
  const ordered = [...pinned, ...rest];
6161
- const listRef = useRef13(null);
6162
- useEffect15(() => {
6239
+ const listRef = useRef14(null);
6240
+ useEffect16(() => {
6163
6241
  if (selectedId) listRef.current?.querySelector(`[data-item="${selectedId}"]`)?.scrollIntoView({ block: "nearest" });
6164
6242
  }, [selectedId, items.length]);
6165
6243
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -6222,8 +6300,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6222
6300
  const confirmed = useConfirmed();
6223
6301
  const copy = useCopy();
6224
6302
  const notify = useNotify();
6225
- const [busy, setBusy] = useState26(false);
6226
- const [menuOpen, setMenuOpen] = useState26(false);
6303
+ const [busy, setBusy] = useState27(false);
6304
+ const [menuOpen, setMenuOpen] = useState27(false);
6227
6305
  const canUse = item.capabilities.canUse;
6228
6306
  const user = canUse ? item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active !== false) : void 0;
6229
6307
  const secret = canUse && item.capabilities.canReveal ? item.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active !== false) : void 0;
@@ -6262,7 +6340,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6262
6340
  ...manageEntries(item, onAction),
6263
6341
  ...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
6264
6342
  ];
6265
- const entriesRef = useRef13(entries);
6343
+ const entriesRef = useRef14(entries);
6266
6344
  entriesRef.current = entries;
6267
6345
  const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ jsx25(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ jsx25(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ jsx25(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ jsx25(StarGlyph, { className: cn11("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ jsx25(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" || e.kind === "manage" ? null : /* @__PURE__ */ jsx25(CopyIcon7, { className: "size-4" });
6268
6346
  const menuItem = (e) => /* @__PURE__ */ jsxs23(DropdownMenuItem4, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
@@ -6285,21 +6363,25 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6285
6363
  {
6286
6364
  type: "button",
6287
6365
  "aria-current": on ? "true" : void 0,
6288
- "data-surface": on ? "primary" : void 0,
6366
+ selected: on,
6367
+ selectedStyle: "primary",
6289
6368
  onClick: () => onSelect(item.id),
6290
6369
  layout: "row",
6291
6370
  variant: "quiet",
6371
+ endInset: "control",
6372
+ oneLine: true,
6292
6373
  icon: /* @__PURE__ */ jsx25(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
6293
6374
  title: item.name,
6294
6375
  line: subtitleOf(item, withOwner),
6295
- className: "w-full pr-10"
6376
+ className: "w-full"
6296
6377
  }
6297
6378
  ),
6298
6379
  /* @__PURE__ */ jsxs23("div", { className: "absolute right-1.5 top-1/2 flex -translate-y-1/2 items-center gap-0.5", "data-surface": on ? "primary" : void 0, children: [
6299
- user || secret || favorite ? /* @__PURE__ */ jsxs23("div", { className: cn11("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
6380
+ user || secret || code || favorite ? /* @__PURE__ */ jsxs23("div", { className: cn11("hidden items-center gap-0.5 rounded-md pl-2 [@media(hover:hover)]:group-hover:flex [@media(hover:hover)]:group-focus-within:flex", on ? "bg-primary" : "bg-accent"), "data-row-quick": "", children: [
6300
6381
  favorite ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx25(StarGlyph, { className: favorite.on ? "fill-current text-warning" : "" }), "aria-label": favorite.on ? "Remove from favorites" : "Add to favorites", "aria-pressed": favorite.on, onClick: favorite.toggle }) : null,
6301
6382
  user ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx25(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
6302
- secret ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx25(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
6383
+ secret ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx25(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null,
6384
+ code ? /* @__PURE__ */ jsx25(Button22, { variant: "quiet", icon: /* @__PURE__ */ jsx25(ClockGlyph, {}), "aria-label": "Copy one-time code", disabled: busy, onClick: copyCode }) : null
6303
6385
  ] }) : null,
6304
6386
  /* @__PURE__ */ jsxs23(DropdownMenu4, { open: menuOpen, onOpenChange: setMenuOpen, children: [
6305
6387
  /* @__PURE__ */ jsx25(DropdownMenuTrigger4, { asChild: true, children: /* @__PURE__ */ jsx25(
@@ -6340,7 +6422,7 @@ function manageEntries(item, onAction) {
6340
6422
  }
6341
6423
 
6342
6424
  // src/lists/TrashView.tsx
6343
- import { useState as useState28 } from "react";
6425
+ import { useState as useState29 } from "react";
6344
6426
  import { Button as Button24 } from "@ai-matrx/design-system/controls";
6345
6427
  import { formatAbsoluteDate as formatAbsoluteDate4 } from "@ai-matrx/kit/format";
6346
6428
 
@@ -6414,7 +6496,7 @@ function refusalText(reason) {
6414
6496
  }
6415
6497
 
6416
6498
  // src/lists/RestorePanel.tsx
6417
- import { useEffect as useEffect16, useState as useState27 } from "react";
6499
+ import { useEffect as useEffect17, useState as useState28 } from "react";
6418
6500
  import { Button as Button23 } from "@ai-matrx/design-system/controls";
6419
6501
  import { Fragment as Fragment18, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
6420
6502
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
@@ -6425,13 +6507,13 @@ function RestorePanel({
6425
6507
  turnOn,
6426
6508
  onClose
6427
6509
  }) {
6428
- const [preview, setPreview] = useState27(null);
6429
- const [restored, setRestored] = useState27(null);
6430
- const [turnedOn, setTurnedOn] = useState27(null);
6431
- const [error, setError] = useState27(null);
6432
- const [busy, setBusy] = useState27(false);
6433
- const [loading, setLoading] = useState27(Boolean(lists.preview));
6434
- useEffect16(() => {
6510
+ const [preview, setPreview] = useState28(null);
6511
+ const [restored, setRestored] = useState28(null);
6512
+ const [turnedOn, setTurnedOn] = useState28(null);
6513
+ const [error, setError] = useState28(null);
6514
+ const [busy, setBusy] = useState28(false);
6515
+ const [loading, setLoading] = useState28(Boolean(lists.preview));
6516
+ useEffect17(() => {
6435
6517
  if (!lists.preview) return;
6436
6518
  let live = true;
6437
6519
  lists.preview(item).then(
@@ -6535,10 +6617,10 @@ function trashLineOf(item) {
6535
6617
  }
6536
6618
  function TrashView({ port, deleted, query, header, onChanged }) {
6537
6619
  const confirmed = useConfirmed();
6538
- const [busyId, setBusyId] = useState28(null);
6539
- const [message2, setMessage] = useState28(null);
6620
+ const [busyId, setBusyId] = useState29(null);
6621
+ const [message2, setMessage] = useState29(null);
6540
6622
  const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
6541
- const [restoring, setRestoring] = useState28(null);
6623
+ const [restoring, setRestoring] = useState29(null);
6542
6624
  const restore = async (item, deletionId) => {
6543
6625
  setBusyId(item.id);
6544
6626
  setMessage(null);
@@ -6586,12 +6668,12 @@ function TrashView({ port, deleted, query, header, onChanged }) {
6586
6668
  }
6587
6669
 
6588
6670
  // src/NewItemFlow.tsx
6589
- import { useMemo as useMemo4, useState as useState29 } from "react";
6671
+ import { useMemo as useMemo4, useState as useState30 } from "react";
6590
6672
  import { Button as Button25, Field as Field10, SearchField as SearchField2, Tile as Tile4 } from "@ai-matrx/design-system/controls";
6591
6673
  import { GlobeIcon as GlobeIcon2 } from "@ai-matrx/design-system/icons";
6592
6674
  import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
6593
6675
  function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6594
- const [search, setSearch] = useState29("");
6676
+ const [search, setSearch] = useState30("");
6595
6677
  const guess = useMemo4(() => inferFromUrl(url, definitions), [url, definitions]);
6596
6678
  const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
6597
6679
  const matches = useMemo4(() => {
@@ -6665,7 +6747,7 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
6665
6747
  }
6666
6748
 
6667
6749
  // src/sharing/SecureLinkPanel.tsx
6668
- import { useEffect as useEffect17, useRef as useRef14, useState as useState30 } from "react";
6750
+ import { useEffect as useEffect18, useRef as useRef15, useState as useState31 } from "react";
6669
6751
  import { confirm as confirm11 } from "@ai-matrx/kit/confirm-opener";
6670
6752
  import { Checkbox as Checkbox2 } from "@ai-matrx/design-system";
6671
6753
  import { Badge as Badge8, Button as Button26, Field as Field11, RegionSkeleton as RegionSkeleton2, SegmentedControl as SegmentedControl6, Textarea as Textarea4 } from "@ai-matrx/design-system/controls";
@@ -6748,20 +6830,20 @@ import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
6748
6830
  function SecureLinkPanel({ item, port, onClose }) {
6749
6831
  const sharing = port.sharing;
6750
6832
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
6751
- const [remedy, setRemedy] = useState30(null);
6752
- const [options, setOptions] = useState30(null);
6753
- const [optionsError, setOptionsError] = useState30(null);
6754
- const [sent, setSent] = useState30(null);
6755
- const [sentError, setSentError] = useState30(null);
6756
- const [nonce, setNonce] = useState30(0);
6757
- const [email, setEmail] = useState30("");
6758
- const [phone, setPhone] = useState30("");
6759
- const [name, setName] = useState30("");
6760
- const [linkBy, setLinkBy] = useState30("email");
6761
- const [fields, setFields] = useState30([]);
6762
- const [note, setNote] = useState30("");
6763
- const [sameChannelSent, setSameChannelSent] = useState30(false);
6764
- useEffect17(() => {
6833
+ const [remedy, setRemedy] = useState31(null);
6834
+ const [options, setOptions] = useState31(null);
6835
+ const [optionsError, setOptionsError] = useState31(null);
6836
+ const [sent, setSent] = useState31(null);
6837
+ const [sentError, setSentError] = useState31(null);
6838
+ const [nonce, setNonce] = useState31(0);
6839
+ const [email, setEmail] = useState31("");
6840
+ const [phone, setPhone] = useState31("");
6841
+ const [name, setName] = useState31("");
6842
+ const [linkBy, setLinkBy] = useState31("email");
6843
+ const [fields, setFields] = useState31([]);
6844
+ const [note, setNote] = useState31("");
6845
+ const [sameChannelSent, setSameChannelSent] = useState31(false);
6846
+ useEffect18(() => {
6765
6847
  let live = true;
6766
6848
  setOptionsError(null);
6767
6849
  sharing.secureLinkOptions(item).then(
@@ -6776,7 +6858,7 @@ function SecureLinkPanel({ item, port, onClose }) {
6776
6858
  live = false;
6777
6859
  };
6778
6860
  }, [sharing, item]);
6779
- useEffect17(() => {
6861
+ useEffect18(() => {
6780
6862
  const list = sharing.sentSecureLinks;
6781
6863
  if (!list) return;
6782
6864
  let live = true;
@@ -6789,9 +6871,9 @@ function SecureLinkPanel({ item, port, onClose }) {
6789
6871
  live = false;
6790
6872
  };
6791
6873
  }, [sharing, item, nonce]);
6792
- const [phoneTyped, setPhoneTyped] = useState30(false);
6793
- const prefilled = useRef14(false);
6794
- useEffect17(() => {
6874
+ const [phoneTyped, setPhoneTyped] = useState31(false);
6875
+ const prefilled = useRef15(false);
6876
+ useEffect18(() => {
6795
6877
  const lookup = sharing.phoneOnFile;
6796
6878
  if (!lookup || phoneTyped) return;
6797
6879
  const clear = () => {
@@ -6944,7 +7026,7 @@ function sentMeta(row, options) {
6944
7026
  }
6945
7027
 
6946
7028
  // src/devices/DevicesPanel.tsx
6947
- import { useCallback as useCallback3, useEffect as useEffect18, useState as useState31 } from "react";
7029
+ import { useCallback as useCallback3, useEffect as useEffect19, useState as useState32 } from "react";
6948
7030
  import { confirm as confirm12 } from "@ai-matrx/kit/confirm-opener";
6949
7031
  import { Button as Button27, RegionSkeleton as RegionSkeleton3 } from "@ai-matrx/design-system/controls";
6950
7032
  import { formatAbsoluteDate as formatAbsoluteDate6 } from "@ai-matrx/kit/format";
@@ -7035,9 +7117,9 @@ function ErrorLine2({ text }) {
7035
7117
  function DevicesPanel({ port, onClose }) {
7036
7118
  const confirmed = useConfirmed();
7037
7119
  const notify = useNotify();
7038
- const [devices, setDevices] = useState31(null);
7039
- const [error, setError] = useState31(null);
7040
- const [busyId, setBusyId] = useState31(null);
7120
+ const [devices, setDevices] = useState32(null);
7121
+ const [error, setError] = useState32(null);
7122
+ const [busyId, setBusyId] = useState32(null);
7041
7123
  const load = useCallback3(async () => {
7042
7124
  setError(null);
7043
7125
  try {
@@ -7046,7 +7128,7 @@ function DevicesPanel({ port, onClose }) {
7046
7128
  setError(messageOf3(e, "Your browsers could not be read."));
7047
7129
  }
7048
7130
  }, [port]);
7049
- useEffect18(() => {
7131
+ useEffect19(() => {
7050
7132
  void load();
7051
7133
  }, [load]);
7052
7134
  const revoke = async (device) => {
@@ -7104,10 +7186,10 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7104
7186
  const where = isMac ? "the Mac app" : "the extension";
7105
7187
  const passkeys = port.devices.passkeys;
7106
7188
  const here = passkeys?.available() ?? false;
7107
- const [methods, setMethods] = useState31(null);
7108
- const [busy, setBusy] = useState31(null);
7109
- const [error, setError] = useState31(null);
7110
- const [approvedUntil, setApprovedUntil] = useState31(null);
7189
+ const [methods, setMethods] = useState32(null);
7190
+ const [busy, setBusy] = useState32(null);
7191
+ const [error, setError] = useState32(null);
7192
+ const [approvedUntil, setApprovedUntil] = useState32(null);
7111
7193
  const load = useCallback3(async () => {
7112
7194
  setError(null);
7113
7195
  try {
@@ -7116,7 +7198,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7116
7198
  setError(messageOf3(e, "Your account could not be checked."));
7117
7199
  }
7118
7200
  }, [port]);
7119
- useEffect18(() => {
7201
+ useEffect19(() => {
7120
7202
  if (key && here) void load();
7121
7203
  }, [key, here, load]);
7122
7204
  const approve = async () => {
@@ -7204,7 +7286,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7204
7286
  }
7205
7287
 
7206
7288
  // src/native/NativeImportPanel.tsx
7207
- import { useEffect as useEffect20, useMemo as useMemo5, useState as useState33 } from "react";
7289
+ import { useEffect as useEffect21, useMemo as useMemo5, useState as useState34 } from "react";
7208
7290
  import { confirm as confirm13 } from "@ai-matrx/kit/confirm-opener";
7209
7291
  import { Badge as Badge9, Button as Button28, Select as Select10 } from "@ai-matrx/design-system/controls";
7210
7292
 
@@ -7267,19 +7349,19 @@ async function loadFullPreview(bridge, operationId, current) {
7267
7349
  }
7268
7350
 
7269
7351
  // src/native/use-native-import.ts
7270
- import { useEffect as useEffect19, useRef as useRef15, useState as useState32 } from "react";
7352
+ import { useEffect as useEffect20, useRef as useRef16, useState as useState33 } from "react";
7271
7353
  var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
7272
7354
  var RESTART = "Your account changed. The import was stopped; start it again.";
7273
7355
  function useNativeImport(bridge, stillAllowed, onImported) {
7274
- const [screen, setScreen] = useState32({ kind: "idle", message: null });
7275
- const [busy, setBusy] = useState32(false);
7276
- const generation = useRef15(0);
7277
- const mounted = useRef15(false);
7278
- const op = useRef15(null);
7279
- const last = useRef15(null);
7280
- const timer2 = useRef15(null);
7281
- const polls = useRef15(0);
7282
- const refreshRef = useRef15(async () => void 0);
7356
+ const [screen, setScreen] = useState33({ kind: "idle", message: null });
7357
+ const [busy, setBusy] = useState33(false);
7358
+ const generation = useRef16(0);
7359
+ const mounted = useRef16(false);
7360
+ const op = useRef16(null);
7361
+ const last = useRef16(null);
7362
+ const timer2 = useRef16(null);
7363
+ const polls = useRef16(0);
7364
+ const refreshRef = useRef16(async () => void 0);
7283
7365
  const current = (g) => mounted.current && g === generation.current;
7284
7366
  const stopPolling = () => {
7285
7367
  if (timer2.current !== null) clearTimeout(timer2.current);
@@ -7448,9 +7530,9 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7448
7530
  setBusy(false);
7449
7531
  setScreen({ kind: "idle", message: null });
7450
7532
  };
7451
- const invalidateRef = useRef15(invalidate);
7533
+ const invalidateRef = useRef16(invalidate);
7452
7534
  invalidateRef.current = invalidate;
7453
- useEffect19(() => {
7535
+ useEffect20(() => {
7454
7536
  mounted.current = true;
7455
7537
  const off = bridge.subscribe?.(() => {
7456
7538
  if (op.current) invalidateRef.current(RESTART);
@@ -7483,13 +7565,13 @@ function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizat
7483
7565
  }
7484
7566
  function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
7485
7567
  const options = useMemo5(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
7486
- const [organizationId, setOrganizationId] = useState33(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7487
- const [limits, setLimits] = useState33(null);
7488
- const [limitError, setLimitError] = useState33(null);
7568
+ const [organizationId, setOrganizationId] = useState34(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7569
+ const [limits, setLimits] = useState34(null);
7570
+ const [limitError, setLimitError] = useState34(null);
7489
7571
  const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
7490
7572
  const { screen, busy } = flow;
7491
7573
  const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
7492
- useEffect20(() => {
7574
+ useEffect21(() => {
7493
7575
  if (!readLimits || !organizationId) return;
7494
7576
  let live = true;
7495
7577
  setLimits(null);
@@ -7550,21 +7632,21 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
7550
7632
  }
7551
7633
 
7552
7634
  // src/extension/PageView.tsx
7553
- import { useState as useState37 } from "react";
7635
+ import { useState as useState38 } from "react";
7554
7636
  import { SiteIcon } from "@ai-matrx/design-system";
7555
7637
  import { Button as Button32, Tile as Tile5 } from "@ai-matrx/design-system/controls";
7556
7638
  import { GlobeIcon as GlobeIcon3 } from "@ai-matrx/design-system/icons";
7557
7639
 
7558
7640
  // src/extension/CaptureCard.tsx
7559
- import { useState as useState34, useSyncExternalStore as useSyncExternalStore3 } from "react";
7641
+ import { useState as useState35, useSyncExternalStore as useSyncExternalStore3 } from "react";
7560
7642
  import { Button as Button29, SearchField as SearchField3 } from "@ai-matrx/design-system/controls";
7561
7643
  import { Fragment as Fragment21, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
7562
7644
  var SEARCH_FROM = 4;
7563
7645
  function CaptureCard({ capture, onChanged }) {
7564
7646
  const prompt = useSyncExternalStore3(capture.subscribe, capture.get, capture.get);
7565
7647
  const notify = useNotify();
7566
- const [busy, setBusy] = useState34(false);
7567
- const [q, setQ] = useState34("");
7648
+ const [busy, setBusy] = useState35(false);
7649
+ const [q, setQ] = useState35("");
7568
7650
  if (!prompt) return null;
7569
7651
  const decide = async (d) => {
7570
7652
  setBusy(true);
@@ -7620,15 +7702,15 @@ function CaptureCard({ capture, onChanged }) {
7620
7702
  }
7621
7703
 
7622
7704
  // src/extension/FillSetupCard.tsx
7623
- import { useRef as useRef16, useState as useState35, useSyncExternalStore as useSyncExternalStore4 } from "react";
7705
+ import { useRef as useRef17, useState as useState36, useSyncExternalStore as useSyncExternalStore4 } from "react";
7624
7706
  import { Button as Button30, Field as Field12 } from "@ai-matrx/design-system/controls";
7625
7707
  import { jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
7626
7708
  function FillSetupCard({ fillSetup }) {
7627
7709
  const notify = useNotify();
7628
7710
  const state = useSyncExternalStore4(fillSetup.subscribe, fillSetup.get, fillSetup.get);
7629
- const box = useRef16(null);
7630
- const [busy, setBusy] = useState35(false);
7631
- const [error, setError] = useState35(null);
7711
+ const box = useRef17(null);
7712
+ const [busy, setBusy] = useState36(false);
7713
+ const [error, setError] = useState36(null);
7632
7714
  if (state.status !== "off") return null;
7633
7715
  const finish = async (run) => {
7634
7716
  setBusy(true);
@@ -7693,7 +7775,7 @@ function FillSetupCard({ fillSetup }) {
7693
7775
  }
7694
7776
 
7695
7777
  // src/extension/PageGenerator.tsx
7696
- import { useState as useState36 } from "react";
7778
+ import { useState as useState37 } from "react";
7697
7779
  import { Popover as Popover2, PopoverContent as PopoverContent2, PopoverTrigger as PopoverTrigger2 } from "@ai-matrx/design-system";
7698
7780
  import { Button as Button31 } from "@ai-matrx/design-system/controls";
7699
7781
  import { CopyIcon as CopyIcon8 } from "@ai-matrx/design-system/icons";
@@ -7703,10 +7785,10 @@ function PageGenerator({ fields }) {
7703
7785
  const limits = useGeneratorLimitsSource();
7704
7786
  const copy = useCopy();
7705
7787
  const held = useTransientSecret(HOLD_MS);
7706
- const [open, setOpen] = useState36(false);
7707
- const [busy, setBusy] = useState36(false);
7708
- const [targets, setTargets] = useState36([]);
7709
- const [said, setSaid] = useState36(null);
7788
+ const [open, setOpen] = useState37(false);
7789
+ const [busy, setBusy] = useState37(false);
7790
+ const [targets, setTargets] = useState37([]);
7791
+ const [said, setSaid] = useState37(null);
7710
7792
  if (!limits) return null;
7711
7793
  const say3 = setSaid;
7712
7794
  const put = async (targetId, value2) => {
@@ -7770,8 +7852,8 @@ function PageGenerator({ fields }) {
7770
7852
  // src/extension/PageView.tsx
7771
7853
  import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
7772
7854
  function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
7773
- const [running, setRunning] = useState37(null);
7774
- const [said, setSaid] = useState37(null);
7855
+ const [running, setRunning] = useState38(null);
7856
+ const [said, setSaid] = useState38(null);
7775
7857
  const site = pageSite(page.url);
7776
7858
  const state = page.matchState ?? { status: "ready" };
7777
7859
  const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
@@ -7780,8 +7862,8 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
7780
7862
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
7781
7863
  const canSave = isFillablePage(page.url);
7782
7864
  const signIn = page.signIn;
7783
- const act = async (itemId, run, failed) => {
7784
- setRunning(itemId);
7865
+ const act = async (itemId, action, run, failed) => {
7866
+ setRunning({ itemId, action });
7785
7867
  setSaid(null);
7786
7868
  try {
7787
7869
  setSaid(await run());
@@ -7814,10 +7896,10 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
7814
7896
  family: item ? familyOf2(item.definitionKey) : "generic",
7815
7897
  port,
7816
7898
  busy: running !== null,
7817
- running: running === itemId,
7899
+ running: running?.itemId === itemId ? running.action : null,
7818
7900
  onOpen,
7819
- onFill: fill && !page.blocked && fillable.has(itemId) && item?.capabilities.canUse !== false ? () => void act(itemId, async () => FILL_WORDS[await fill(itemId)], FILL_WORDS.unavailable) : null,
7820
- onSignIn: signIn ? () => void act(itemId, async () => SIGN_IN_WORDS[await signIn(itemId)], SIGN_IN_WORDS.unknown) : null
7901
+ onFill: fill && !page.blocked && fillable.has(itemId) && item?.capabilities.canUse !== false ? () => void act(itemId, "fill", async () => FILL_WORDS[await fill(itemId)], FILL_WORDS.unavailable) : null,
7902
+ onSignIn: signIn ? () => void act(itemId, "signIn", async () => SIGN_IN_WORDS[await signIn(itemId)], SIGN_IN_WORDS.unknown) : null
7821
7903
  },
7822
7904
  itemId
7823
7905
  )) });
@@ -7855,7 +7937,7 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7855
7937
  const confirmed = useConfirmed();
7856
7938
  const copy = useCopy();
7857
7939
  const notify = useNotify();
7858
- const [reading, setReading] = useState37(false);
7940
+ const [reading, setReading] = useState38(false);
7859
7941
  const usable = item?.capabilities.canUse ?? false;
7860
7942
  const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
7861
7943
  const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
@@ -7884,8 +7966,8 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7884
7966
  className: "min-w-0 flex-1"
7885
7967
  }
7886
7968
  ),
7887
- onFill ? /* @__PURE__ */ jsx35(Button32, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
7888
- onSignIn ? /* @__PURE__ */ jsx35(Button32, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ jsx35(ShieldGlyph, {}), disabled: busy, onClick: onSignIn, "aria-label": `Sign me in with ${item?.name ?? "this login"}`, title: "Sign me in", children: "Sign me in" }) : null,
7969
+ onFill ? /* @__PURE__ */ jsx35(Button32, { variant: "primary", disabled: busy, "aria-busy": running === "fill" || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running === "fill" ? "Filling\u2026" : "Fill" }) : null,
7970
+ onSignIn ? /* @__PURE__ */ jsx35(Button32, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ jsx35(ShieldGlyph, {}), disabled: busy, "aria-busy": running === "signIn" || void 0, onClick: onSignIn, "aria-label": `Sign me in with ${item?.name ?? "this login"}`, title: "Sign me in", children: running === "signIn" ? "Signing in\u2026" : "Sign me in" }) : null,
7889
7971
  user && item ? /* @__PURE__ */ jsx35(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx35(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
7890
7972
  secret && item ? /* @__PURE__ */ jsx35(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx35(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
7891
7973
  otp ? /* @__PURE__ */ jsx35(Button32, { variant: "quiet", icon: /* @__PURE__ */ jsx35(ClockGlyph, {}), "aria-label": "Copy one-time code", title: "Copy one-time code", disabled: reading, onClick: () => void read("One-time code", async () => (await port.authenticator.code(otp)).code) }) : null
@@ -7893,8 +7975,8 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
7893
7975
  }
7894
7976
 
7895
7977
  // src/Sidebar.tsx
7896
- import { useState as useState38 } from "react";
7897
- import { cn as cn12 } from "@ai-matrx/design-system";
7978
+ import { useState as useState39 } from "react";
7979
+ import { cn as cn12, useLook as useLook2 } from "@ai-matrx/design-system";
7898
7980
  import { DisclosureHeader as DisclosureHeader4, Select as Select11, Tile as Tile6 } from "@ai-matrx/design-system/controls";
7899
7981
  import { GlobeIcon as GlobeIcon4 } from "@ai-matrx/design-system/icons";
7900
7982
  import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
@@ -7902,6 +7984,7 @@ var AUTHENTICATOR_LABEL = "Authenticator";
7902
7984
  function vaultChoices(items, organizations, _current) {
7903
7985
  const n = (f) => items.filter(f).length;
7904
7986
  const shared = n((i) => i.owner.kind === "shared");
7987
+ const hints = organizationHints(organizations);
7905
7988
  return [
7906
7989
  { value: "all", label: "All items", count: items.length },
7907
7990
  { value: "mine", label: "Personal", count: n((i) => i.owner.kind === "me") },
@@ -7909,11 +7992,11 @@ function vaultChoices(items, organizations, _current) {
7909
7992
  // Every organization the person belongs to, empty ones too: an empty vault opens on its own
7910
7993
  // "Nothing here yet" with New item, so the first credential can go there. (The organization
7911
7994
  // list carries no role, so who may add is the server's answer to the save, said in place.)
7912
- ...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id) }))
7995
+ ...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id), ...hints.has(o.id) ? { hint: hints.get(o.id) } : {} }))
7913
7996
  ];
7914
7997
  }
7915
- function VaultSelect({ value, choices, onChange }) {
7916
- return /* @__PURE__ */ jsx36(Select11, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
7998
+ function VaultSelect({ value, choices, onChange, searchAt = ORGANIZATION_SEARCH_AT_UNREAD }) {
7999
+ return /* @__PURE__ */ jsx36(Select11, { value, onValueChange: onChange, "aria-label": "Vault", searchAt, options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count), ...c.hint ? { hint: c.hint } : {} })) });
7917
8000
  }
7918
8001
  var CATEGORY_GLYPHS = { logins: GlobeIcon4, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
7919
8002
  var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -7977,12 +8060,14 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
7977
8060
  ];
7978
8061
  }
7979
8062
  function Entry({ on, glyph: Icon, label, count: count2, onClick, nested = false }) {
8063
+ const desktop = useLook2() === "desktop";
7980
8064
  return /* @__PURE__ */ jsx36(
7981
8065
  Tile6,
7982
8066
  {
7983
8067
  type: "button",
7984
8068
  "aria-current": on ? "page" : void 0,
7985
8069
  selected: on,
8070
+ ...desktop ? { selectedStyle: "fill" } : {},
7986
8071
  onClick,
7987
8072
  layout: "row",
7988
8073
  variant: "quiet",
@@ -7990,8 +8075,9 @@ function Entry({ on, glyph: Icon, label, count: count2, onClick, nested = false
7990
8075
  icon: nested ? void 0 : /* @__PURE__ */ jsx36(Icon, { className: "size-4 shrink-0" }),
7991
8076
  title: label,
7992
8077
  ...count2 !== void 0 ? { end: /* @__PURE__ */ jsx36("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) } : {},
8078
+ ...nested ? { level: 1 } : {},
7993
8079
  "data-nested": nested ? "" : void 0,
7994
- className: cn12("w-full", nested && "pl-9")
8080
+ className: "w-full"
7995
8081
  }
7996
8082
  );
7997
8083
  }
@@ -8001,12 +8087,12 @@ function Group({ title, children }) {
8001
8087
  children
8002
8088
  ] });
8003
8089
  }
8004
- function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
8005
- const [tagsOpen, setTagsOpen] = useState38(view.startsWith("tag:"));
8090
+ function VaultSidebar({ vault, choices, onVault, organizationSearchAt, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
8091
+ const [tagsOpen, setTagsOpen] = useState39(view.startsWith("tag:"));
8006
8092
  return /* @__PURE__ */ jsxs34("nav", { "aria-label": "Vault", className: "flex h-full min-h-0 flex-col border-r border-sidebar-border bg-sidebar-background text-sidebar-foreground", children: [
8007
8093
  /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
8008
8094
  /* @__PURE__ */ jsx36(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
8009
- /* @__PURE__ */ jsx36("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx36(VaultSelect, { value: vault, choices, onChange: onVault }) })
8095
+ /* @__PURE__ */ jsx36("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx36(VaultSelect, { value: vault, choices, onChange: onVault, searchAt: organizationSearchAt }) })
8010
8096
  ] }),
8011
8097
  /* @__PURE__ */ jsxs34("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
8012
8098
  /* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-0.5", children: [
@@ -8083,8 +8169,8 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
8083
8169
  } : void 0;
8084
8170
  function ImportWithLimits(props) {
8085
8171
  const { knobs, ...rest } = props;
8086
- const [state, setState] = useState39(null);
8087
- useEffect21(() => {
8172
+ const [state, setState] = useState40(null);
8173
+ useEffect22(() => {
8088
8174
  if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
8089
8175
  knobs().then(
8090
8176
  (r) => {
@@ -8109,13 +8195,13 @@ function VaultApp(given) {
8109
8195
  }
8110
8196
  function useOrganizationSettings(host) {
8111
8197
  const knobs = host.knobs;
8112
- const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
8113
- const [read, setRead] = useState39(null);
8114
- useEffect21(() => {
8198
+ const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0 || host.organizationSearchAt === void 0);
8199
+ const [read, setRead] = useState40(null);
8200
+ useEffect22(() => {
8115
8201
  if (!needs || !knobs) return;
8116
8202
  let live = true;
8117
8203
  knobs().then(
8118
- (r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
8204
+ (r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB), searchAt: positiveKnob(r, ORGANIZATION_SEARCH_AT_KNOB) }),
8119
8205
  () => void 0
8120
8206
  );
8121
8207
  return () => {
@@ -8126,7 +8212,8 @@ function useOrganizationSettings(host) {
8126
8212
  return {
8127
8213
  ...host,
8128
8214
  ...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
8129
- ...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
8215
+ ...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {},
8216
+ ...host.organizationSearchAt === void 0 && read.searchAt !== null ? { organizationSearchAt: read.searchAt } : {}
8130
8217
  };
8131
8218
  }
8132
8219
  var NO_STORE = () => () => void 0;
@@ -8137,8 +8224,8 @@ function useHostPrompts(capture, fillSetup) {
8137
8224
  return prompt !== null || setup?.status === "off";
8138
8225
  }
8139
8226
  function LockedScreen({ lock }) {
8140
- const [busy, setBusy] = useState39(false);
8141
- const [error, setError] = useState39(null);
8227
+ const [busy, setBusy] = useState40(false);
8228
+ const [error, setError] = useState40(null);
8142
8229
  const unlock = async () => {
8143
8230
  setBusy(true);
8144
8231
  setError(null);
@@ -8158,21 +8245,21 @@ function LockedScreen({ lock }) {
8158
8245
  ] });
8159
8246
  }
8160
8247
  function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
8161
- const rootRef = useRef17(null);
8248
+ const rootRef = useRef18(null);
8162
8249
  const width = useElementWidth(rootRef);
8163
8250
  const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
8164
8251
  const notify = useNotify();
8165
- const [snap, setSnap] = useState39(null);
8166
- const [items, setItems] = useState39([]);
8167
- const [deleted, setDeleted] = useState39([]);
8168
- const [favorites, setFavorites] = useState39(null);
8169
- const [recents, setRecents] = useState39(null);
8170
- const [error, setError] = useState39(null);
8171
- const [inner, setInner] = useState39(DEFAULT_LOCATION);
8252
+ const [snap, setSnap] = useState40(null);
8253
+ const [items, setItems] = useState40([]);
8254
+ const [deleted, setDeleted] = useState40([]);
8255
+ const [favorites, setFavorites] = useState40(null);
8256
+ const [recents, setRecents] = useState40(null);
8257
+ const [error, setError] = useState40(null);
8258
+ const [inner, setInner] = useState40(DEFAULT_LOCATION);
8172
8259
  const loc = location ?? inner;
8173
- const dirty = useRef17(false);
8174
- const [notice, setNotice] = useState39(null);
8175
- const [firstCode, setFirstCode] = useState39(null);
8260
+ const dirty = useRef18(false);
8261
+ const [notice, setNotice] = useState40(null);
8262
+ const [firstCode, setFirstCode] = useShownUntilMove(loc);
8176
8263
  const move = useCallback4(
8177
8264
  (next, how) => {
8178
8265
  if (!location) setInner(next);
@@ -8199,9 +8286,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8199
8286
  },
8200
8287
  [loc, move]
8201
8288
  );
8202
- const keyState = useRef17({ loc, go });
8289
+ const keyState = useRef18({ loc, go });
8203
8290
  keyState.current = { loc, go };
8204
- useEffect21(() => {
8291
+ useEffect22(() => {
8205
8292
  const onKey = (e) => {
8206
8293
  if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
8207
8294
  const root = rootRef.current;
@@ -8223,8 +8310,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8223
8310
  document.addEventListener("keydown", onKey);
8224
8311
  return () => document.removeEventListener("keydown", onKey);
8225
8312
  }, []);
8226
- const keepSearchFocus = useRef17(false);
8227
- useEffect21(() => {
8313
+ const keepSearchFocus = useRef18(false);
8314
+ useEffect22(() => {
8228
8315
  if (!keepSearchFocus.current) return;
8229
8316
  keepSearchFocus.current = false;
8230
8317
  const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
@@ -8233,13 +8320,13 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8233
8320
  search.setSelectionRange(search.value.length, search.value.length);
8234
8321
  }, [loc.q]);
8235
8322
  const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
8236
- const knobsRef = useRef17(host.knobs);
8323
+ const knobsRef = useRef18(host.knobs);
8237
8324
  knobsRef.current = host.knobs;
8238
- const [signedOut, setSignedOut] = useState39(false);
8239
- const [refreshError, setRefreshError] = useState39(null);
8240
- const [refreshing, setRefreshing] = useState39(false);
8241
- const loadedAt = useRef17(0);
8242
- const inFlight = useRef17(false);
8325
+ const [signedOut, setSignedOut] = useState40(false);
8326
+ const [refreshError, setRefreshError] = useState40(null);
8327
+ const [refreshing, setRefreshing] = useState40(false);
8328
+ const loadedAt = useRef18(0);
8329
+ const inFlight = useRef18(false);
8243
8330
  const apply = useCallback4(
8244
8331
  (s) => {
8245
8332
  loadedAt.current = Date.now();
@@ -8287,11 +8374,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8287
8374
  knobsRef.current?.().catch(() => void 0);
8288
8375
  port.lists.recents?.list().then(setRecents, () => void 0);
8289
8376
  }, [port, apply]);
8290
- useEffect21(load, [load]);
8291
- const quietRef = useRef17({ loc, ready: false });
8377
+ useEffect22(load, [load]);
8378
+ const quietRef = useRef18({ loc, ready: false });
8292
8379
  quietRef.current = { loc, ready: snap !== null && !error };
8293
- const [knobSeconds, setKnobSeconds] = useState39(null);
8294
- useEffect21(() => {
8380
+ const [knobSeconds, setKnobSeconds] = useState40(null);
8381
+ useEffect22(() => {
8295
8382
  if (host.refreshSeconds !== void 0 || !knobsRef.current) return;
8296
8383
  let live = true;
8297
8384
  knobsRef.current().then(
@@ -8306,7 +8393,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8306
8393
  };
8307
8394
  }, [host.refreshSeconds]);
8308
8395
  const everySeconds = host.refreshSeconds ?? knobSeconds;
8309
- useEffect21(() => {
8396
+ useEffect22(() => {
8310
8397
  const quietly = (minGapMs) => {
8311
8398
  const { loc: here, ready } = quietRef.current;
8312
8399
  if (!ready || document.visibilityState === "hidden" || dirty.current || here.mode !== "view") return;
@@ -8324,17 +8411,17 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8324
8411
  if (timer2) clearInterval(timer2);
8325
8412
  };
8326
8413
  }, [refresh, everySeconds]);
8327
- const inventoryRef = useRef17(onInventory);
8414
+ const inventoryRef = useRef18(onInventory);
8328
8415
  inventoryRef.current = onInventory;
8329
- useEffect21(() => {
8416
+ useEffect22(() => {
8330
8417
  if (snap) inventoryRef.current?.({ items, definitions: snap.definitions });
8331
8418
  }, [snap, items]);
8332
- useEffect21(() => {
8419
+ useEffect22(() => {
8333
8420
  if (!loc.itemId || !port.lists.recents) return;
8334
8421
  const id = loc.itemId;
8335
8422
  port.lists.recents.record(id).then(() => setRecents((r) => [id, ...(r ?? []).filter((x) => x !== id)]), () => void 0);
8336
8423
  }, [loc.itemId, port]);
8337
- const orgs = snap?.organizations ?? [];
8424
+ const orgs = useMemo6(() => orderOrganizations(snap?.organizations ?? [], items, recents), [snap?.organizations, items, recents]);
8338
8425
  const definitions = snap?.definitions ?? [];
8339
8426
  const inThisVault = useMemo6(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
8340
8427
  const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
@@ -8417,7 +8504,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8417
8504
  const hasFavorites = port.lists.favorites !== void 0;
8418
8505
  const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
8419
8506
  const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ jsxs35("div", { className: "grid grid-cols-[repeat(auto-fit,minmax(11rem,1fr))] gap-2", "data-vault-compact-header": "", children: [
8420
- /* @__PURE__ */ jsx37(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8507
+ /* @__PURE__ */ jsx37(VaultSelect, { value: loc.vault, choices, searchAt: host.organizationSearchAt, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8421
8508
  /* @__PURE__ */ jsx37(Select12, { value: loc.view, onValueChange: (view) => go({ view, itemId: null, panel: null }), options: viewOptions(views, inThisVault.length, deleted.length, hasFavorites, port.lists.recents !== void 0, host.page !== void 0, loc.view), "aria-label": "Show" })
8422
8509
  ] });
8423
8510
  const compactActions = mode === "full" ? void 0 : /* @__PURE__ */ jsxs35("div", { className: "flex shrink-0 items-center gap-2", "data-vault-compact-actions": "", children: [
@@ -8654,6 +8741,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8654
8741
  arg: panelArg ?? null,
8655
8742
  onClose: closePanel,
8656
8743
  onPanel,
8744
+ onOpenItem: (next) => {
8745
+ replaceItem(next);
8746
+ const holds = loc.vault === "all" || loc.vault === "mine" && next.owner.kind === "me" || loc.vault === next.owner.organizationId;
8747
+ go({ ...holds ? {} : { vault: "all" }, itemId: next.id, mode: "view", panel: null });
8748
+ },
8657
8749
  onChanged: (next) => {
8658
8750
  if (next) replaceItem(next);
8659
8751
  else if (next === null) {
@@ -8693,6 +8785,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8693
8785
  vault: loc.vault,
8694
8786
  choices,
8695
8787
  onVault: (vault) => go({ vault, itemId: null, panel: null }),
8788
+ organizationSearchAt: host.organizationSearchAt,
8696
8789
  view: loc.view,
8697
8790
  allCount: inThisVault.length,
8698
8791
  deletedCount: deleted.length,