@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.cjs CHANGED
@@ -179,7 +179,7 @@ __export(src_exports, {
179
179
  module.exports = __toCommonJS(src_exports);
180
180
 
181
181
  // src/VaultApp.tsx
182
- var import_react42 = require("react");
182
+ var import_react43 = require("react");
183
183
  var import_design_system25 = require("@ai-matrx/design-system");
184
184
  var import_controls35 = require("@ai-matrx/design-system/controls");
185
185
  var import_confirm_opener14 = require("@ai-matrx/kit/confirm-opener");
@@ -1362,11 +1362,11 @@ function whenInDay(iso, now = /* @__PURE__ */ new Date()) {
1362
1362
  if (dayKey(d) === dayKey(now)) return (0, import_format.formatRelativeTime)(iso, { now: now.getTime() });
1363
1363
  return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
1364
1364
  }
1365
- function collapseRuns(rows, keyOf) {
1365
+ function collapseRuns(rows, keyOf2) {
1366
1366
  const out = [];
1367
1367
  const at = /* @__PURE__ */ new Map();
1368
1368
  for (const row of rows) {
1369
- const k = keyOf(row);
1369
+ const k = keyOf2(row);
1370
1370
  const seen = at.get(k);
1371
1371
  if (seen) seen.times += 1;
1372
1372
  else {
@@ -1774,14 +1774,12 @@ function CodeButton({ live, digits, size = "md", label }) {
1774
1774
  disabled: !live.code,
1775
1775
  onClick: () => live.code && void copy(live.code),
1776
1776
  "aria-label": live.code ? `Copy ${label} code` : `Getting ${label} code`,
1777
+ ...live.code ? { tooltip: "Copy code" } : {},
1777
1778
  variant: "quiet",
1778
1779
  layout: "row",
1779
- title: "Copy code",
1780
- end: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: (0, import_design_system8.cn)("inline-flex shrink-0 items-center", size === "lg" ? "gap-4" : "gap-3"), children: [
1781
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: (0, import_design_system8.cn)("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 }),
1782
- copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1783
- ] }),
1784
- className: "max-w-full shrink-0"
1780
+ fit: true,
1781
+ title: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: (0, import_design_system8.cn)("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 }),
1782
+ end: copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex size-6 items-center justify-center text-success", role: "status", "aria-label": "Copied", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckGlyph, { className: "size-4" }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CountdownRing, { remaining: live.remaining, period: live.period, loading: !live.code })
1785
1783
  }
1786
1784
  );
1787
1785
  }
@@ -1891,6 +1889,14 @@ function canDecodeQrLocally() {
1891
1889
  function hasCamera() {
1892
1890
  return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
1893
1891
  }
1892
+ async function hasCameraDevice() {
1893
+ if (!hasCamera() || typeof navigator.mediaDevices?.enumerateDevices !== "function") return false;
1894
+ try {
1895
+ return (await navigator.mediaDevices.enumerateDevices()).some((d) => d.kind === "videoinput");
1896
+ } catch {
1897
+ return false;
1898
+ }
1899
+ }
1894
1900
  async function decodeQr(source) {
1895
1901
  return (0, import_qr.decodeQrFromElement)(source);
1896
1902
  }
@@ -1922,17 +1928,15 @@ function useCanScan() {
1922
1928
  }, []);
1923
1929
  return ok;
1924
1930
  }
1925
- function QrScanPanel({ open, onResult, onClose }) {
1931
+ function QrScanInline({ onResult, onClose }) {
1926
1932
  const video = (0, import_react10.useRef)(null);
1927
1933
  const [error, setError] = (0, import_react10.useState)(null);
1928
1934
  const done = (0, import_react10.useRef)(onResult);
1929
1935
  done.current = onResult;
1930
1936
  (0, import_react10.useEffect)(() => {
1931
- if (!open) return;
1932
1937
  let stream = null;
1933
1938
  let live = true;
1934
1939
  let timer2 = null;
1935
- setError(null);
1936
1940
  const stop = () => {
1937
1941
  if (timer2) clearTimeout(timer2);
1938
1942
  stream?.getTracks().forEach((t) => t.stop());
@@ -1975,13 +1979,26 @@ function QrScanPanel({ open, onResult, onClose }) {
1975
1979
  live = false;
1976
1980
  stop();
1977
1981
  };
1978
- }, [open]);
1979
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Panel, { title: "Scan QR code", open, onClose, size: "sm", footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", onClick: onClose, children: "Cancel" }), children: [
1980
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl bg-muted", children: [
1982
+ }, []);
1983
+ if (error) {
1984
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "flex items-center gap-2 px-1 pt-1 text-xs text-muted-foreground", role: "status", "data-camera-note": "", children: [
1985
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CameraGlyph, { className: "size-3.5 shrink-0", "aria-hidden": true }),
1986
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
1987
+ error,
1988
+ " Paste the setup key or choose a QR image."
1989
+ ] }),
1990
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", onClick: onClose, children: "Dismiss" })
1991
+ ] });
1992
+ }
1993
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center gap-1.5 pt-2", role: "region", "aria-label": "Scan QR code", "data-camera-preview": "", children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative aspect-square w-full max-w-56 overflow-hidden rounded-xl bg-muted", children: [
1981
1995
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("video", { ref: video, className: "size-full object-cover", playsInline: true, muted: true, "aria-label": "Camera" }),
1982
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-destructive", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1996
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "pointer-events-none absolute inset-[18%] rounded-lg border-2 border-primary", "aria-hidden": true })
1983
1997
  ] }),
1984
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "Point at the site's QR code" })
1998
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
1999
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground", children: "Point at the site's QR code" }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_controls6.Button, { variant: "quiet", onClick: onClose, children: "Stop camera" })
2001
+ ] })
1985
2002
  ] });
1986
2003
  }
1987
2004
  function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "Paste setup key or otpauth link", disabled = false, autoFocus = false, onImage, onRecognized, status, autoStartCamera = false }) {
@@ -1991,8 +2008,15 @@ function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "
1991
2008
  const autoStarted = (0, import_react10.useRef)(false);
1992
2009
  (0, import_react10.useEffect)(() => {
1993
2010
  if (!autoStartCamera || !canScan || disabled || autoStarted.current || value) return;
1994
- autoStarted.current = true;
1995
- setScanning(true);
2011
+ let live = true;
2012
+ void hasCameraDevice().then((has) => {
2013
+ if (!live || !has || autoStarted.current) return;
2014
+ autoStarted.current = true;
2015
+ setScanning(true);
2016
+ });
2017
+ return () => {
2018
+ live = false;
2019
+ };
1996
2020
  }, [autoStartCamera, canScan, disabled, value]);
1997
2021
  const [reading, setReading] = (0, import_react10.useState)(false);
1998
2022
  const [imageError, setImageError] = (0, import_react10.useState)(null);
@@ -2094,10 +2118,9 @@ function OtpSetupRow({ value, onChange, label = "Authenticator", placeholder = "
2094
2118
  ]
2095
2119
  }
2096
2120
  ),
2097
- canScan ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2098
- QrScanPanel,
2121
+ canScan && scanning ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2122
+ QrScanInline,
2099
2123
  {
2100
- open: scanning,
2101
2124
  onClose: () => setScanning(false),
2102
2125
  onResult: (text) => {
2103
2126
  setScanning(false);
@@ -2583,7 +2606,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRenam
2583
2606
  const canManage = item.capabilities.canManage || item.capabilities.canEdit;
2584
2607
  if (a.removed) return null;
2585
2608
  const sub = a.error ?? [entry?.account, loginSiteOf(item) || entry?.issuer].filter((v, i, all) => Boolean(v) && all.indexOf(v) === i).join(" \xB7 ");
2586
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
2609
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
2587
2610
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2588
2611
  import_controls9.Button,
2589
2612
  {
@@ -2604,6 +2627,7 @@ function OtpListRow({ port, item, family, entry, onOpen, onOpenInNewTab, onRenam
2604
2627
  onClick: onOpen,
2605
2628
  title: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: a.enabled ? "text-foreground" : "text-muted-foreground", children: item.name }),
2606
2629
  line: sub ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: a.error ? "text-destructive" : "text-muted-foreground", title: sub, children: sub }) : void 0,
2630
+ oneLine: true,
2607
2631
  className: "min-w-0"
2608
2632
  }
2609
2633
  ),
@@ -3207,14 +3231,58 @@ function createVaultKnobs(client, address) {
3207
3231
  }
3208
3232
  var REVEAL_SECONDS_KNOB = "desktop.vault.reveal_hide_seconds";
3209
3233
  var BACKUP_PASSPHRASE_MIN_KNOB = "desktop.vault.backup_passphrase_min_length";
3234
+ var ORGANIZATION_SEARCH_AT_KNOB = "vault.organization_search_at";
3235
+ var ORGANIZATION_SEARCH_AT_UNREAD = 8;
3210
3236
  function positiveKnob(resolved, key) {
3211
3237
  const v = resolved[key];
3212
3238
  const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
3213
3239
  return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
3214
3240
  }
3215
3241
 
3216
- // src/lock.ts
3242
+ // src/organizations.ts
3243
+ var import_record_id_format = require("@ai-matrx/design-system/record-id-format");
3244
+ function orderOrganizations(orgs, items, recentItemIds) {
3245
+ const counts = /* @__PURE__ */ new Map();
3246
+ for (const i of items) if (i.owner.organizationId) counts.set(i.owner.organizationId, (counts.get(i.owner.organizationId) ?? 0) + 1);
3247
+ const byId = new Map(items.map((i) => [i.id, i]));
3248
+ const recent = /* @__PURE__ */ new Map();
3249
+ for (const id of recentItemIds ?? []) {
3250
+ const org = byId.get(id)?.owner.organizationId;
3251
+ if (org && !recent.has(org)) recent.set(org, recent.size);
3252
+ }
3253
+ const group = (o) => recent.has(o.id) ? 0 : (counts.get(o.id) ?? 0) > 0 ? 1 : 2;
3254
+ 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));
3255
+ }
3256
+ function organizationHints(orgs) {
3257
+ const seen = /* @__PURE__ */ new Map();
3258
+ for (const o of orgs) seen.set(o.name.trim().toLowerCase(), (seen.get(o.name.trim().toLowerCase()) ?? 0) + 1);
3259
+ return new Map(orgs.filter((o) => (seen.get(o.name.trim().toLowerCase()) ?? 0) > 1).map((o) => [o.id, (0, import_record_id_format.shortUuid)(o.id)]));
3260
+ }
3261
+
3262
+ // src/shown-until-move.ts
3217
3263
  var import_react16 = require("react");
3264
+ var keyOf = (loc) => `${String(loc.vault)}|${loc.view}|${loc.itemId ?? ""}|${loc.mode}|${loc.panel ?? ""}|${loc.kind ?? ""}`;
3265
+ function useShownUntilMove(loc) {
3266
+ const [shown, setShown] = (0, import_react16.useState)(null);
3267
+ const home = (0, import_react16.useRef)(null);
3268
+ const key = keyOf(loc);
3269
+ (0, import_react16.useEffect)(() => {
3270
+ if (!shown) {
3271
+ home.current = null;
3272
+ return;
3273
+ }
3274
+ if (home.current?.id !== shown.id) home.current = { id: shown.id, key: null };
3275
+ if (home.current.key === null) {
3276
+ if (loc.itemId === shown.id && loc.mode === "view") home.current.key = key;
3277
+ return;
3278
+ }
3279
+ if (key !== home.current.key) setShown(null);
3280
+ }, [shown, key, loc.itemId, loc.mode]);
3281
+ return [shown, setShown];
3282
+ }
3283
+
3284
+ // src/lock.ts
3285
+ var import_react17 = require("react");
3218
3286
  var LOCKED_MESSAGE = "The vault is locked. Unlock it first.";
3219
3287
  var VaultLockedError = class extends Error {
3220
3288
  code = "vault_locked";
@@ -3249,12 +3317,12 @@ function guardPort(port, locked) {
3249
3317
  var NEVER = () => () => void 0;
3250
3318
  var UNLOCKED = () => false;
3251
3319
  function useLocked(lock) {
3252
- return (0, import_react16.useSyncExternalStore)(lock ? lock.subscribe : NEVER, lock ? () => lock.locked() : UNLOCKED, UNLOCKED);
3320
+ return (0, import_react17.useSyncExternalStore)(lock ? lock.subscribe : NEVER, lock ? () => lock.locked() : UNLOCKED, UNLOCKED);
3253
3321
  }
3254
3322
 
3255
3323
  // src/io/BackupPanel.tsx
3256
3324
  var import_format6 = require("@ai-matrx/kit/format");
3257
- var import_react18 = require("react");
3325
+ var import_react19 = require("react");
3258
3326
  var import_controls13 = require("@ai-matrx/design-system/controls");
3259
3327
  var import_download = require("@ai-matrx/kit/download");
3260
3328
  var import_confirm_opener4 = require("@ai-matrx/kit/confirm-opener");
@@ -3347,7 +3415,7 @@ function startNewRestoreRun(preview) {
3347
3415
  }
3348
3416
 
3349
3417
  // src/io/lines.tsx
3350
- var import_react17 = require("react");
3418
+ var import_react18 = require("react");
3351
3419
  var import_design_system12 = require("@ai-matrx/design-system");
3352
3420
  var import_controls12 = require("@ai-matrx/design-system/controls");
3353
3421
  var import_jsx_runtime16 = require("react/jsx-runtime");
@@ -3360,7 +3428,7 @@ function PickLine({ checked, onChange, disabled = false, title, detail, badge, t
3360
3428
  ] });
3361
3429
  }
3362
3430
  function Windowed({ items, size = 150, render }) {
3363
- const [all, setAll] = (0, import_react17.useState)(false);
3431
+ const [all, setAll] = (0, import_react18.useState)(false);
3364
3432
  const shown = all ? items : items.slice(0, size);
3365
3433
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
3366
3434
  shown.map(render),
@@ -3371,7 +3439,7 @@ function Windowed({ items, size = 150, render }) {
3371
3439
  ] });
3372
3440
  }
3373
3441
  function More({ title = "More", children }) {
3374
- const [open, setOpen] = (0, import_react17.useState)(false);
3442
+ const [open, setOpen] = (0, import_react18.useState)(false);
3375
3443
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-2", children: [
3376
3444
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_controls12.DisclosureHeader, { open, title, onClick: () => setOpen((o) => !o) }),
3377
3445
  open ? children : null
@@ -3411,21 +3479,21 @@ function Omissions({ omissions, accepted, onAccepted, verb }) {
3411
3479
  function BackupPanel({ port, host, items, onClose, onChanged }) {
3412
3480
  const minLength = passphraseMinimum(host.backupPassphraseMinLength);
3413
3481
  const confirmed = useConfirmed();
3414
- const fileInput = (0, import_react18.useRef)(null);
3415
- const abort = (0, import_react18.useRef)(null);
3416
- const [mode, setMode] = (0, import_react18.useState)("backup");
3417
- const [busy, setBusy] = (0, import_react18.useState)(false);
3418
- const [error, setError] = (0, import_react18.useState)(null);
3419
- const [passphrase, setPassphrase] = (0, import_react18.useState)("");
3420
- const [repeat, setRepeat] = (0, import_react18.useState)("");
3421
- const [accepted, setAccepted] = (0, import_react18.useState)(false);
3422
- const [selected, setSelected] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
3423
- const [backup, setBackup] = (0, import_react18.useState)(null);
3424
- const [file, setFile] = (0, import_react18.useState)(null);
3425
- const [restorePreview, setRestorePreview] = (0, import_react18.useState)(null);
3426
- const [runId, setRunId] = (0, import_react18.useState)(null);
3427
- const [result, setResult] = (0, import_react18.useState)(null);
3428
- (0, import_react18.useEffect)(() => () => abort.current?.abort(), []);
3482
+ const fileInput = (0, import_react19.useRef)(null);
3483
+ const abort = (0, import_react19.useRef)(null);
3484
+ const [mode, setMode] = (0, import_react19.useState)("backup");
3485
+ const [busy, setBusy] = (0, import_react19.useState)(false);
3486
+ const [error, setError] = (0, import_react19.useState)(null);
3487
+ const [passphrase, setPassphrase] = (0, import_react19.useState)("");
3488
+ const [repeat, setRepeat] = (0, import_react19.useState)("");
3489
+ const [accepted, setAccepted] = (0, import_react19.useState)(false);
3490
+ const [selected, setSelected] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
3491
+ const [backup, setBackup] = (0, import_react19.useState)(null);
3492
+ const [file, setFile] = (0, import_react19.useState)(null);
3493
+ const [restorePreview, setRestorePreview] = (0, import_react19.useState)(null);
3494
+ const [runId, setRunId] = (0, import_react19.useState)(null);
3495
+ const [result, setResult] = (0, import_react19.useState)(null);
3496
+ (0, import_react19.useEffect)(() => () => abort.current?.abort(), []);
3429
3497
  const switchMode = (next) => {
3430
3498
  abort.current?.abort();
3431
3499
  setMode(next);
@@ -3562,7 +3630,7 @@ function BackupPanel({ port, host, items, onClose, onChanged }) {
3562
3630
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Summary, { value: backup }),
3563
3631
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Omissions, { omissions: backup.omissions, accepted, onAccepted: setAccepted, verb: "Back up" }),
3564
3632
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(VaultSection, { children: [
3565
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VaultRow, { label: "Passphrase", hint: minLength ? `At least ${minLength} characters. Not saved.` : "Not saved. It can't be recovered.", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
3633
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(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__ */ (0, import_jsx_runtime17.jsx)(import_controls13.Field, { type: "password", value: passphrase, autoComplete: "new-password", "aria-label": "Backup passphrase", "aria-invalid": short || void 0, onChange: (e) => setPassphrase(e.target.value) }) }),
3566
3634
  short ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { role: "alert", className: "px-1 text-xs text-destructive", "data-passphrase-too-short": "", children: [
3567
3635
  "Use at least ",
3568
3636
  minLength,
@@ -3610,7 +3678,7 @@ function tooShort(passphrase, minLength) {
3610
3678
  }
3611
3679
 
3612
3680
  // src/io/ExportPanel.tsx
3613
- var import_react19 = require("react");
3681
+ var import_react20 = require("react");
3614
3682
  var import_controls14 = require("@ai-matrx/design-system/controls");
3615
3683
  var import_download2 = require("@ai-matrx/kit/download");
3616
3684
  var import_confirm_opener5 = require("@ai-matrx/kit/confirm-opener");
@@ -3634,12 +3702,12 @@ function omissionText2(omissions) {
3634
3702
  }
3635
3703
  function ExportPanel({ port, items, onClose }) {
3636
3704
  const confirmed = useConfirmed();
3637
- const logins = (0, import_react19.useMemo)(() => items.filter((i) => i.definitionKey === WEBSITE_LOGIN), [items]);
3638
- const [profile, setProfile] = (0, import_react19.useState)("matrx_login_csv_v1");
3639
- const [selected, setSelected] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
3640
- const [preview, setPreview] = (0, import_react19.useState)(null);
3641
- const [busy, setBusy] = (0, import_react19.useState)(false);
3642
- const [error, setError] = (0, import_react19.useState)(null);
3705
+ const logins = (0, import_react20.useMemo)(() => items.filter((i) => i.definitionKey === WEBSITE_LOGIN), [items]);
3706
+ const [profile, setProfile] = (0, import_react20.useState)("matrx_login_csv_v1");
3707
+ const [selected, setSelected] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
3708
+ const [preview, setPreview] = (0, import_react20.useState)(null);
3709
+ const [busy, setBusy] = (0, import_react20.useState)(false);
3710
+ const [error, setError] = (0, import_react20.useState)(null);
3643
3711
  const format = FORMATS.find((f) => f.value === profile);
3644
3712
  const reasons = new Map(preview?.items.map((p) => [p.item_id, p]) ?? []);
3645
3713
  const eligible = preview?.items.filter((p) => p.eligible).length ?? 0;
@@ -3764,7 +3832,7 @@ function ExportPanel({ port, items, onClose }) {
3764
3832
  }
3765
3833
 
3766
3834
  // src/io/ImportPanel.tsx
3767
- var import_react20 = require("react");
3835
+ var import_react21 = require("react");
3768
3836
  var import_controls15 = require("@ai-matrx/design-system/controls");
3769
3837
 
3770
3838
  // src/io/csv-import.ts
@@ -4626,25 +4694,25 @@ var STATE_BADGE = {
4626
4694
  var ME = "me";
4627
4695
  function ImportPanel({ port, host, items, definitions, organizations, onClose, onChanged, limits }) {
4628
4696
  const confirmed = useConfirmed();
4629
- const [otpFor, setOtpFor] = (0, import_react20.useState)(null);
4630
- const fileInput = (0, import_react20.useRef)(null);
4631
- const abort = (0, import_react20.useRef)(null);
4632
- const stop = (0, import_react20.useRef)(false);
4633
- const keys = (0, import_react20.useRef)(/* @__PURE__ */ new Map());
4634
- const [source, setSource] = (0, import_react20.useState)("auto");
4635
- const [envText, setEnvText] = (0, import_react20.useState)("");
4636
- const [injectSandbox, setInjectSandbox] = (0, import_react20.useState)(false);
4637
- const [fileName, setFileName] = (0, import_react20.useState)(null);
4638
- const [reading, setReading] = (0, import_react20.useState)(false);
4639
- const [draft, setDraft] = (0, import_react20.useState)(null);
4640
- const [destination, setDestination] = (0, import_react20.useState)(ME);
4641
- const [browserFill, setBrowserFill] = (0, import_react20.useState)(false);
4642
- const [approvedVisible, setApprovedVisible] = (0, import_react20.useState)(false);
4643
- const [selected, setSelected] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
4644
- const [running, setRunning] = (0, import_react20.useState)(null);
4645
- const [done, setDone] = (0, import_react20.useState)(null);
4646
- const [error, setError] = (0, import_react20.useState)(null);
4647
- (0, import_react20.useEffect)(
4697
+ const [otpFor, setOtpFor] = (0, import_react21.useState)(null);
4698
+ const fileInput = (0, import_react21.useRef)(null);
4699
+ const abort = (0, import_react21.useRef)(null);
4700
+ const stop = (0, import_react21.useRef)(false);
4701
+ const keys = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
4702
+ const [source, setSource] = (0, import_react21.useState)("auto");
4703
+ const [envText, setEnvText] = (0, import_react21.useState)("");
4704
+ const [injectSandbox, setInjectSandbox] = (0, import_react21.useState)(false);
4705
+ const [fileName, setFileName] = (0, import_react21.useState)(null);
4706
+ const [reading, setReading] = (0, import_react21.useState)(false);
4707
+ const [draft, setDraft] = (0, import_react21.useState)(null);
4708
+ const [destination, setDestination] = (0, import_react21.useState)(ME);
4709
+ const [browserFill, setBrowserFill] = (0, import_react21.useState)(false);
4710
+ const [approvedVisible, setApprovedVisible] = (0, import_react21.useState)(false);
4711
+ const [selected, setSelected] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
4712
+ const [running, setRunning] = (0, import_react21.useState)(null);
4713
+ const [done, setDone] = (0, import_react21.useState)(null);
4714
+ const [error, setError] = (0, import_react21.useState)(null);
4715
+ (0, import_react21.useEffect)(
4648
4716
  () => () => {
4649
4717
  abort.current?.abort();
4650
4718
  stop.current = true;
@@ -4653,9 +4721,9 @@ function ImportPanel({ port, host, items, definitions, organizations, onClose, o
4653
4721
  );
4654
4722
  const organizationId = destination === ME ? null : destination;
4655
4723
  const existingIn = (org) => items.filter((i) => org === null ? i.owner.kind === "me" : i.owner.organizationId === org).map((i) => ({ displayName: i.name, loginUrls: i.loginUrls }));
4656
- const existing = (0, import_react20.useMemo)(() => existingIn(organizationId), [items, organizationId]);
4657
- const destinationOptions = (0, import_react20.useMemo)(() => [{ value: ME, label: "Personal" }, ...organizations.map((o) => ({ value: o.id, label: o.name }))], [organizations]);
4658
- const lines = (0, import_react20.useMemo)(
4724
+ const existing = (0, import_react21.useMemo)(() => existingIn(organizationId), [items, organizationId]);
4725
+ const destinationOptions = (0, import_react21.useMemo)(() => [{ value: ME, label: "Personal" }, ...organizations.map((o) => ({ value: o.id, label: o.name }))], [organizations]);
4726
+ const lines = (0, import_react21.useMemo)(
4659
4727
  () => draft?.kind === "file" ? reviewLines(draft.parsed, { organizationId, browserFill, existing, limits, mapping: draft.mapping }) : [],
4660
4728
  [draft, organizationId, browserFill, existing, limits]
4661
4729
  );
@@ -4931,14 +4999,14 @@ function Notices({ draft }) {
4931
4999
  }
4932
5000
 
4933
5001
  // src/ItemList.tsx
4934
- var import_react29 = require("react");
5002
+ var import_react30 = require("react");
4935
5003
  var import_design_system19 = require("@ai-matrx/design-system");
4936
5004
  var import_design_system20 = require("@ai-matrx/design-system");
4937
5005
  var import_controls23 = require("@ai-matrx/design-system/controls");
4938
5006
  var import_icons12 = require("@ai-matrx/design-system/icons");
4939
5007
 
4940
5008
  // src/ItemPane.tsx
4941
- var import_react28 = require("react");
5009
+ var import_react29 = require("react");
4942
5010
  var import_design_system17 = require("@ai-matrx/design-system");
4943
5011
  var import_design_system18 = require("@ai-matrx/design-system");
4944
5012
  var import_controls22 = require("@ai-matrx/design-system/controls");
@@ -4946,7 +5014,7 @@ var import_confirm_opener10 = require("@ai-matrx/kit/confirm-opener");
4946
5014
 
4947
5015
  // src/activity/FilesSection.tsx
4948
5016
  var import_format7 = require("@ai-matrx/kit/format");
4949
- var import_react21 = require("react");
5017
+ var import_react22 = require("react");
4950
5018
  var import_controls16 = require("@ai-matrx/design-system/controls");
4951
5019
  var import_design_system13 = require("@ai-matrx/design-system");
4952
5020
  var import_confirm_opener6 = require("@ai-matrx/kit/confirm-opener");
@@ -4964,11 +5032,11 @@ function FilesSection({ item, port, editing, onChanged }) {
4964
5032
  const confirmed = useConfirmed();
4965
5033
  const canEdit = editing && item.capabilities.canEdit;
4966
5034
  const canAdd = item.capabilities.canEdit;
4967
- const [busy, setBusy] = (0, import_react21.useState)(null);
4968
- const [error, setError] = (0, import_react21.useState)(null);
4969
- const [pending, setPending] = (0, import_react21.useState)(null);
4970
- const [dragging, setDragging] = (0, import_react21.useState)(false);
4971
- const picker = (0, import_react21.useRef)(null);
5035
+ const [busy, setBusy] = (0, import_react22.useState)(null);
5036
+ const [error, setError] = (0, import_react22.useState)(null);
5037
+ const [pending, setPending] = (0, import_react22.useState)(null);
5038
+ const [dragging, setDragging] = (0, import_react22.useState)(false);
5039
+ const picker = (0, import_react22.useRef)(null);
4972
5040
  if (!canAdd && item.attachments.length === 0) return null;
4973
5041
  async function run(key, work, fallback) {
4974
5042
  setBusy(key);
@@ -5045,8 +5113,8 @@ function FilesSection({ item, port, editing, onChanged }) {
5045
5113
  );
5046
5114
  }
5047
5115
  function EditableFile({ port, item: it, file: a, busy: b, run: go, onDownload, onTooBig }) {
5048
- const [open, setOpen] = (0, import_react21.useState)(false);
5049
- const replacer = (0, import_react21.useRef)(null);
5116
+ const [open, setOpen] = (0, import_react22.useState)(false);
5117
+ const replacer = (0, import_react22.useRef)(null);
5050
5118
  async function remove() {
5051
5119
  const yes = await (0, import_confirm_opener6.confirm)({ title: `Delete ${a.label}?`, description: "The encrypted file is removed from this item.", confirmLabel: "Delete", variant: "destructive" });
5052
5120
  if (yes) await go(`delete:${a.id}`, () => port.activity.deleteFile(it, a.id), "The file could not be deleted.");
@@ -5104,9 +5172,9 @@ function Protection({ value, locked, onChange }) {
5104
5172
  );
5105
5173
  }
5106
5174
  function NewFile({ file, busy, onAdd, onCancel }) {
5107
- const [label, setLabel] = (0, import_react21.useState)(file.name);
5108
- const [description, setDescription] = (0, import_react21.useState)("");
5109
- const [handling, setHandling] = (0, import_react21.useState)("revealable");
5175
+ const [label, setLabel] = (0, import_react22.useState)(file.name);
5176
+ const [description, setDescription] = (0, import_react22.useState)("");
5177
+ const [handling, setHandling] = (0, import_react22.useState)("revealable");
5110
5178
  async function add() {
5111
5179
  if (handling === "sealed" && !await confirmSeal(label)) return;
5112
5180
  await onAdd({ label: label.trim(), description: description.trim() || null, handling });
@@ -5126,10 +5194,10 @@ function NewFile({ file, busy, onAdd, onCancel }) {
5126
5194
  ] });
5127
5195
  }
5128
5196
  function FileDetailsRows({ file, busy, onSave, onCancel }) {
5129
- const [label, setLabel] = (0, import_react21.useState)(file.label);
5130
- const [description, setDescription] = (0, import_react21.useState)(file.description);
5131
- const [fileName, setFileName] = (0, import_react21.useState)(file.fileName);
5132
- const [handling, setHandling] = (0, import_react21.useState)(file.handling);
5197
+ const [label, setLabel] = (0, import_react22.useState)(file.label);
5198
+ const [description, setDescription] = (0, import_react22.useState)(file.description);
5199
+ const [fileName, setFileName] = (0, import_react22.useState)(file.fileName);
5200
+ const [handling, setHandling] = (0, import_react22.useState)(file.handling);
5133
5201
  const changed = label !== file.label || description !== file.description || fileName !== file.fileName || handling !== file.handling;
5134
5202
  async function save() {
5135
5203
  if (handling === "sealed" && file.handling !== "sealed" && !await confirmSeal(label)) return;
@@ -5155,10 +5223,10 @@ function confirmSeal(label) {
5155
5223
  });
5156
5224
  }
5157
5225
  function DraftFilesSection({ files, onFiles }) {
5158
- const [pending, setPending] = (0, import_react21.useState)(null);
5159
- const [error, setError] = (0, import_react21.useState)(null);
5160
- const [dragging, setDragging] = (0, import_react21.useState)(false);
5161
- const picker = (0, import_react21.useRef)(null);
5226
+ const [pending, setPending] = (0, import_react22.useState)(null);
5227
+ const [error, setError] = (0, import_react22.useState)(null);
5228
+ const [dragging, setDragging] = (0, import_react22.useState)(false);
5229
+ const picker = (0, import_react22.useRef)(null);
5162
5230
  const choose = (file) => {
5163
5231
  if (!file) return;
5164
5232
  if (fileTooBig(file.size)) return setError(TOO_BIG);
@@ -5207,7 +5275,7 @@ function DraftFilesSection({ files, onFiles }) {
5207
5275
  }
5208
5276
 
5209
5277
  // src/fields/RecoveryCodesRow.tsx
5210
- var import_react22 = require("react");
5278
+ var import_react23 = require("react");
5211
5279
  var import_controls17 = require("@ai-matrx/design-system/controls");
5212
5280
  var import_icons9 = require("@ai-matrx/design-system/icons");
5213
5281
  var import_jsx_runtime21 = require("react/jsx-runtime");
@@ -5217,9 +5285,9 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
5217
5285
  const confirmed = useConfirmed();
5218
5286
  const copyValue2 = useCopy();
5219
5287
  const secret = useTransientSecret();
5220
- const [busy, setBusy] = (0, import_react22.useState)(false);
5221
- const [error, setError] = (0, import_react22.useState)(null);
5222
- const [draft, setDraft] = (0, import_react22.useState)(null);
5288
+ const [busy, setBusy] = (0, import_react23.useState)(false);
5289
+ const [error, setError] = (0, import_react23.useState)(null);
5290
+ const [draft, setDraft] = (0, import_react23.useState)(null);
5223
5291
  const canEdit = item.capabilities.canEdit;
5224
5292
  const run = async (step) => {
5225
5293
  setBusy(true);
@@ -5314,7 +5382,7 @@ function RecoveryCodesRow({ item, field, port, onChanged }) {
5314
5382
  }
5315
5383
 
5316
5384
  // src/fields/DraftRows.tsx
5317
- var import_react23 = require("react");
5385
+ var import_react24 = require("react");
5318
5386
  var import_controls18 = require("@ai-matrx/design-system/controls");
5319
5387
  var import_design_system14 = require("@ai-matrx/design-system");
5320
5388
  var import_confirm_opener7 = require("@ai-matrx/kit/confirm-opener");
@@ -5369,7 +5437,7 @@ function FieldSettingsRows({ name, value, defaultHandling = "revealable", onChan
5369
5437
  var hasSecretSettings = (s) => saysMore(s, "revealable");
5370
5438
  var hasDeclaredSettings = (s, defaultHandling) => Boolean(s && saysMore(s, defaultHandling));
5371
5439
  function SecretBuilderRow({ field, onChange, onRemove }) {
5372
- const [open, setOpen] = (0, import_react23.useState)(hasSecretSettings(field));
5440
+ const [open, setOpen] = (0, import_react24.useState)(hasSecretSettings(field));
5373
5441
  const handling = field.handling ?? "revealable";
5374
5442
  const name = field.label.trim() || "Secret";
5375
5443
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
@@ -5610,7 +5678,7 @@ function targetLabel(t) {
5610
5678
  }
5611
5679
 
5612
5680
  // src/extension/UseOnSiteButton.tsx
5613
- var import_react24 = require("react");
5681
+ var import_react25 = require("react");
5614
5682
  var import_controls19 = require("@ai-matrx/design-system/controls");
5615
5683
  var import_jsx_runtime23 = require("react/jsx-runtime");
5616
5684
  function canUseOnSite(item, pageUrl) {
@@ -5618,7 +5686,7 @@ function canUseOnSite(item, pageUrl) {
5618
5686
  }
5619
5687
  function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5620
5688
  const notify = useNotify();
5621
- const [busy, setBusy] = (0, import_react24.useState)(false);
5689
+ const [busy, setBusy] = (0, import_react25.useState)(false);
5622
5690
  if (!canUseOnSite(item, pageUrl)) return null;
5623
5691
  const site = pageSite(pageUrl);
5624
5692
  const run = async () => {
@@ -5637,7 +5705,7 @@ function UseOnSiteButton({ port, item, pageUrl, onChanged }) {
5637
5705
  }
5638
5706
 
5639
5707
  // src/sharing/SharePanel.tsx
5640
- var import_react27 = require("react");
5708
+ var import_react28 = require("react");
5641
5709
  var import_confirm_opener9 = require("@ai-matrx/kit/confirm-opener");
5642
5710
  var import_controls21 = require("@ai-matrx/design-system/controls");
5643
5711
  var import_design_system16 = require("@ai-matrx/design-system");
@@ -5660,14 +5728,17 @@ function isEmail(value) {
5660
5728
  }
5661
5729
  var PERSONAL = "personal";
5662
5730
  var destinationOf = (key) => key === PERSONAL ? null : key;
5731
+ var orgChoice = (o, hints) => ({ value: o.id, label: o.name, ...hints.has(o.id) ? { hint: hints.get(o.id) } : {} });
5663
5732
  function moveDestinations(item, orgs) {
5664
5733
  if (item.owner.kind === "shared") return [];
5665
5734
  const here = item.owner.organizationId;
5666
- return [...here ? [{ value: PERSONAL, label: "Personal" }] : [], ...orgs.filter((o) => o.id !== here).map((o) => ({ value: o.id, label: o.name }))];
5735
+ const hints = organizationHints(orgs);
5736
+ return [...here ? [{ value: PERSONAL, label: "Personal" }] : [], ...orgs.filter((o) => o.id !== here).map((o) => orgChoice(o, hints))];
5667
5737
  }
5668
5738
  function copyDestinations(orgs, item) {
5669
5739
  const here = item ? item.owner.kind === "me" ? PERSONAL : item.owner.organizationId : void 0;
5670
- return [{ value: PERSONAL, label: "Personal" }, ...orgs.map((o) => ({ value: o.id, label: o.name }))].filter((d) => d.value !== here);
5740
+ const hints = organizationHints(orgs);
5741
+ return [{ value: PERSONAL, label: "Personal" }, ...orgs.map((o) => orgChoice(o, hints))].filter((d) => d.value !== here);
5671
5742
  }
5672
5743
  function copyRefusal(message2) {
5673
5744
  return /duplicate/i.test(message2) ? "There is already a copy of this item there." : null;
@@ -5695,7 +5766,7 @@ function shareSummary(grants) {
5695
5766
  var MEMBER_CHOICE_DEFAULT = "default";
5696
5767
 
5697
5768
  // src/sharing/parts.tsx
5698
- var import_react25 = require("react");
5769
+ var import_react26 = require("react");
5699
5770
  var import_design_system15 = require("@ai-matrx/design-system");
5700
5771
  var import_jsx_runtime24 = require("react/jsx-runtime");
5701
5772
  var message = (e, fallback) => {
@@ -5704,9 +5775,9 @@ var message = (e, fallback) => {
5704
5775
  };
5705
5776
  function useConfirmedChange() {
5706
5777
  const confirmed = useConfirmed();
5707
- const [busy, setBusy] = (0, import_react25.useState)(null);
5708
- const [error, setError] = (0, import_react25.useState)(null);
5709
- const [notice, setNotice] = (0, import_react25.useState)(null);
5778
+ const [busy, setBusy] = (0, import_react26.useState)(null);
5779
+ const [error, setError] = (0, import_react26.useState)(null);
5780
+ const [notice, setNotice] = (0, import_react26.useState)(null);
5710
5781
  async function run(key, fn, done) {
5711
5782
  setBusy(key);
5712
5783
  setError(null);
@@ -5740,18 +5811,20 @@ function StatusLine({ error, notice }) {
5740
5811
  }
5741
5812
 
5742
5813
  // src/sharing/MovePanel.tsx
5743
- var import_react26 = require("react");
5814
+ var import_react27 = require("react");
5744
5815
  var import_confirm_opener8 = require("@ai-matrx/kit/confirm-opener");
5745
5816
  var import_controls20 = require("@ai-matrx/design-system/controls");
5746
5817
  var import_jsx_runtime25 = require("react/jsx-runtime");
5747
5818
  var NONE = "__none__";
5748
- function MovePanel({ item, port, organizations, onClose, onChanged }) {
5819
+ function MovePanel({ item, port, host, organizations, onClose, onChanged, onOpenItem }) {
5749
5820
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
5750
5821
  const moves = moveDestinations(item, organizations);
5751
5822
  const copies = copyDestinations(organizations, item);
5752
- const [moveTo, setMoveTo] = (0, import_react26.useState)("");
5753
- const [copyTo, setCopyTo] = (0, import_react26.useState)("");
5754
- const [email, setEmail] = (0, import_react26.useState)("");
5823
+ const [moveTo, setMoveTo] = (0, import_react27.useState)("");
5824
+ const [copyTo, setCopyTo] = (0, import_react27.useState)("");
5825
+ const [email, setEmail] = (0, import_react27.useState)("");
5826
+ const [made, setMade] = (0, import_react27.useState)(null);
5827
+ const searchAt = host.organizationSearchAt ?? ORGANIZATION_SEARCH_AT_UNREAD;
5755
5828
  const passkey = isPasskey(item);
5756
5829
  const canMove = item.capabilities.canManage && !passkey && moves.length > 0;
5757
5830
  const canGive = item.capabilities.canManage && item.owner.kind === "me" && !passkey;
@@ -5785,8 +5858,10 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5785
5858
  };
5786
5859
  const copy = async () => {
5787
5860
  if (!copyChoice) return;
5788
- const made = await run("copy", () => port.sharing.copy(item, destinationOf(copyChoice.value)), `Copy made in ${copyChoice.label}`);
5789
- if (made) onChanged();
5861
+ const copied = await run("copy", () => port.sharing.copy(item, destinationOf(copyChoice.value)), `Copy made in ${copyChoice.label}`);
5862
+ if (!copied) return;
5863
+ setMade(copied);
5864
+ onChanged();
5790
5865
  };
5791
5866
  const nothing = !canMove && !canGive && !canCopy;
5792
5867
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
@@ -5795,7 +5870,10 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5795
5870
  title: "Move or copy",
5796
5871
  size: "md",
5797
5872
  onClose,
5798
- footer: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusLine, { error, notice }) : null, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "primary", onClick: onClose, children: "Done" }) }),
5873
+ footer: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(PanelFooter, { status: error || notice ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StatusLine, { error, notice }) : null, children: [
5874
+ made && onOpenItem ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", onClick: () => onOpenItem(made), children: "Open copy" }) : null,
5875
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "primary", onClick: onClose, children: "Done" })
5876
+ ] }),
5799
5877
  children: nothing ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultSection, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Empty, { children: passkey ? "A passkey stays where it was created." : "Only the owner can move or give this item." }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(VaultSection, { children: [
5800
5878
  canMove && moves.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5801
5879
  VaultRow,
@@ -5803,7 +5881,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5803
5881
  label: "Move to",
5804
5882
  hint: moveChoice ? itemMoveConsequence(item, destinationOf(moveChoice.value)) : void 0,
5805
5883
  actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", disabled: busy !== null || !moveChoice, onClick: () => void move(), children: "Move" }),
5806
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { className: "w-full", "aria-label": "Move to", value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5884
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { className: "w-full", "aria-label": "Move to", searchAt, value: moveTo || NONE, onValueChange: (v) => setMoveTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...moves] })
5807
5885
  }
5808
5886
  ) : null,
5809
5887
  canGive ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultRow, { label: "Give to", hint: "You lose all access; your shares end", actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "danger", disabled: busy !== null || !isEmail(email), onClick: () => void give(), children: "Give" }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
@@ -5820,7 +5898,7 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5820
5898
  onChange: (e) => setEmail(e.target.value)
5821
5899
  }
5822
5900
  ) }) : null,
5823
- canCopy && copies.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { className: "w-full", "aria-label": "Copy to", value: copyTo || NONE, onValueChange: (v) => setCopyTo(v === NONE ? "" : v), options: [{ value: NONE, label: "Choose where" }, ...copies] }) }) : null
5901
+ canCopy && copies.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(VaultRow, { label: "Copy to", hint: "A separate item; edits no longer sync", actions: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Button, { variant: "outline", disabled: busy !== null || !copyChoice, onClick: () => void copy(), children: "Copy" }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_controls20.Select, { 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
5824
5902
  ] })
5825
5903
  }
5826
5904
  );
@@ -5829,11 +5907,11 @@ function MovePanel({ item, port, organizations, onClose, onChanged }) {
5829
5907
  // src/sharing/SharePanel.tsx
5830
5908
  var import_jsx_runtime26 = require("react/jsx-runtime");
5831
5909
  function useGrants(port, item) {
5832
- const [grants, setGrants] = (0, import_react27.useState)(null);
5833
- const [loadError, setLoadError] = (0, import_react27.useState)(null);
5834
- const [nonce, setNonce] = (0, import_react27.useState)(0);
5910
+ const [grants, setGrants] = (0, import_react28.useState)(null);
5911
+ const [loadError, setLoadError] = (0, import_react28.useState)(null);
5912
+ const [nonce, setNonce] = (0, import_react28.useState)(0);
5835
5913
  const allowed = item.capabilities.canManage;
5836
- (0, import_react27.useEffect)(() => {
5914
+ (0, import_react28.useEffect)(() => {
5837
5915
  if (!allowed) return;
5838
5916
  let live = true;
5839
5917
  setLoadError(null);
@@ -5850,9 +5928,9 @@ function useGrants(port, item) {
5850
5928
  function SharePanel({ item, port, organizations, onClose, onChanged }) {
5851
5929
  const { grants, setGrants, loadError, reload } = useGrants(port, item);
5852
5930
  const { busy, error, notice, run } = useConfirmedChange();
5853
- const [email, setEmail] = (0, import_react27.useState)("");
5854
- const [level, setLevel] = (0, import_react27.useState)("use");
5855
- const [more, setMore] = (0, import_react27.useState)(false);
5931
+ const [email, setEmail] = (0, import_react28.useState)("");
5932
+ const [level, setLevel] = (0, import_react28.useState)("use");
5933
+ const [more, setMore] = (0, import_react28.useState)(false);
5856
5934
  const isOrg = item.owner.kind === "organization" && item.owner.organizationId !== null;
5857
5935
  const orgName = item.owner.label;
5858
5936
  const people = (grants ?? []).filter((g) => g.kind === "person");
@@ -5971,8 +6049,8 @@ function SharePanel({ item, port, organizations, onClose, onChanged }) {
5971
6049
  function IntoOrganization({ item, port, organizations, grants, onShared }) {
5972
6050
  const { busy, error, notice, run } = useConfirmedChange();
5973
6051
  const open = organizations.filter((o) => !grants.some((g) => g.organizationId === o.id));
5974
- const [target, setTarget] = (0, import_react27.useState)("");
5975
- const [level, setLevel] = (0, import_react27.useState)("use");
6052
+ const [target, setTarget] = (0, import_react28.useState)("");
6053
+ const [level, setLevel] = (0, import_react28.useState)("use");
5976
6054
  const chosen = open.find((o) => o.id === target);
5977
6055
  if (item.owner.kind !== "me") return null;
5978
6056
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VaultSection, { title: "Share into organization", children: open.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
@@ -6007,10 +6085,10 @@ var CHOICES = [
6007
6085
  { value: "editor", label: "Can edit", meta: "See and change" }
6008
6086
  ];
6009
6087
  function MemberAccess({ port, organizationId, organizationName }) {
6010
- const [list, setList] = (0, import_react27.useState)(null);
6011
- const [loadError, setLoadError] = (0, import_react27.useState)(null);
6088
+ const [list, setList] = (0, import_react28.useState)(null);
6089
+ const [loadError, setLoadError] = (0, import_react28.useState)(null);
6012
6090
  const { busy, error, run } = useConfirmedChange();
6013
- (0, import_react27.useEffect)(() => {
6091
+ (0, import_react28.useEffect)(() => {
6014
6092
  let live = true;
6015
6093
  port.sharing.memberAccess(organizationId).then(
6016
6094
  (l) => live && setList(l),
@@ -6042,9 +6120,9 @@ function MemberAccess({ port, organizationId, organizationName }) {
6042
6120
  ] });
6043
6121
  }
6044
6122
  function SharingSummary({ item, port, className }) {
6045
- const [text, setText] = (0, import_react27.useState)("");
6123
+ const [text, setText] = (0, import_react28.useState)("");
6046
6124
  const allowed = item.capabilities.canManage;
6047
- (0, import_react27.useEffect)(() => {
6125
+ (0, import_react28.useEffect)(() => {
6048
6126
  if (!allowed) return;
6049
6127
  let live = true;
6050
6128
  port.sharing.grants(item).then(
@@ -6075,8 +6153,8 @@ function ItemPane(props) {
6075
6153
  const editing = mode !== "view";
6076
6154
  const seedName = seed?.name ?? "";
6077
6155
  const seedUrl = seed?.url ?? "";
6078
- const [loaded, setLoaded] = (0, import_react28.useState)({});
6079
- const base = (0, import_react28.useMemo)(() => {
6156
+ const [loaded, setLoaded] = (0, import_react29.useState)({});
6157
+ const base = (0, import_react29.useMemo)(() => {
6080
6158
  const b = draftOf(item);
6081
6159
  if (!item) {
6082
6160
  b.name = seedName;
@@ -6085,28 +6163,28 @@ function ItemPane(props) {
6085
6163
  b.values = { ...loaded };
6086
6164
  return b;
6087
6165
  }, [item, seedName, seedUrl, loaded]);
6088
- const [draft, setDraft] = (0, import_react28.useState)(base);
6089
- const [tagsText, setTagsText] = (0, import_react28.useState)(base.tags.join(", "));
6090
- const [showTags, setShowTags] = (0, import_react28.useState)(false);
6091
- const [showDescription, setShowDescription] = (0, import_react28.useState)(false);
6092
- const [showRecovery, setShowRecovery] = (0, import_react28.useState)(false);
6093
- const [settingUpOtp, setSettingUpOtp] = (0, import_react28.useState)(false);
6094
- const [owner, setOwner] = (0, import_react28.useState)(defaultOwner ?? "me");
6095
- const [recipient, setRecipient] = (0, import_react28.useState)("");
6096
- const [generatePrivately, setGeneratePrivately] = (0, import_react28.useState)(false);
6097
- const [busy, setBusy] = (0, import_react28.useState)(false);
6098
- const [sent, setSent] = (0, import_react28.useState)(null);
6099
- const [queuedFiles, setQueuedFiles] = (0, import_react28.useState)([]);
6100
- const [showBrowser, setShowBrowser] = (0, import_react28.useState)(false);
6101
- const [error, setError] = (0, import_react28.useState)(null);
6102
- const [destinations, setDestinations] = (0, import_react28.useState)({});
6103
- const [savedNew, setSavedNew] = (0, import_react28.useState)(false);
6166
+ const [draft, setDraft] = (0, import_react29.useState)(base);
6167
+ const [tagsText, setTagsText] = (0, import_react29.useState)(base.tags.join(", "));
6168
+ const [showTags, setShowTags] = (0, import_react29.useState)(false);
6169
+ const [showDescription, setShowDescription] = (0, import_react29.useState)(false);
6170
+ const [showRecovery, setShowRecovery] = (0, import_react29.useState)(false);
6171
+ const [settingUpOtp, setSettingUpOtp] = (0, import_react29.useState)(false);
6172
+ const [owner, setOwner] = (0, import_react29.useState)(defaultOwner ?? "me");
6173
+ const [recipient, setRecipient] = (0, import_react29.useState)("");
6174
+ const [generatePrivately, setGeneratePrivately] = (0, import_react29.useState)(false);
6175
+ const [busy, setBusy] = (0, import_react29.useState)(false);
6176
+ const [sent, setSent] = (0, import_react29.useState)(null);
6177
+ const [queuedFiles, setQueuedFiles] = (0, import_react29.useState)([]);
6178
+ const [showBrowser, setShowBrowser] = (0, import_react29.useState)(false);
6179
+ const [error, setError] = (0, import_react29.useState)(null);
6180
+ const [destinations, setDestinations] = (0, import_react29.useState)({});
6181
+ const [savedNew, setSavedNew] = (0, import_react29.useState)(false);
6104
6182
  const dirty = editing && !savedNew && isDirty(base, draft);
6105
6183
  const declared = definition?.fields ?? [];
6106
- const prev = (0, import_react28.useRef)(null);
6107
- const paneRef = (0, import_react28.useRef)(null);
6184
+ const prev = (0, import_react29.useRef)(null);
6185
+ const paneRef = (0, import_react29.useRef)(null);
6108
6186
  const room = useRoomOf(paneRef);
6109
- (0, import_react28.useEffect)(() => {
6187
+ (0, import_react29.useEffect)(() => {
6110
6188
  const was = prev.current;
6111
6189
  const id = item?.id ?? null;
6112
6190
  if (was && was.id === id && was.mode === mode && editing) {
@@ -6119,22 +6197,22 @@ function ItemPane(props) {
6119
6197
  }
6120
6198
  prev.current = { base, id, mode };
6121
6199
  }, [base, mode, item?.id, editing]);
6122
- (0, import_react28.useEffect)(() => {
6200
+ (0, import_react29.useEffect)(() => {
6123
6201
  setLoaded({});
6124
6202
  setShowTags(false);
6125
6203
  setShowDescription(false);
6126
6204
  setShowRecovery(false);
6127
6205
  setSavedNew(false);
6128
6206
  }, [item?.id, mode]);
6129
- const onDirtyRef = (0, import_react28.useRef)(onDirty);
6207
+ const onDirtyRef = (0, import_react29.useRef)(onDirty);
6130
6208
  onDirtyRef.current = onDirty;
6131
- (0, import_react28.useEffect)(() => onDirtyRef.current(dirty), [dirty]);
6209
+ (0, import_react29.useEffect)(() => onDirtyRef.current(dirty), [dirty]);
6132
6210
  const keepKey = draftKey(item?.id ?? null, definition?.key ?? item?.definitionKey ?? null);
6133
- (0, import_react28.useEffect)(() => {
6211
+ (0, import_react29.useEffect)(() => {
6134
6212
  if (editing && dirty) (0, import_drafts.keepDraft)(keepKey, keptFieldsOf(draft), { basedOn: item?.updatedAt ?? "new" });
6135
6213
  else if (!editing) (0, import_drafts.dropKeptDraft)(keepKey);
6136
6214
  }, [editing, dirty, draft, keepKey, item?.updatedAt]);
6137
- (0, import_react28.useEffect)(() => {
6215
+ (0, import_react29.useEffect)(() => {
6138
6216
  if (!editing || !item) return;
6139
6217
  let live = true;
6140
6218
  for (const f of item.fields) {
@@ -6259,7 +6337,7 @@ function ItemPane(props) {
6259
6337
  const turnOnOne = canTurnOn ? (f) => () => turnOn([f]) : () => void 0;
6260
6338
  const declaredKeys = new Set(declared.map((f) => f.key));
6261
6339
  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);
6262
- const [settingsToggled, setSettingsToggled] = (0, import_react28.useState)(/* @__PURE__ */ new Set());
6340
+ const [settingsToggled, setSettingsToggled] = (0, import_react29.useState)(/* @__PURE__ */ new Set());
6263
6341
  const settingsOpen = (f) => settingsToggled.has(f.key) !== (definition?.key === ENV_VALUE_KEY || hasDeclaredSettings(draft.fieldSettings?.[f.key], f.handling));
6264
6342
  const toggleSettings = (key) => setSettingsToggled((cur) => {
6265
6343
  const next = new Set(cur);
@@ -6414,7 +6492,7 @@ function ItemPane(props) {
6414
6492
  const hidden = existing && existing.handling !== "visible" && !(f.key in loaded);
6415
6493
  const newSecret = mode === "new" && f.storage === "encrypted" && owner !== "person";
6416
6494
  const open = newSecret && settingsOpen(f);
6417
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react28.Fragment, { children: [
6495
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react29.Fragment, { children: [
6418
6496
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6419
6497
  EditRow,
6420
6498
  {
@@ -6636,8 +6714,8 @@ function ItemList({ title, items, definitions, port, selectedId, onSelect, query
6636
6714
  const pinned = matchingIds ? items.filter((i) => matchingIds.has(i.id)) : [];
6637
6715
  const rest = matchingIds ? items.filter((i) => !matchingIds.has(i.id)) : items;
6638
6716
  const ordered = [...pinned, ...rest];
6639
- const listRef = (0, import_react29.useRef)(null);
6640
- (0, import_react29.useEffect)(() => {
6717
+ const listRef = (0, import_react30.useRef)(null);
6718
+ (0, import_react30.useEffect)(() => {
6641
6719
  if (selectedId) listRef.current?.querySelector(`[data-item="${selectedId}"]`)?.scrollIntoView({ block: "nearest" });
6642
6720
  }, [selectedId, items.length]);
6643
6721
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -6700,8 +6778,8 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6700
6778
  const confirmed = useConfirmed();
6701
6779
  const copy = useCopy();
6702
6780
  const notify = useNotify();
6703
- const [busy, setBusy] = (0, import_react29.useState)(false);
6704
- const [menuOpen, setMenuOpen] = (0, import_react29.useState)(false);
6781
+ const [busy, setBusy] = (0, import_react30.useState)(false);
6782
+ const [menuOpen, setMenuOpen] = (0, import_react30.useState)(false);
6705
6783
  const canUse = item.capabilities.canUse;
6706
6784
  const user = canUse ? item.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active !== false) : void 0;
6707
6785
  const secret = canUse && item.capabilities.canReveal ? item.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active !== false) : void 0;
@@ -6740,7 +6818,7 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6740
6818
  ...manageEntries(item, onAction),
6741
6819
  ...hostEntries.map((h) => ({ ...h, kind: h.kind ?? "host" }))
6742
6820
  ];
6743
- const entriesRef = (0, import_react29.useRef)(entries);
6821
+ const entriesRef = (0, import_react30.useRef)(entries);
6744
6822
  entriesRef.current = entries;
6745
6823
  const glyphOf = (e) => e.id === "copy:username" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, { className: "size-4" }) : e.id === "copy:password" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, { className: "size-4" }) : e.id === "copy:code" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, { className: "size-4" }) : e.kind === "favorite" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StarGlyph, { className: (0, import_design_system20.cn)("size-4", favorite?.on && "fill-current text-warning") }) : e.kind === "open" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightGlyph, { className: "size-4" }) : e.kind === "host" || e.kind === "manage" ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_icons12.CopyIcon, { className: "size-4" });
6746
6824
  const menuItem = (e) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenuItem, { disabled: e.disabled ?? false, onSelect: e.onSelect, children: [
@@ -6763,21 +6841,25 @@ function ListRow({ item, family, port, on, onSelect, withOwner, ownContextMenu,
6763
6841
  {
6764
6842
  type: "button",
6765
6843
  "aria-current": on ? "true" : void 0,
6766
- "data-surface": on ? "primary" : void 0,
6844
+ selected: on,
6845
+ selectedStyle: "primary",
6767
6846
  onClick: () => onSelect(item.id),
6768
6847
  layout: "row",
6769
6848
  variant: "quiet",
6849
+ endInset: "control",
6850
+ oneLine: true,
6770
6851
  icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ItemIcon, { definitionKey: item.definitionKey, family, site: loginSiteOf(item), inverted: on }),
6771
6852
  title: item.name,
6772
6853
  line: subtitleOf(item, withOwner),
6773
- className: "w-full pr-10"
6854
+ className: "w-full"
6774
6855
  }
6775
6856
  ),
6776
6857
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("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: [
6777
- user || secret || favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("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: [
6858
+ user || secret || code || favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_design_system20.cn)("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: [
6778
6859
  favorite ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(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,
6779
6860
  user ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, disabled: busy, onClick: copyUser }) : null,
6780
- secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null
6861
+ secret ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(KeyGlyph, {}), "aria-label": "Copy password", disabled: busy, onClick: copyPassword }) : null,
6862
+ code ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_controls23.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClockGlyph, {}), "aria-label": "Copy one-time code", disabled: busy, onClick: copyCode }) : null
6781
6863
  ] }) : null,
6782
6864
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_design_system19.DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [
6783
6865
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_design_system19.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -6818,7 +6900,7 @@ function manageEntries(item, onAction) {
6818
6900
  }
6819
6901
 
6820
6902
  // src/lists/TrashView.tsx
6821
- var import_react31 = require("react");
6903
+ var import_react32 = require("react");
6822
6904
  var import_controls25 = require("@ai-matrx/design-system/controls");
6823
6905
  var import_format9 = require("@ai-matrx/kit/format");
6824
6906
 
@@ -6892,7 +6974,7 @@ function refusalText(reason) {
6892
6974
  }
6893
6975
 
6894
6976
  // src/lists/RestorePanel.tsx
6895
- var import_react30 = require("react");
6977
+ var import_react31 = require("react");
6896
6978
  var import_controls24 = require("@ai-matrx/design-system/controls");
6897
6979
  var import_jsx_runtime29 = require("react/jsx-runtime");
6898
6980
  var count = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
@@ -6903,13 +6985,13 @@ function RestorePanel({
6903
6985
  turnOn,
6904
6986
  onClose
6905
6987
  }) {
6906
- const [preview, setPreview] = (0, import_react30.useState)(null);
6907
- const [restored, setRestored] = (0, import_react30.useState)(null);
6908
- const [turnedOn, setTurnedOn] = (0, import_react30.useState)(null);
6909
- const [error, setError] = (0, import_react30.useState)(null);
6910
- const [busy, setBusy] = (0, import_react30.useState)(false);
6911
- const [loading, setLoading] = (0, import_react30.useState)(Boolean(lists.preview));
6912
- (0, import_react30.useEffect)(() => {
6988
+ const [preview, setPreview] = (0, import_react31.useState)(null);
6989
+ const [restored, setRestored] = (0, import_react31.useState)(null);
6990
+ const [turnedOn, setTurnedOn] = (0, import_react31.useState)(null);
6991
+ const [error, setError] = (0, import_react31.useState)(null);
6992
+ const [busy, setBusy] = (0, import_react31.useState)(false);
6993
+ const [loading, setLoading] = (0, import_react31.useState)(Boolean(lists.preview));
6994
+ (0, import_react31.useEffect)(() => {
6913
6995
  if (!lists.preview) return;
6914
6996
  let live = true;
6915
6997
  lists.preview(item).then(
@@ -7013,10 +7095,10 @@ function trashLineOf(item) {
7013
7095
  }
7014
7096
  function TrashView({ port, deleted, query, header, onChanged }) {
7015
7097
  const confirmed = useConfirmed();
7016
- const [busyId, setBusyId] = (0, import_react31.useState)(null);
7017
- const [message2, setMessage] = (0, import_react31.useState)(null);
7098
+ const [busyId, setBusyId] = (0, import_react32.useState)(null);
7099
+ const [message2, setMessage] = (0, import_react32.useState)(null);
7018
7100
  const shown = deleted.filter((i) => trashItemMatchesQuery(i, query));
7019
- const [restoring, setRestoring] = (0, import_react31.useState)(null);
7101
+ const [restoring, setRestoring] = (0, import_react32.useState)(null);
7020
7102
  const restore = async (item, deletionId) => {
7021
7103
  setBusyId(item.id);
7022
7104
  setMessage(null);
@@ -7064,15 +7146,15 @@ function TrashView({ port, deleted, query, header, onChanged }) {
7064
7146
  }
7065
7147
 
7066
7148
  // src/NewItemFlow.tsx
7067
- var import_react32 = require("react");
7149
+ var import_react33 = require("react");
7068
7150
  var import_controls26 = require("@ai-matrx/design-system/controls");
7069
7151
  var import_icons13 = require("@ai-matrx/design-system/icons");
7070
7152
  var import_jsx_runtime31 = require("react/jsx-runtime");
7071
7153
  function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
7072
- const [search, setSearch] = (0, import_react32.useState)("");
7073
- const guess = (0, import_react32.useMemo)(() => inferFromUrl(url, definitions), [url, definitions]);
7154
+ const [search, setSearch] = (0, import_react33.useState)("");
7155
+ const guess = (0, import_react33.useMemo)(() => inferFromUrl(url, definitions), [url, definitions]);
7074
7156
  const common = COMMON_DEFINITION_KEYS.map((k) => definitions.find((d) => d.key === k)).filter((d) => d !== void 0);
7075
- const matches = (0, import_react32.useMemo)(() => {
7157
+ const matches = (0, import_react33.useMemo)(() => {
7076
7158
  const q = search.trim().toLowerCase();
7077
7159
  if (!q) return [];
7078
7160
  return definitions.filter((d) => `${d.label} ${d.key} ${d.providerKey ?? ""} ${FAMILY_LABELS[d.family] ?? ""}`.toLowerCase().includes(q)).slice(0, 60);
@@ -7143,7 +7225,7 @@ function NewItemFlow({ definitions, url, onUrl, onChoose, onCancel }) {
7143
7225
  }
7144
7226
 
7145
7227
  // src/sharing/SecureLinkPanel.tsx
7146
- var import_react33 = require("react");
7228
+ var import_react34 = require("react");
7147
7229
  var import_confirm_opener11 = require("@ai-matrx/kit/confirm-opener");
7148
7230
  var import_design_system21 = require("@ai-matrx/design-system");
7149
7231
  var import_controls27 = require("@ai-matrx/design-system/controls");
@@ -7226,20 +7308,20 @@ var import_jsx_runtime32 = require("react/jsx-runtime");
7226
7308
  function SecureLinkPanel({ item, port, onClose }) {
7227
7309
  const sharing = port.sharing;
7228
7310
  const { busy, error, notice, run, setNotice } = useConfirmedChange();
7229
- const [remedy, setRemedy] = (0, import_react33.useState)(null);
7230
- const [options, setOptions] = (0, import_react33.useState)(null);
7231
- const [optionsError, setOptionsError] = (0, import_react33.useState)(null);
7232
- const [sent, setSent] = (0, import_react33.useState)(null);
7233
- const [sentError, setSentError] = (0, import_react33.useState)(null);
7234
- const [nonce, setNonce] = (0, import_react33.useState)(0);
7235
- const [email, setEmail] = (0, import_react33.useState)("");
7236
- const [phone, setPhone] = (0, import_react33.useState)("");
7237
- const [name, setName] = (0, import_react33.useState)("");
7238
- const [linkBy, setLinkBy] = (0, import_react33.useState)("email");
7239
- const [fields, setFields] = (0, import_react33.useState)([]);
7240
- const [note, setNote] = (0, import_react33.useState)("");
7241
- const [sameChannelSent, setSameChannelSent] = (0, import_react33.useState)(false);
7242
- (0, import_react33.useEffect)(() => {
7311
+ const [remedy, setRemedy] = (0, import_react34.useState)(null);
7312
+ const [options, setOptions] = (0, import_react34.useState)(null);
7313
+ const [optionsError, setOptionsError] = (0, import_react34.useState)(null);
7314
+ const [sent, setSent] = (0, import_react34.useState)(null);
7315
+ const [sentError, setSentError] = (0, import_react34.useState)(null);
7316
+ const [nonce, setNonce] = (0, import_react34.useState)(0);
7317
+ const [email, setEmail] = (0, import_react34.useState)("");
7318
+ const [phone, setPhone] = (0, import_react34.useState)("");
7319
+ const [name, setName] = (0, import_react34.useState)("");
7320
+ const [linkBy, setLinkBy] = (0, import_react34.useState)("email");
7321
+ const [fields, setFields] = (0, import_react34.useState)([]);
7322
+ const [note, setNote] = (0, import_react34.useState)("");
7323
+ const [sameChannelSent, setSameChannelSent] = (0, import_react34.useState)(false);
7324
+ (0, import_react34.useEffect)(() => {
7243
7325
  let live = true;
7244
7326
  setOptionsError(null);
7245
7327
  sharing.secureLinkOptions(item).then(
@@ -7254,7 +7336,7 @@ function SecureLinkPanel({ item, port, onClose }) {
7254
7336
  live = false;
7255
7337
  };
7256
7338
  }, [sharing, item]);
7257
- (0, import_react33.useEffect)(() => {
7339
+ (0, import_react34.useEffect)(() => {
7258
7340
  const list = sharing.sentSecureLinks;
7259
7341
  if (!list) return;
7260
7342
  let live = true;
@@ -7267,9 +7349,9 @@ function SecureLinkPanel({ item, port, onClose }) {
7267
7349
  live = false;
7268
7350
  };
7269
7351
  }, [sharing, item, nonce]);
7270
- const [phoneTyped, setPhoneTyped] = (0, import_react33.useState)(false);
7271
- const prefilled = (0, import_react33.useRef)(false);
7272
- (0, import_react33.useEffect)(() => {
7352
+ const [phoneTyped, setPhoneTyped] = (0, import_react34.useState)(false);
7353
+ const prefilled = (0, import_react34.useRef)(false);
7354
+ (0, import_react34.useEffect)(() => {
7273
7355
  const lookup = sharing.phoneOnFile;
7274
7356
  if (!lookup || phoneTyped) return;
7275
7357
  const clear = () => {
@@ -7422,7 +7504,7 @@ function sentMeta(row, options) {
7422
7504
  }
7423
7505
 
7424
7506
  // src/devices/DevicesPanel.tsx
7425
- var import_react34 = require("react");
7507
+ var import_react35 = require("react");
7426
7508
  var import_confirm_opener12 = require("@ai-matrx/kit/confirm-opener");
7427
7509
  var import_controls28 = require("@ai-matrx/design-system/controls");
7428
7510
  var import_format12 = require("@ai-matrx/kit/format");
@@ -7513,10 +7595,10 @@ function ErrorLine2({ text }) {
7513
7595
  function DevicesPanel({ port, onClose }) {
7514
7596
  const confirmed = useConfirmed();
7515
7597
  const notify = useNotify();
7516
- const [devices, setDevices] = (0, import_react34.useState)(null);
7517
- const [error, setError] = (0, import_react34.useState)(null);
7518
- const [busyId, setBusyId] = (0, import_react34.useState)(null);
7519
- const load = (0, import_react34.useCallback)(async () => {
7598
+ const [devices, setDevices] = (0, import_react35.useState)(null);
7599
+ const [error, setError] = (0, import_react35.useState)(null);
7600
+ const [busyId, setBusyId] = (0, import_react35.useState)(null);
7601
+ const load = (0, import_react35.useCallback)(async () => {
7520
7602
  setError(null);
7521
7603
  try {
7522
7604
  setDevices(await port.devices.list());
@@ -7524,7 +7606,7 @@ function DevicesPanel({ port, onClose }) {
7524
7606
  setError(messageOf3(e, "Your browsers could not be read."));
7525
7607
  }
7526
7608
  }, [port]);
7527
- (0, import_react34.useEffect)(() => {
7609
+ (0, import_react35.useEffect)(() => {
7528
7610
  void load();
7529
7611
  }, [load]);
7530
7612
  const revoke = async (device) => {
@@ -7582,11 +7664,11 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7582
7664
  const where = isMac ? "the Mac app" : "the extension";
7583
7665
  const passkeys = port.devices.passkeys;
7584
7666
  const here = passkeys?.available() ?? false;
7585
- const [methods, setMethods] = (0, import_react34.useState)(null);
7586
- const [busy, setBusy] = (0, import_react34.useState)(null);
7587
- const [error, setError] = (0, import_react34.useState)(null);
7588
- const [approvedUntil, setApprovedUntil] = (0, import_react34.useState)(null);
7589
- const load = (0, import_react34.useCallback)(async () => {
7667
+ const [methods, setMethods] = (0, import_react35.useState)(null);
7668
+ const [busy, setBusy] = (0, import_react35.useState)(null);
7669
+ const [error, setError] = (0, import_react35.useState)(null);
7670
+ const [approvedUntil, setApprovedUntil] = (0, import_react35.useState)(null);
7671
+ const load = (0, import_react35.useCallback)(async () => {
7590
7672
  setError(null);
7591
7673
  try {
7592
7674
  setMethods(await port.devices.stepUpMethods());
@@ -7594,7 +7676,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7594
7676
  setError(messageOf3(e, "Your account could not be checked."));
7595
7677
  }
7596
7678
  }, [port]);
7597
- (0, import_react34.useEffect)(() => {
7679
+ (0, import_react35.useEffect)(() => {
7598
7680
  if (key && here) void load();
7599
7681
  }, [key, here, load]);
7600
7682
  const approve = async () => {
@@ -7682,7 +7764,7 @@ function ApprovePanel({ port, host, onClose, approvalKey, label, kind = "browser
7682
7764
  }
7683
7765
 
7684
7766
  // src/native/NativeImportPanel.tsx
7685
- var import_react36 = require("react");
7767
+ var import_react37 = require("react");
7686
7768
  var import_confirm_opener13 = require("@ai-matrx/kit/confirm-opener");
7687
7769
  var import_controls29 = require("@ai-matrx/design-system/controls");
7688
7770
 
@@ -7745,19 +7827,19 @@ async function loadFullPreview(bridge, operationId, current) {
7745
7827
  }
7746
7828
 
7747
7829
  // src/native/use-native-import.ts
7748
- var import_react35 = require("react");
7830
+ var import_react36 = require("react");
7749
7831
  var fail = (e, fallback) => e instanceof Error && e.message ? e.message : fallback;
7750
7832
  var RESTART = "Your account changed. The import was stopped; start it again.";
7751
7833
  function useNativeImport(bridge, stillAllowed, onImported) {
7752
- const [screen, setScreen] = (0, import_react35.useState)({ kind: "idle", message: null });
7753
- const [busy, setBusy] = (0, import_react35.useState)(false);
7754
- const generation = (0, import_react35.useRef)(0);
7755
- const mounted = (0, import_react35.useRef)(false);
7756
- const op = (0, import_react35.useRef)(null);
7757
- const last = (0, import_react35.useRef)(null);
7758
- const timer2 = (0, import_react35.useRef)(null);
7759
- const polls = (0, import_react35.useRef)(0);
7760
- const refreshRef = (0, import_react35.useRef)(async () => void 0);
7834
+ const [screen, setScreen] = (0, import_react36.useState)({ kind: "idle", message: null });
7835
+ const [busy, setBusy] = (0, import_react36.useState)(false);
7836
+ const generation = (0, import_react36.useRef)(0);
7837
+ const mounted = (0, import_react36.useRef)(false);
7838
+ const op = (0, import_react36.useRef)(null);
7839
+ const last = (0, import_react36.useRef)(null);
7840
+ const timer2 = (0, import_react36.useRef)(null);
7841
+ const polls = (0, import_react36.useRef)(0);
7842
+ const refreshRef = (0, import_react36.useRef)(async () => void 0);
7761
7843
  const current = (g) => mounted.current && g === generation.current;
7762
7844
  const stopPolling = () => {
7763
7845
  if (timer2.current !== null) clearTimeout(timer2.current);
@@ -7926,9 +8008,9 @@ function useNativeImport(bridge, stillAllowed, onImported) {
7926
8008
  setBusy(false);
7927
8009
  setScreen({ kind: "idle", message: null });
7928
8010
  };
7929
- const invalidateRef = (0, import_react35.useRef)(invalidate);
8011
+ const invalidateRef = (0, import_react36.useRef)(invalidate);
7930
8012
  invalidateRef.current = invalidate;
7931
- (0, import_react35.useEffect)(() => {
8013
+ (0, import_react36.useEffect)(() => {
7932
8014
  mounted.current = true;
7933
8015
  const off = bridge.subscribe?.(() => {
7934
8016
  if (op.current) invalidateRef.current(RESTART);
@@ -7960,14 +8042,14 @@ function NativeImportPanel({ bridge, readLimits, activeOrganizationId, organizat
7960
8042
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Importer, { bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged });
7961
8043
  }
7962
8044
  function Importer({ bridge, readLimits, activeOrganizationId, organizations, onClose, onChanged }) {
7963
- const options = (0, import_react36.useMemo)(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
7964
- const [organizationId, setOrganizationId] = (0, import_react36.useState)(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
7965
- const [limits, setLimits] = (0, import_react36.useState)(null);
7966
- const [limitError, setLimitError] = (0, import_react36.useState)(null);
8045
+ const options = (0, import_react37.useMemo)(() => organizations.map((o) => ({ value: o.id, label: o.name })), [organizations]);
8046
+ const [organizationId, setOrganizationId] = (0, import_react37.useState)(() => organizations.some((o) => o.id === activeOrganizationId) ? activeOrganizationId : organizations[0]?.id ?? "");
8047
+ const [limits, setLimits] = (0, import_react37.useState)(null);
8048
+ const [limitError, setLimitError] = (0, import_react37.useState)(null);
7967
8049
  const flow = useNativeImport(bridge, (id) => organizations.some((o) => o.id === id), onChanged);
7968
8050
  const { screen, busy } = flow;
7969
8051
  const orgName = organizations.find((o) => o.id === organizationId)?.name ?? "this organization";
7970
- (0, import_react36.useEffect)(() => {
8052
+ (0, import_react37.useEffect)(() => {
7971
8053
  if (!readLimits || !organizationId) return;
7972
8054
  let live = true;
7973
8055
  setLimits(null);
@@ -8028,21 +8110,21 @@ function Importer({ bridge, readLimits, activeOrganizationId, organizations, onC
8028
8110
  }
8029
8111
 
8030
8112
  // src/extension/PageView.tsx
8031
- var import_react40 = require("react");
8113
+ var import_react41 = require("react");
8032
8114
  var import_design_system23 = require("@ai-matrx/design-system");
8033
8115
  var import_controls33 = require("@ai-matrx/design-system/controls");
8034
8116
  var import_icons15 = require("@ai-matrx/design-system/icons");
8035
8117
 
8036
8118
  // src/extension/CaptureCard.tsx
8037
- var import_react37 = require("react");
8119
+ var import_react38 = require("react");
8038
8120
  var import_controls30 = require("@ai-matrx/design-system/controls");
8039
8121
  var import_jsx_runtime35 = require("react/jsx-runtime");
8040
8122
  var SEARCH_FROM = 4;
8041
8123
  function CaptureCard({ capture, onChanged }) {
8042
- const prompt = (0, import_react37.useSyncExternalStore)(capture.subscribe, capture.get, capture.get);
8124
+ const prompt = (0, import_react38.useSyncExternalStore)(capture.subscribe, capture.get, capture.get);
8043
8125
  const notify = useNotify();
8044
- const [busy, setBusy] = (0, import_react37.useState)(false);
8045
- const [q, setQ] = (0, import_react37.useState)("");
8126
+ const [busy, setBusy] = (0, import_react38.useState)(false);
8127
+ const [q, setQ] = (0, import_react38.useState)("");
8046
8128
  if (!prompt) return null;
8047
8129
  const decide = async (d) => {
8048
8130
  setBusy(true);
@@ -8098,15 +8180,15 @@ function CaptureCard({ capture, onChanged }) {
8098
8180
  }
8099
8181
 
8100
8182
  // src/extension/FillSetupCard.tsx
8101
- var import_react38 = require("react");
8183
+ var import_react39 = require("react");
8102
8184
  var import_controls31 = require("@ai-matrx/design-system/controls");
8103
8185
  var import_jsx_runtime36 = require("react/jsx-runtime");
8104
8186
  function FillSetupCard({ fillSetup }) {
8105
8187
  const notify = useNotify();
8106
- const state = (0, import_react38.useSyncExternalStore)(fillSetup.subscribe, fillSetup.get, fillSetup.get);
8107
- const box = (0, import_react38.useRef)(null);
8108
- const [busy, setBusy] = (0, import_react38.useState)(false);
8109
- const [error, setError] = (0, import_react38.useState)(null);
8188
+ const state = (0, import_react39.useSyncExternalStore)(fillSetup.subscribe, fillSetup.get, fillSetup.get);
8189
+ const box = (0, import_react39.useRef)(null);
8190
+ const [busy, setBusy] = (0, import_react39.useState)(false);
8191
+ const [error, setError] = (0, import_react39.useState)(null);
8110
8192
  if (state.status !== "off") return null;
8111
8193
  const finish = async (run) => {
8112
8194
  setBusy(true);
@@ -8171,7 +8253,7 @@ function FillSetupCard({ fillSetup }) {
8171
8253
  }
8172
8254
 
8173
8255
  // src/extension/PageGenerator.tsx
8174
- var import_react39 = require("react");
8256
+ var import_react40 = require("react");
8175
8257
  var import_design_system22 = require("@ai-matrx/design-system");
8176
8258
  var import_controls32 = require("@ai-matrx/design-system/controls");
8177
8259
  var import_icons14 = require("@ai-matrx/design-system/icons");
@@ -8181,10 +8263,10 @@ function PageGenerator({ fields }) {
8181
8263
  const limits = useGeneratorLimitsSource();
8182
8264
  const copy = useCopy();
8183
8265
  const held = useTransientSecret(HOLD_MS);
8184
- const [open, setOpen] = (0, import_react39.useState)(false);
8185
- const [busy, setBusy] = (0, import_react39.useState)(false);
8186
- const [targets, setTargets] = (0, import_react39.useState)([]);
8187
- const [said, setSaid] = (0, import_react39.useState)(null);
8266
+ const [open, setOpen] = (0, import_react40.useState)(false);
8267
+ const [busy, setBusy] = (0, import_react40.useState)(false);
8268
+ const [targets, setTargets] = (0, import_react40.useState)([]);
8269
+ const [said, setSaid] = (0, import_react40.useState)(null);
8188
8270
  if (!limits) return null;
8189
8271
  const say3 = setSaid;
8190
8272
  const put = async (targetId, value2) => {
@@ -8248,8 +8330,8 @@ function PageGenerator({ fields }) {
8248
8330
  // src/extension/PageView.tsx
8249
8331
  var import_jsx_runtime38 = require("react/jsx-runtime");
8250
8332
  function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, items, definitions, onOpen, onNewForPage, onBrowse, onChanged, header }) {
8251
- const [running, setRunning] = (0, import_react40.useState)(null);
8252
- const [said, setSaid] = (0, import_react40.useState)(null);
8333
+ const [running, setRunning] = (0, import_react41.useState)(null);
8334
+ const [said, setSaid] = (0, import_react41.useState)(null);
8253
8335
  const site = pageSite(page.url);
8254
8336
  const state = page.matchState ?? { status: "ready" };
8255
8337
  const fillable = new Set(page.fillableItemIds ?? page.matchingItemIds);
@@ -8258,8 +8340,8 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
8258
8340
  const familyOf2 = (key) => definitions.find((d) => d.key === key)?.family ?? "generic";
8259
8341
  const canSave = isFillablePage(page.url);
8260
8342
  const signIn = page.signIn;
8261
- const act = async (itemId, run, failed) => {
8262
- setRunning(itemId);
8343
+ const act = async (itemId, action, run, failed) => {
8344
+ setRunning({ itemId, action });
8263
8345
  setSaid(null);
8264
8346
  try {
8265
8347
  setSaid(await run());
@@ -8292,10 +8374,10 @@ function PageView({ port, page, fill, capture, fillSetup, newPasswordFields, ite
8292
8374
  family: item ? familyOf2(item.definitionKey) : "generic",
8293
8375
  port,
8294
8376
  busy: running !== null,
8295
- running: running === itemId,
8377
+ running: running?.itemId === itemId ? running.action : null,
8296
8378
  onOpen,
8297
- onFill: fill && !page.blocked && fillable.has(itemId) && item?.capabilities.canUse !== false ? () => void act(itemId, async () => FILL_WORDS[await fill(itemId)], FILL_WORDS.unavailable) : null,
8298
- onSignIn: signIn ? () => void act(itemId, async () => SIGN_IN_WORDS[await signIn(itemId)], SIGN_IN_WORDS.unknown) : null
8379
+ 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,
8380
+ onSignIn: signIn ? () => void act(itemId, "signIn", async () => SIGN_IN_WORDS[await signIn(itemId)], SIGN_IN_WORDS.unknown) : null
8299
8381
  },
8300
8382
  itemId
8301
8383
  )) });
@@ -8333,7 +8415,7 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
8333
8415
  const confirmed = useConfirmed();
8334
8416
  const copy = useCopy();
8335
8417
  const notify = useNotify();
8336
- const [reading, setReading] = (0, import_react40.useState)(false);
8418
+ const [reading, setReading] = (0, import_react41.useState)(false);
8337
8419
  const usable = item?.capabilities.canUse ?? false;
8338
8420
  const user = usable ? item?.fields.find((f) => USERNAME_KEYS.test(f.key) && f.handling !== "sealed" && f.active) : void 0;
8339
8421
  const secret = usable && item?.capabilities.canReveal ? item?.fields.find((f) => f.key === "password" && f.handling === "revealable" && f.active) : void 0;
@@ -8362,8 +8444,8 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
8362
8444
  className: "min-w-0 flex-1"
8363
8445
  }
8364
8446
  ),
8365
- onFill ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "primary", disabled: busy, "aria-busy": running || void 0, onClick: onFill, "aria-label": `Fill ${item?.name ?? "this login"}`, children: running ? "Filling\u2026" : "Fill" }) : null,
8366
- onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ShieldGlyph, {}), disabled: busy, onClick: onSignIn, "aria-label": `Sign me in with ${item?.name ?? "this login"}`, title: "Sign me in", children: "Sign me in" }) : null,
8447
+ onFill ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { 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,
8448
+ onSignIn ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: onFill ? "outline" : "primary", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(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,
8367
8449
  user && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(UserGlyph, {}), "aria-label": `Copy ${user.label}`, title: `Copy ${user.label}`, disabled: reading, onClick: () => void read(user.label, () => port.reveal(item, user.key)) }) : null,
8368
8450
  secret && item ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(KeyGlyph, {}), "aria-label": "Copy password", title: "Copy password", disabled: reading, onClick: () => void read("Password", () => port.reveal(item, secret.key)) }) : null,
8369
8451
  otp ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_controls33.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(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
@@ -8371,7 +8453,7 @@ function MatchRow({ itemId, item, tag, family, port, busy, running, onOpen, onFi
8371
8453
  }
8372
8454
 
8373
8455
  // src/Sidebar.tsx
8374
- var import_react41 = require("react");
8456
+ var import_react42 = require("react");
8375
8457
  var import_design_system24 = require("@ai-matrx/design-system");
8376
8458
  var import_controls34 = require("@ai-matrx/design-system/controls");
8377
8459
  var import_icons16 = require("@ai-matrx/design-system/icons");
@@ -8380,6 +8462,7 @@ var AUTHENTICATOR_LABEL = "Authenticator";
8380
8462
  function vaultChoices(items, organizations, _current) {
8381
8463
  const n = (f) => items.filter(f).length;
8382
8464
  const shared = n((i) => i.owner.kind === "shared");
8465
+ const hints = organizationHints(organizations);
8383
8466
  return [
8384
8467
  { value: "all", label: "All items", count: items.length },
8385
8468
  { value: "mine", label: "Personal", count: n((i) => i.owner.kind === "me") },
@@ -8387,11 +8470,11 @@ function vaultChoices(items, organizations, _current) {
8387
8470
  // Every organization the person belongs to, empty ones too: an empty vault opens on its own
8388
8471
  // "Nothing here yet" with New item, so the first credential can go there. (The organization
8389
8472
  // list carries no role, so who may add is the server's answer to the save, said in place.)
8390
- ...organizations.map((o) => ({ value: o.id, label: o.name, count: n((i) => i.owner.organizationId === o.id) }))
8473
+ ...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) } : {} }))
8391
8474
  ];
8392
8475
  }
8393
- function VaultSelect({ value, choices, onChange }) {
8394
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Select, { value, onValueChange: onChange, "aria-label": "Vault", options: choices.map((c) => ({ value: c.value, label: c.label, meta: String(c.count) })) });
8476
+ function VaultSelect({ value, choices, onChange, searchAt = ORGANIZATION_SEARCH_AT_UNREAD }) {
8477
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_controls34.Select, { 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 } : {} })) });
8395
8478
  }
8396
8479
  var CATEGORY_GLYPHS = { logins: import_icons16.GlobeIcon, passkeys: ShieldGlyph, api: KeyGlyph, oauth: PlugGlyph, infra: DatabaseGlyph, env: TerminalGlyph, files: FileGlyph, other: NoteGlyph };
8397
8480
  var familyOf = (key, definitions) => definitions.find((d) => d.key === key)?.family ?? "generic";
@@ -8455,12 +8538,14 @@ function viewOptions(views, allCount, deletedCount, hasFavorites, hasRecents, ha
8455
8538
  ];
8456
8539
  }
8457
8540
  function Entry({ on, glyph: Icon, label, count: count2, onClick, nested = false }) {
8541
+ const desktop = (0, import_design_system24.useLook)() === "desktop";
8458
8542
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
8459
8543
  import_controls34.Tile,
8460
8544
  {
8461
8545
  type: "button",
8462
8546
  "aria-current": on ? "page" : void 0,
8463
8547
  selected: on,
8548
+ ...desktop ? { selectedStyle: "fill" } : {},
8464
8549
  onClick,
8465
8550
  layout: "row",
8466
8551
  variant: "quiet",
@@ -8468,8 +8553,9 @@ function Entry({ on, glyph: Icon, label, count: count2, onClick, nested = false
8468
8553
  icon: nested ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Icon, { className: "size-4 shrink-0" }),
8469
8554
  title: label,
8470
8555
  ...count2 !== void 0 ? { end: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs tabular-nums text-muted-foreground", children: count2 }) } : {},
8556
+ ...nested ? { level: 1 } : {},
8471
8557
  "data-nested": nested ? "" : void 0,
8472
- className: (0, import_design_system24.cn)("w-full", nested && "pl-9")
8558
+ className: "w-full"
8473
8559
  }
8474
8560
  );
8475
8561
  }
@@ -8479,12 +8565,12 @@ function Group({ title, children }) {
8479
8565
  children
8480
8566
  ] });
8481
8567
  }
8482
- function VaultSidebar({ vault, choices, onVault, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
8483
- const [tagsOpen, setTagsOpen] = (0, import_react41.useState)(view.startsWith("tag:"));
8568
+ function VaultSidebar({ vault, choices, onVault, organizationSearchAt, view, allCount, deletedCount, views, hasFavorites, hasRecents, onView, onPanel, nativeProvider, hasNativeImport = false, hasPage = false, onLock, onOpenWeb }) {
8569
+ const [tagsOpen, setTagsOpen] = (0, import_react42.useState)(view.startsWith("tag:"));
8484
8570
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("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: [
8485
8571
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 px-3 pb-2 pt-3", children: [
8486
8572
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(SafeGlyph, { className: "size-5 shrink-0 text-primary" }),
8487
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(VaultSelect, { value: vault, choices, onChange: onVault }) })
8573
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(VaultSelect, { value: vault, choices, onChange: onVault, searchAt: organizationSearchAt }) })
8488
8574
  ] }),
8489
8575
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto px-2 pb-3 pt-1", children: [
8490
8576
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
@@ -8561,8 +8647,8 @@ var generatorLimitsFrom = (knobs) => knobs ? async () => {
8561
8647
  } : void 0;
8562
8648
  function ImportWithLimits(props) {
8563
8649
  const { knobs, ...rest } = props;
8564
- const [state, setState] = (0, import_react42.useState)(null);
8565
- (0, import_react42.useEffect)(() => {
8650
+ const [state, setState] = (0, import_react43.useState)(null);
8651
+ (0, import_react43.useEffect)(() => {
8566
8652
  if (!knobs) return setState({ error: "Import is not set up for this organization yet." });
8567
8653
  knobs().then(
8568
8654
  (r) => {
@@ -8582,18 +8668,18 @@ function VaultApp(given) {
8582
8668
  const props = { ...given, host: useOrganizationSettings(given.host ?? NO_HOST) };
8583
8669
  const lock = props.host?.lock;
8584
8670
  const locked = useLocked(lock);
8585
- const port = (0, import_react42.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
8671
+ const port = (0, import_react43.useMemo)(() => lock ? guardPort(props.port, () => lock.locked()) : props.port, [props.port, lock]);
8586
8672
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_design_system25.LookScope, { look: props.look ?? "web", className: "h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "relative h-full min-h-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(NoticeProvider, { notify: props.notify, children: lock && locked ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LockedScreen, { lock }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ClipboardProvider, { clipboard: props.host?.clipboard, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(RevealSecondsProvider, { seconds: props.host?.revealSeconds, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(IdentityGate, { identity: props.host?.identity, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(GeneratorLimitsProvider, { resolve: generatorLimitsFrom(props.host?.knobs), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Workspace, { ...props, port }) }) }) }) }) }) }) });
8587
8673
  }
8588
8674
  function useOrganizationSettings(host) {
8589
8675
  const knobs = host.knobs;
8590
- const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0);
8591
- const [read, setRead] = (0, import_react42.useState)(null);
8592
- (0, import_react42.useEffect)(() => {
8676
+ const needs = knobs !== void 0 && (host.revealSeconds === void 0 || host.backupPassphraseMinLength === void 0 || host.organizationSearchAt === void 0);
8677
+ const [read, setRead] = (0, import_react43.useState)(null);
8678
+ (0, import_react43.useEffect)(() => {
8593
8679
  if (!needs || !knobs) return;
8594
8680
  let live = true;
8595
8681
  knobs().then(
8596
- (r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB) }),
8682
+ (r) => live && setRead({ reveal: positiveKnob(r, REVEAL_SECONDS_KNOB), backupMin: positiveKnob(r, BACKUP_PASSPHRASE_MIN_KNOB), searchAt: positiveKnob(r, ORGANIZATION_SEARCH_AT_KNOB) }),
8597
8683
  () => void 0
8598
8684
  );
8599
8685
  return () => {
@@ -8604,19 +8690,20 @@ function useOrganizationSettings(host) {
8604
8690
  return {
8605
8691
  ...host,
8606
8692
  ...host.revealSeconds === void 0 && read.reveal !== null ? { revealSeconds: read.reveal } : {},
8607
- ...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {}
8693
+ ...host.backupPassphraseMinLength === void 0 && read.backupMin !== null ? { backupPassphraseMinLength: read.backupMin } : {},
8694
+ ...host.organizationSearchAt === void 0 && read.searchAt !== null ? { organizationSearchAt: read.searchAt } : {}
8608
8695
  };
8609
8696
  }
8610
8697
  var NO_STORE = () => () => void 0;
8611
8698
  var NOTHING = () => null;
8612
8699
  function useHostPrompts(capture, fillSetup) {
8613
- const prompt = (0, import_react42.useSyncExternalStore)(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
8614
- const setup = (0, import_react42.useSyncExternalStore)(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
8700
+ const prompt = (0, import_react43.useSyncExternalStore)(capture ? capture.subscribe : NO_STORE, capture ? capture.get : NOTHING, capture ? capture.get : NOTHING);
8701
+ const setup = (0, import_react43.useSyncExternalStore)(fillSetup ? fillSetup.subscribe : NO_STORE, fillSetup ? fillSetup.get : NOTHING, fillSetup ? fillSetup.get : NOTHING);
8615
8702
  return prompt !== null || setup?.status === "off";
8616
8703
  }
8617
8704
  function LockedScreen({ lock }) {
8618
- const [busy, setBusy] = (0, import_react42.useState)(false);
8619
- const [error, setError] = (0, import_react42.useState)(null);
8705
+ const [busy, setBusy] = (0, import_react43.useState)(false);
8706
+ const [error, setError] = (0, import_react43.useState)(null);
8620
8707
  const unlock = async () => {
8621
8708
  setBusy(true);
8622
8709
  setError(null);
@@ -8636,29 +8723,29 @@ function LockedScreen({ lock }) {
8636
8723
  ] });
8637
8724
  }
8638
8725
  function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocationChange, onInventory }) {
8639
- const rootRef = (0, import_react42.useRef)(null);
8726
+ const rootRef = (0, import_react43.useRef)(null);
8640
8727
  const width = useElementWidth(rootRef);
8641
8728
  const mode = layout !== "auto" ? layout : width >= FULL_AT ? "full" : width >= SPLIT_AT ? "split" : "stack";
8642
8729
  const notify = useNotify();
8643
- const [snap, setSnap] = (0, import_react42.useState)(null);
8644
- const [items, setItems] = (0, import_react42.useState)([]);
8645
- const [deleted, setDeleted] = (0, import_react42.useState)([]);
8646
- const [favorites, setFavorites] = (0, import_react42.useState)(null);
8647
- const [recents, setRecents] = (0, import_react42.useState)(null);
8648
- const [error, setError] = (0, import_react42.useState)(null);
8649
- const [inner, setInner] = (0, import_react42.useState)(DEFAULT_LOCATION);
8730
+ const [snap, setSnap] = (0, import_react43.useState)(null);
8731
+ const [items, setItems] = (0, import_react43.useState)([]);
8732
+ const [deleted, setDeleted] = (0, import_react43.useState)([]);
8733
+ const [favorites, setFavorites] = (0, import_react43.useState)(null);
8734
+ const [recents, setRecents] = (0, import_react43.useState)(null);
8735
+ const [error, setError] = (0, import_react43.useState)(null);
8736
+ const [inner, setInner] = (0, import_react43.useState)(DEFAULT_LOCATION);
8650
8737
  const loc = location ?? inner;
8651
- const dirty = (0, import_react42.useRef)(false);
8652
- const [notice, setNotice] = (0, import_react42.useState)(null);
8653
- const [firstCode, setFirstCode] = (0, import_react42.useState)(null);
8654
- const move = (0, import_react42.useCallback)(
8738
+ const dirty = (0, import_react43.useRef)(false);
8739
+ const [notice, setNotice] = (0, import_react43.useState)(null);
8740
+ const [firstCode, setFirstCode] = useShownUntilMove(loc);
8741
+ const move = (0, import_react43.useCallback)(
8655
8742
  (next, how) => {
8656
8743
  if (!location) setInner(next);
8657
8744
  onLocationChange?.(next, how);
8658
8745
  },
8659
8746
  [location, onLocationChange]
8660
8747
  );
8661
- const go = (0, import_react42.useCallback)(
8748
+ const go = (0, import_react43.useCallback)(
8662
8749
  (patch, how = "push") => {
8663
8750
  const leaving = patch.itemId !== void 0 || patch.mode !== void 0 || patch.vault !== void 0 || patch.view !== void 0;
8664
8751
  const next = { ...loc, ...patch };
@@ -8677,9 +8764,9 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8677
8764
  },
8678
8765
  [loc, move]
8679
8766
  );
8680
- const keyState = (0, import_react42.useRef)({ loc, go });
8767
+ const keyState = (0, import_react43.useRef)({ loc, go });
8681
8768
  keyState.current = { loc, go };
8682
- (0, import_react42.useEffect)(() => {
8769
+ (0, import_react43.useEffect)(() => {
8683
8770
  const onKey = (e) => {
8684
8771
  if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
8685
8772
  const root = rootRef.current;
@@ -8701,8 +8788,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8701
8788
  document.addEventListener("keydown", onKey);
8702
8789
  return () => document.removeEventListener("keydown", onKey);
8703
8790
  }, []);
8704
- const keepSearchFocus = (0, import_react42.useRef)(false);
8705
- (0, import_react42.useEffect)(() => {
8791
+ const keepSearchFocus = (0, import_react43.useRef)(false);
8792
+ (0, import_react43.useEffect)(() => {
8706
8793
  if (!keepSearchFocus.current) return;
8707
8794
  keepSearchFocus.current = false;
8708
8795
  const search = rootRef.current?.querySelector('input[aria-label^="Search"]');
@@ -8711,14 +8798,14 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8711
8798
  search.setSelectionRange(search.value.length, search.value.length);
8712
8799
  }, [loc.q]);
8713
8800
  const hasPrompts = useHostPrompts(host.capture, host.fillSetup);
8714
- const knobsRef = (0, import_react42.useRef)(host.knobs);
8801
+ const knobsRef = (0, import_react43.useRef)(host.knobs);
8715
8802
  knobsRef.current = host.knobs;
8716
- const [signedOut, setSignedOut] = (0, import_react42.useState)(false);
8717
- const [refreshError, setRefreshError] = (0, import_react42.useState)(null);
8718
- const [refreshing, setRefreshing] = (0, import_react42.useState)(false);
8719
- const loadedAt = (0, import_react42.useRef)(0);
8720
- const inFlight = (0, import_react42.useRef)(false);
8721
- const apply = (0, import_react42.useCallback)(
8803
+ const [signedOut, setSignedOut] = (0, import_react43.useState)(false);
8804
+ const [refreshError, setRefreshError] = (0, import_react43.useState)(null);
8805
+ const [refreshing, setRefreshing] = (0, import_react43.useState)(false);
8806
+ const loadedAt = (0, import_react43.useRef)(0);
8807
+ const inFlight = (0, import_react43.useRef)(false);
8808
+ const apply = (0, import_react43.useCallback)(
8722
8809
  (s) => {
8723
8810
  loadedAt.current = Date.now();
8724
8811
  setSnap(s);
@@ -8731,7 +8818,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8731
8818
  },
8732
8819
  [port]
8733
8820
  );
8734
- const refresh = (0, import_react42.useCallback)(() => {
8821
+ const refresh = (0, import_react43.useCallback)(() => {
8735
8822
  if (inFlight.current) return;
8736
8823
  inFlight.current = true;
8737
8824
  setRefreshing(true);
@@ -8745,7 +8832,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8745
8832
  port.lists.favorites?.list().then((ids) => setFavorites(new Set(ids)), () => void 0);
8746
8833
  port.lists.recents?.list().then(setRecents, () => void 0);
8747
8834
  }, [port, apply]);
8748
- const load = (0, import_react42.useCallback)(() => {
8835
+ const load = (0, import_react43.useCallback)(() => {
8749
8836
  setError(null);
8750
8837
  setRefreshError(null);
8751
8838
  let finished = false;
@@ -8765,11 +8852,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8765
8852
  knobsRef.current?.().catch(() => void 0);
8766
8853
  port.lists.recents?.list().then(setRecents, () => void 0);
8767
8854
  }, [port, apply]);
8768
- (0, import_react42.useEffect)(load, [load]);
8769
- const quietRef = (0, import_react42.useRef)({ loc, ready: false });
8855
+ (0, import_react43.useEffect)(load, [load]);
8856
+ const quietRef = (0, import_react43.useRef)({ loc, ready: false });
8770
8857
  quietRef.current = { loc, ready: snap !== null && !error };
8771
- const [knobSeconds, setKnobSeconds] = (0, import_react42.useState)(null);
8772
- (0, import_react42.useEffect)(() => {
8858
+ const [knobSeconds, setKnobSeconds] = (0, import_react43.useState)(null);
8859
+ (0, import_react43.useEffect)(() => {
8773
8860
  if (host.refreshSeconds !== void 0 || !knobsRef.current) return;
8774
8861
  let live = true;
8775
8862
  knobsRef.current().then(
@@ -8784,7 +8871,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8784
8871
  };
8785
8872
  }, [host.refreshSeconds]);
8786
8873
  const everySeconds = host.refreshSeconds ?? knobSeconds;
8787
- (0, import_react42.useEffect)(() => {
8874
+ (0, import_react43.useEffect)(() => {
8788
8875
  const quietly = (minGapMs) => {
8789
8876
  const { loc: here, ready } = quietRef.current;
8790
8877
  if (!ready || document.visibilityState === "hidden" || dirty.current || here.mode !== "view") return;
@@ -8802,22 +8889,22 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8802
8889
  if (timer2) clearInterval(timer2);
8803
8890
  };
8804
8891
  }, [refresh, everySeconds]);
8805
- const inventoryRef = (0, import_react42.useRef)(onInventory);
8892
+ const inventoryRef = (0, import_react43.useRef)(onInventory);
8806
8893
  inventoryRef.current = onInventory;
8807
- (0, import_react42.useEffect)(() => {
8894
+ (0, import_react43.useEffect)(() => {
8808
8895
  if (snap) inventoryRef.current?.({ items, definitions: snap.definitions });
8809
8896
  }, [snap, items]);
8810
- (0, import_react42.useEffect)(() => {
8897
+ (0, import_react43.useEffect)(() => {
8811
8898
  if (!loc.itemId || !port.lists.recents) return;
8812
8899
  const id = loc.itemId;
8813
8900
  port.lists.recents.record(id).then(() => setRecents((r) => [id, ...(r ?? []).filter((x) => x !== id)]), () => void 0);
8814
8901
  }, [loc.itemId, port]);
8815
- const orgs = snap?.organizations ?? [];
8902
+ const orgs = (0, import_react43.useMemo)(() => orderOrganizations(snap?.organizations ?? [], items, recents), [snap?.organizations, items, recents]);
8816
8903
  const definitions = snap?.definitions ?? [];
8817
- const inThisVault = (0, import_react42.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
8904
+ const inThisVault = (0, import_react43.useMemo)(() => items.filter((i) => inVault(i, loc.vault)), [items, loc.vault]);
8818
8905
  const vaultMixesOwners = new Set(inThisVault.map((i) => i.owner.organizationId ?? i.owner.kind)).size > 1;
8819
- const views = (0, import_react42.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
8820
- const visible = (0, import_react42.useMemo)(() => {
8906
+ const views = (0, import_react43.useMemo)(() => buildViews(inThisVault, definitions, favorites, recents), [inThisVault, definitions, favorites, recents]);
8907
+ const visible = (0, import_react43.useMemo)(() => {
8821
8908
  const filtered = inThisVault.filter((i) => {
8822
8909
  if (!matchesQuery(i, loc.q, familyLabel(itemFamily(i, definitions)))) return false;
8823
8910
  if (loc.view === "favorites") return favorites?.has(i.id) ?? false;
@@ -8829,8 +8916,8 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8829
8916
  if (loc.view === "recent" && recents) return [...filtered].sort((a, b) => recents.indexOf(a.id) - recents.indexOf(b.id));
8830
8917
  return sortItems(filtered, loc.sort, recents);
8831
8918
  }, [inThisVault, loc.view, loc.q, loc.sort, favorites, recents, definitions]);
8832
- const choices = (0, import_react42.useMemo)(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
8833
- const matchingIds = (0, import_react42.useMemo)(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
8919
+ const choices = (0, import_react43.useMemo)(() => vaultChoices(items, orgs, loc.vault), [items, orgs, loc.vault]);
8920
+ const matchingIds = (0, import_react43.useMemo)(() => host.page ? new Set(host.page.matchingItemIds) : void 0, [host.page]);
8834
8921
  const selected = loc.itemId ? items.find((i) => i.id === loc.itemId) ?? null : null;
8835
8922
  const replaceItem = (next) => setItems((cur) => cur.some((i) => i.id === next.id) ? cur.map((i) => i.id === next.id ? next : i) : [...cur, next]);
8836
8923
  const toggleFavorite = (id) => {
@@ -8895,7 +8982,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
8895
8982
  const hasFavorites = port.lists.favorites !== void 0;
8896
8983
  const title = loc.vault === "all" && loc.view === "all" ? "All items" : viewLabel(loc.view, views);
8897
8984
  const compactHeader = mode === "full" ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-[repeat(auto-fit,minmax(11rem,1fr))] gap-2", "data-vault-compact-header": "", children: [
8898
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(VaultSelect, { value: loc.vault, choices, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8985
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(VaultSelect, { value: loc.vault, choices, searchAt: host.organizationSearchAt, onChange: (vault) => go({ vault, itemId: null, panel: null }) }),
8899
8986
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_controls35.Select, { 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" })
8900
8987
  ] });
8901
8988
  const compactActions = mode === "full" ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex shrink-0 items-center gap-2", "data-vault-compact-actions": "", children: [
@@ -9132,6 +9219,11 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
9132
9219
  arg: panelArg ?? null,
9133
9220
  onClose: closePanel,
9134
9221
  onPanel,
9222
+ onOpenItem: (next) => {
9223
+ replaceItem(next);
9224
+ const holds = loc.vault === "all" || loc.vault === "mine" && next.owner.kind === "me" || loc.vault === next.owner.organizationId;
9225
+ go({ ...holds ? {} : { vault: "all" }, itemId: next.id, mode: "view", panel: null });
9226
+ },
9135
9227
  onChanged: (next) => {
9136
9228
  if (next) replaceItem(next);
9137
9229
  else if (next === null) {
@@ -9171,6 +9263,7 @@ function Workspace({ port, host = NO_HOST, layout = "auto", location, onLocation
9171
9263
  vault: loc.vault,
9172
9264
  choices,
9173
9265
  onVault: (vault) => go({ vault, itemId: null, panel: null }),
9266
+ organizationSearchAt: host.organizationSearchAt,
9174
9267
  view: loc.view,
9175
9268
  allCount: inThisVault.length,
9176
9269
  deletedCount: deleted.length,