@codemem/server 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/static/app.js CHANGED
@@ -2106,8 +2106,8 @@
2106
2106
  var useLayoutEffect2 = globalThis?.document ? _$2 : () => {};
2107
2107
  //#endregion
2108
2108
  //#region ../../node_modules/.pnpm/@radix-ui+react-portal@1.1.9_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-portal/dist/index.mjs
2109
- var PORTAL_NAME$5 = "Portal";
2110
- var Portal$4 = D((props, forwardedRef) => {
2109
+ var PORTAL_NAME$6 = "Portal";
2110
+ var Portal$5 = D((props, forwardedRef) => {
2111
2111
  const { container: containerProp, ...portalProps } = props;
2112
2112
  const [mounted, setMounted] = d$2(false);
2113
2113
  useLayoutEffect2(() => setMounted(true), []);
@@ -2117,7 +2117,7 @@
2117
2117
  ref: forwardedRef
2118
2118
  }), container) : null;
2119
2119
  });
2120
- Portal$4.displayName = PORTAL_NAME$5;
2120
+ Portal$5.displayName = PORTAL_NAME$6;
2121
2121
  //#endregion
2122
2122
  //#region ../../node_modules/.pnpm/@radix-ui+react-presence@1.1.5_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-presence/dist/index.mjs
2123
2123
  function useStateMachine(initialState, machine) {
@@ -2686,7 +2686,7 @@
2686
2686
  const timer = window.setTimeout(() => setIsAnnounced(true), 1e3);
2687
2687
  return () => window.clearTimeout(timer);
2688
2688
  }, []);
2689
- return isAnnounced ? null : /* @__PURE__ */ u(Portal$4, {
2689
+ return isAnnounced ? null : /* @__PURE__ */ u(Portal$5, {
2690
2690
  asChild: true,
2691
2691
  children: /* @__PURE__ */ u(VisuallyHidden, {
2692
2692
  ...announceProps,
@@ -2733,10 +2733,10 @@
2733
2733
  });
2734
2734
  });
2735
2735
  ToastAction.displayName = ACTION_NAME;
2736
- var CLOSE_NAME$1 = "ToastClose";
2736
+ var CLOSE_NAME$2 = "ToastClose";
2737
2737
  var ToastClose = D((props, forwardedRef) => {
2738
2738
  const { __scopeToast, ...closeProps } = props;
2739
- const interactiveContext = useToastInteractiveContext(CLOSE_NAME$1, __scopeToast);
2739
+ const interactiveContext = useToastInteractiveContext(CLOSE_NAME$2, __scopeToast);
2740
2740
  return /* @__PURE__ */ u(ToastAnnounceExclude, {
2741
2741
  asChild: true,
2742
2742
  children: /* @__PURE__ */ u(Primitive.button, {
@@ -2747,7 +2747,7 @@
2747
2747
  })
2748
2748
  });
2749
2749
  });
2750
- ToastClose.displayName = CLOSE_NAME$1;
2750
+ ToastClose.displayName = CLOSE_NAME$2;
2751
2751
  var ToastAnnounceExclude = D((props, forwardedRef) => {
2752
2752
  const { __scopeToast, altText, ...announceExcludeProps } = props;
2753
2753
  return /* @__PURE__ */ u(Primitive.div, {
@@ -2825,7 +2825,7 @@
2825
2825
  }
2826
2826
  var Provider$1 = ToastProvider;
2827
2827
  var Viewport$1 = ToastViewport;
2828
- var Root2$5 = Toast;
2828
+ var Root2$6 = Toast;
2829
2829
  var Description = ToastDescription;
2830
2830
  var Close = ToastClose;
2831
2831
  //#endregion
@@ -2862,7 +2862,7 @@
2862
2862
  return /* @__PURE__ */ u(Provider$1, {
2863
2863
  duration: 8e3,
2864
2864
  swipeDirection: "right",
2865
- children: [items.map((item) => /* @__PURE__ */ u(Root2$5, {
2865
+ children: [items.map((item) => /* @__PURE__ */ u(Root2$6, {
2866
2866
  className: `toast-root toast-${item.variant}`,
2867
2867
  duration: item.durationMs,
2868
2868
  onOpenChange: (open) => {
@@ -3062,6 +3062,19 @@
3062
3062
  if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
3063
3063
  return payload;
3064
3064
  }
3065
+ async function moveMemoryProject(memoryId, project) {
3066
+ const resp = await fetch("/api/memories/project", {
3067
+ method: "POST",
3068
+ headers: { "Content-Type": "application/json" },
3069
+ body: JSON.stringify({
3070
+ memory_id: memoryId,
3071
+ project
3072
+ })
3073
+ });
3074
+ const { text, payload } = await readJsonPayload(resp);
3075
+ if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
3076
+ return payload;
3077
+ }
3065
3078
  async function forgetMemory(memoryId) {
3066
3079
  const resp = await fetch("/api/memories/forget", {
3067
3080
  method: "POST",
@@ -3213,6 +3226,26 @@
3213
3226
  if (!resp.ok) throw new Error(detail || payloadError(payload) || text || "request failed");
3214
3227
  return payload;
3215
3228
  }
3229
+ async function loadCoordinatorGroupPreferences(groupId) {
3230
+ const resp = await fetch(`/api/coordinator/admin/groups/${encodeURIComponent(groupId)}/preferences`);
3231
+ const { text, payload } = await readJsonPayload(resp);
3232
+ if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
3233
+ const prefs = payload?.preferences;
3234
+ if (!prefs) throw new Error("response missing preferences");
3235
+ return prefs;
3236
+ }
3237
+ async function saveCoordinatorGroupPreferences(groupId, input) {
3238
+ const resp = await fetch(`/api/coordinator/admin/groups/${encodeURIComponent(groupId)}/preferences`, {
3239
+ method: "PUT",
3240
+ headers: { "Content-Type": "application/json" },
3241
+ body: JSON.stringify(input)
3242
+ });
3243
+ const { text, payload } = await readJsonPayload(resp);
3244
+ if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
3245
+ const prefs = payload?.preferences;
3246
+ if (!prefs) throw new Error("response missing preferences");
3247
+ return prefs;
3248
+ }
3216
3249
  async function createActor(displayName) {
3217
3250
  const resp = await fetch("/api/sync/actors", {
3218
3251
  method: "POST",
@@ -3270,11 +3303,10 @@
3270
3303
  return payload;
3271
3304
  }
3272
3305
  async function triggerSync(address) {
3273
- const payload = address ? { address } : {};
3274
3306
  const resp = await fetch("/api/sync/run", {
3275
3307
  method: "POST",
3276
3308
  headers: { "Content-Type": "application/json" },
3277
- body: JSON.stringify(payload)
3309
+ body: JSON.stringify(address ? { address } : {})
3278
3310
  });
3279
3311
  const { text, payload: body } = await readJsonPayload(resp);
3280
3312
  if (!resp.ok) throw new Error(payloadError(body) || text || "request failed");
@@ -3380,6 +3412,7 @@
3380
3412
  lastSyncCoordinator: null,
3381
3413
  lastCoordinatorAdminStatus: null,
3382
3414
  coordinatorAdminTargetGroup: "",
3415
+ knownProjects: [],
3383
3416
  lastCoordinatorAdminGroups: [],
3384
3417
  lastCoordinatorAdminJoinRequests: [],
3385
3418
  lastCoordinatorAdminDevices: [],
@@ -3413,9 +3446,18 @@
3413
3446
  function resolveAccessibleTab(tab, status) {
3414
3447
  return getVisibleTabs(status).includes(tab) ? tab : "sync";
3415
3448
  }
3449
+ /**
3450
+ * Parse `window.location.hash` into its top-level tab segment. Hashes with
3451
+ * sub-view segments (e.g. `#sync/diagnostics`) return their leading tab
3452
+ * (`sync`); sub-view state is owned per-tab.
3453
+ */
3454
+ function parseTabFromHash(hash = window.location.hash) {
3455
+ const first = hash.replace(/^#/, "").split("/")[0];
3456
+ return ALL_TAB_IDS.includes(first) ? first : null;
3457
+ }
3416
3458
  function getActiveTab() {
3417
- const hash = window.location.hash.replace("#", "");
3418
- if (ALL_TAB_IDS.includes(hash)) return resolveAccessibleTab(hash, state.lastCoordinatorAdminStatus);
3459
+ const fromHash = parseTabFromHash();
3460
+ if (fromHash) return resolveAccessibleTab(fromHash, state.lastCoordinatorAdminStatus);
3419
3461
  const saved = localStorage.getItem(TAB_KEY);
3420
3462
  if (saved && ALL_TAB_IDS.includes(saved)) return resolveAccessibleTab(saved, state.lastCoordinatorAdminStatus);
3421
3463
  return "feed";
@@ -3423,8 +3465,8 @@
3423
3465
  function setActiveTab(tab) {
3424
3466
  const nextTab = resolveAccessibleTab(tab, state.lastCoordinatorAdminStatus);
3425
3467
  state.activeTab = nextTab;
3426
- window.location.hash = nextTab;
3427
3468
  localStorage.setItem(TAB_KEY, nextTab);
3469
+ if (parseTabFromHash() !== nextTab) window.location.hash = nextTab;
3428
3470
  }
3429
3471
  function getFeedTypeFilter() {
3430
3472
  const saved = localStorage.getItem(FEED_FILTER_KEY) || "all";
@@ -3777,10 +3819,10 @@
3777
3819
  });
3778
3820
  });
3779
3821
  TabsList.displayName = TAB_LIST_NAME;
3780
- var TRIGGER_NAME$5 = "TabsTrigger";
3822
+ var TRIGGER_NAME$6 = "TabsTrigger";
3781
3823
  var TabsTrigger = D((props, forwardedRef) => {
3782
3824
  const { __scopeTabs, value, disabled = false, ...triggerProps } = props;
3783
- const context = useTabsContext(TRIGGER_NAME$5, __scopeTabs);
3825
+ const context = useTabsContext(TRIGGER_NAME$6, __scopeTabs);
3784
3826
  const rovingFocusGroupScope = useRovingFocusGroupScope$2(__scopeTabs);
3785
3827
  const triggerId = makeTriggerId(context.baseId, value);
3786
3828
  const contentId = makeContentId(context.baseId, value);
@@ -3815,11 +3857,11 @@
3815
3857
  })
3816
3858
  });
3817
3859
  });
3818
- TabsTrigger.displayName = TRIGGER_NAME$5;
3819
- var CONTENT_NAME$7 = "TabsContent";
3860
+ TabsTrigger.displayName = TRIGGER_NAME$6;
3861
+ var CONTENT_NAME$8 = "TabsContent";
3820
3862
  var TabsContent = D((props, forwardedRef) => {
3821
3863
  const { __scopeTabs, value, forceMount, children, ...contentProps } = props;
3822
- const context = useTabsContext(CONTENT_NAME$7, __scopeTabs);
3864
+ const context = useTabsContext(CONTENT_NAME$8, __scopeTabs);
3823
3865
  const triggerId = makeTriggerId(context.baseId, value);
3824
3866
  const contentId = makeContentId(context.baseId, value);
3825
3867
  const isSelected = value === context.value;
@@ -3848,27 +3890,27 @@
3848
3890
  })
3849
3891
  });
3850
3892
  });
3851
- TabsContent.displayName = CONTENT_NAME$7;
3893
+ TabsContent.displayName = CONTENT_NAME$8;
3852
3894
  function makeTriggerId(baseId, value) {
3853
3895
  return `${baseId}-trigger-${value}`;
3854
3896
  }
3855
3897
  function makeContentId(baseId, value) {
3856
3898
  return `${baseId}-content-${value}`;
3857
3899
  }
3858
- var Root2$4 = Tabs;
3900
+ var Root2$5 = Tabs;
3859
3901
  var List = TabsList;
3860
- var Trigger$4 = TabsTrigger;
3902
+ var Trigger$5 = TabsTrigger;
3861
3903
  var Content$3 = TabsContent;
3862
3904
  //#endregion
3863
3905
  //#region src/components/primitives/radix-tabs.tsx
3864
3906
  function RadixTabs({ ariaLabel, children, listClassName, onValueChange, tabs, triggerClassName, value }) {
3865
- return /* @__PURE__ */ u(Root2$4, {
3907
+ return /* @__PURE__ */ u(Root2$5, {
3866
3908
  onValueChange,
3867
3909
  value,
3868
3910
  children: [/* @__PURE__ */ u(List, {
3869
3911
  "aria-label": ariaLabel,
3870
3912
  className: listClassName,
3871
- children: tabs.map((tab) => /* @__PURE__ */ u(Trigger$4, {
3913
+ children: tabs.map((tab) => /* @__PURE__ */ u(Trigger$5, {
3872
3914
  className: triggerClassName,
3873
3915
  disabled: tab.disabled,
3874
3916
  value: tab.value,
@@ -3909,7 +3951,10 @@
3909
3951
  deviceActionPendingId: "",
3910
3952
  deviceActionPendingKind: "",
3911
3953
  groupRenameDrafts: /* @__PURE__ */ new Map(),
3912
- deviceRenameDrafts: /* @__PURE__ */ new Map()
3954
+ deviceRenameDrafts: /* @__PURE__ */ new Map(),
3955
+ groupPreferencesOpen: /* @__PURE__ */ new Set(),
3956
+ groupPreferencesDrafts: /* @__PURE__ */ new Map(),
3957
+ availableProjects: []
3913
3958
  };
3914
3959
  //#endregion
3915
3960
  //#region src/tabs/coordinator-admin/components/devices-panel.ts
@@ -3919,7 +3964,7 @@
3919
3964
  return _$3(RadixTabsContent, {
3920
3965
  className: "coordinator-admin-panel",
3921
3966
  value: "devices"
3922
- }, _$3("h3", null, "Enrolled devices"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Rename, disable, re-enable, or remove enrolled devices from the operator surface without confusing this with direct sync state." : "Finish setup first. Device administration stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No enrolled devices found for the active coordinator group." : "Device administration will appear here once setup is complete.") : _$3("div", { class: "coordinator-admin-request-list" }, items.map((item) => {
3967
+ }, _$3("h3", null, "Enrolled devices"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Rename, disable, re-enable, or remove enrolled devices from the operator surface without confusing this with direct sync state." : "Finish setup first. Device administration stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No enrolled devices found for the active coordinator group." : "Device administration will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, items.map((item) => {
3923
3968
  const deviceId = String(item.device_id || "").trim();
3924
3969
  const groupId = String(item.group_id || state.lastCoordinatorAdminStatus?.active_group || "").trim();
3925
3970
  const displayName = String(item.display_name || deviceId || "Unnamed device");
@@ -3927,7 +3972,7 @@
3927
3972
  const draft = coordinatorAdminState.deviceRenameDrafts.get(deviceId) ?? String(item.display_name || "");
3928
3973
  const enabled = item.enabled !== false && item.enabled !== 0;
3929
3974
  return _$3("div", {
3930
- class: "peer-card",
3975
+ class: "peer-card peer-card--padded",
3931
3976
  key: deviceId || String(item.fingerprint || "unknown")
3932
3977
  }, _$3("div", { class: "peer-title" }, _$3("strong", null, draft || displayName)), _$3("div", { class: "peer-meta" }, `Device: ${deviceId || "unknown"}`), groupId ? _$3("div", { class: "peer-submeta" }, `Group: ${groupId}`) : null, _$3("div", { class: "peer-submeta" }, enabled ? "Enabled" : "Disabled"), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
3933
3978
  class: "peer-scope-input",
@@ -3961,337 +4006,121 @@
3961
4006
  })));
3962
4007
  }
3963
4008
  //#endregion
3964
- //#region ../../node_modules/.pnpm/@radix-ui+react-use-previous@1.1.1_react@19.2.4/node_modules/@radix-ui/react-use-previous/dist/index.mjs
3965
- function usePrevious(value) {
3966
- const ref = A$1({
3967
- value,
3968
- previous: value
3969
- });
3970
- return T$1(() => {
3971
- if (ref.current.value !== value) {
3972
- ref.current.previous = ref.current.value;
3973
- ref.current.value = value;
3974
- }
3975
- return ref.current.previous;
3976
- }, [value]);
3977
- }
3978
- //#endregion
3979
- //#region ../../node_modules/.pnpm/@radix-ui+react-use-size@1.1.1_react@19.2.4/node_modules/@radix-ui/react-use-size/dist/index.mjs
3980
- function useSize(element) {
3981
- const [size, setSize] = d$2(void 0);
3982
- useLayoutEffect2(() => {
3983
- if (element) {
3984
- setSize({
3985
- width: element.offsetWidth,
3986
- height: element.offsetHeight
3987
- });
3988
- const resizeObserver = new ResizeObserver((entries) => {
3989
- if (!Array.isArray(entries)) return;
3990
- if (!entries.length) return;
3991
- const entry = entries[0];
3992
- let width;
3993
- let height;
3994
- if ("borderBoxSize" in entry) {
3995
- const borderSizeEntry = entry["borderBoxSize"];
3996
- const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry;
3997
- width = borderSize["inlineSize"];
3998
- height = borderSize["blockSize"];
3999
- } else {
4000
- width = element.offsetWidth;
4001
- height = element.offsetHeight;
4002
- }
4003
- setSize({
4004
- width,
4005
- height
4006
- });
4007
- });
4008
- resizeObserver.observe(element, { box: "border-box" });
4009
- return () => resizeObserver.unobserve(element);
4010
- } else setSize(void 0);
4011
- }, [element]);
4012
- return size;
4013
- }
4014
- //#endregion
4015
- //#region ../../node_modules/.pnpm/@radix-ui+react-switch@1.2.6_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-switch/dist/index.mjs
4016
- var SWITCH_NAME = "Switch";
4017
- var [createSwitchContext, createSwitchScope] = createContextScope(SWITCH_NAME);
4018
- var [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);
4019
- var Switch = D((props, forwardedRef) => {
4020
- const { __scopeSwitch, name, checked: checkedProp, defaultChecked, required, disabled, value = "on", onCheckedChange, form, ...switchProps } = props;
4021
- const [button, setButton] = d$2(null);
4022
- const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
4023
- const hasConsumerStoppedPropagationRef = A$1(false);
4024
- const isFormControl = button ? form || !!button.closest("form") : true;
4025
- const [checked, setChecked] = useControllableState({
4026
- prop: checkedProp,
4027
- defaultProp: defaultChecked ?? false,
4028
- onChange: onCheckedChange,
4029
- caller: SWITCH_NAME
4009
+ //#region ../../node_modules/.pnpm/@radix-ui+react-collapsible@1.1.12_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-collapsible/dist/index.mjs
4010
+ var COLLAPSIBLE_NAME = "Collapsible";
4011
+ var [createCollapsibleContext, createCollapsibleScope] = createContextScope(COLLAPSIBLE_NAME);
4012
+ var [CollapsibleProvider, useCollapsibleContext] = createCollapsibleContext(COLLAPSIBLE_NAME);
4013
+ var Collapsible = D((props, forwardedRef) => {
4014
+ const { __scopeCollapsible, open: openProp, defaultOpen, disabled, onOpenChange, ...collapsibleProps } = props;
4015
+ const [open, setOpen] = useControllableState({
4016
+ prop: openProp,
4017
+ defaultProp: defaultOpen ?? false,
4018
+ onChange: onOpenChange,
4019
+ caller: COLLAPSIBLE_NAME
4030
4020
  });
4031
- return /* @__PURE__ */ u(SwitchProvider, {
4032
- scope: __scopeSwitch,
4033
- checked,
4021
+ return /* @__PURE__ */ u(CollapsibleProvider, {
4022
+ scope: __scopeCollapsible,
4034
4023
  disabled,
4035
- children: [/* @__PURE__ */ u(Primitive.button, {
4036
- type: "button",
4037
- role: "switch",
4038
- "aria-checked": checked,
4039
- "aria-required": required,
4040
- "data-state": getState$3(checked),
4024
+ contentId: useId(),
4025
+ open,
4026
+ onOpenToggle: q$2(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
4027
+ children: /* @__PURE__ */ u(Primitive.div, {
4028
+ "data-state": getState$4(open),
4041
4029
  "data-disabled": disabled ? "" : void 0,
4042
- disabled,
4043
- value,
4044
- ...switchProps,
4045
- ref: composedRefs,
4046
- onClick: composeEventHandlers(props.onClick, (event) => {
4047
- setChecked((prevChecked) => !prevChecked);
4048
- if (isFormControl) {
4049
- hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
4050
- if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
4051
- }
4052
- })
4053
- }), isFormControl && /* @__PURE__ */ u(SwitchBubbleInput, {
4054
- control: button,
4055
- bubbles: !hasConsumerStoppedPropagationRef.current,
4056
- name,
4057
- value,
4058
- checked,
4059
- required,
4060
- disabled,
4061
- form,
4062
- style: { transform: "translateX(-100%)" }
4063
- })]
4030
+ ...collapsibleProps,
4031
+ ref: forwardedRef
4032
+ })
4064
4033
  });
4065
4034
  });
4066
- Switch.displayName = SWITCH_NAME;
4067
- var THUMB_NAME = "SwitchThumb";
4068
- var SwitchThumb = D((props, forwardedRef) => {
4069
- const { __scopeSwitch, ...thumbProps } = props;
4070
- const context = useSwitchContext(THUMB_NAME, __scopeSwitch);
4071
- return /* @__PURE__ */ u(Primitive.span, {
4072
- "data-state": getState$3(context.checked),
4035
+ Collapsible.displayName = COLLAPSIBLE_NAME;
4036
+ var TRIGGER_NAME$5 = "CollapsibleTrigger";
4037
+ var CollapsibleTrigger = D((props, forwardedRef) => {
4038
+ const { __scopeCollapsible, ...triggerProps } = props;
4039
+ const context = useCollapsibleContext(TRIGGER_NAME$5, __scopeCollapsible);
4040
+ return /* @__PURE__ */ u(Primitive.button, {
4041
+ type: "button",
4042
+ "aria-controls": context.contentId,
4043
+ "aria-expanded": context.open || false,
4044
+ "data-state": getState$4(context.open),
4073
4045
  "data-disabled": context.disabled ? "" : void 0,
4074
- ...thumbProps,
4075
- ref: forwardedRef
4046
+ disabled: context.disabled,
4047
+ ...triggerProps,
4048
+ ref: forwardedRef,
4049
+ onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
4076
4050
  });
4077
4051
  });
4078
- SwitchThumb.displayName = THUMB_NAME;
4079
- var BUBBLE_INPUT_NAME$2 = "SwitchBubbleInput";
4080
- var SwitchBubbleInput = D(({ __scopeSwitch, control, checked, bubbles = true, ...props }, forwardedRef) => {
4052
+ CollapsibleTrigger.displayName = TRIGGER_NAME$5;
4053
+ var CONTENT_NAME$7 = "CollapsibleContent";
4054
+ var CollapsibleContent = D((props, forwardedRef) => {
4055
+ const { forceMount, ...contentProps } = props;
4056
+ const context = useCollapsibleContext(CONTENT_NAME$7, props.__scopeCollapsible);
4057
+ return /* @__PURE__ */ u(Presence, {
4058
+ present: forceMount || context.open,
4059
+ children: ({ present }) => /* @__PURE__ */ u(CollapsibleContentImpl, {
4060
+ ...contentProps,
4061
+ ref: forwardedRef,
4062
+ present
4063
+ })
4064
+ });
4065
+ });
4066
+ CollapsibleContent.displayName = CONTENT_NAME$7;
4067
+ var CollapsibleContentImpl = D((props, forwardedRef) => {
4068
+ const { __scopeCollapsible, present, children, ...contentProps } = props;
4069
+ const context = useCollapsibleContext(CONTENT_NAME$7, __scopeCollapsible);
4070
+ const [isPresent, setIsPresent] = d$2(present);
4081
4071
  const ref = A$1(null);
4082
- const composedRefs = useComposedRefs(ref, forwardedRef);
4083
- const prevChecked = usePrevious(checked);
4084
- const controlSize = useSize(control);
4072
+ const composedRefs = useComposedRefs(forwardedRef, ref);
4073
+ const heightRef = A$1(0);
4074
+ const height = heightRef.current;
4075
+ const widthRef = A$1(0);
4076
+ const width = widthRef.current;
4077
+ const isOpen = context.open || isPresent;
4078
+ const isMountAnimationPreventedRef = A$1(isOpen);
4079
+ const originalStylesRef = A$1(void 0);
4085
4080
  y$2(() => {
4086
- const input = ref.current;
4087
- if (!input) return;
4088
- const inputProto = window.HTMLInputElement.prototype;
4089
- const setChecked = Object.getOwnPropertyDescriptor(inputProto, "checked").set;
4090
- if (prevChecked !== checked && setChecked) {
4091
- const event = new Event("click", { bubbles });
4092
- setChecked.call(input, checked);
4093
- input.dispatchEvent(event);
4081
+ const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);
4082
+ return () => cancelAnimationFrame(rAF);
4083
+ }, []);
4084
+ useLayoutEffect2(() => {
4085
+ const node = ref.current;
4086
+ if (node) {
4087
+ originalStylesRef.current = originalStylesRef.current || {
4088
+ transitionDuration: node.style.transitionDuration,
4089
+ animationName: node.style.animationName
4090
+ };
4091
+ node.style.transitionDuration = "0s";
4092
+ node.style.animationName = "none";
4093
+ const rect = node.getBoundingClientRect();
4094
+ heightRef.current = rect.height;
4095
+ widthRef.current = rect.width;
4096
+ if (!isMountAnimationPreventedRef.current) {
4097
+ node.style.transitionDuration = originalStylesRef.current.transitionDuration;
4098
+ node.style.animationName = originalStylesRef.current.animationName;
4099
+ }
4100
+ setIsPresent(present);
4094
4101
  }
4095
- }, [
4096
- prevChecked,
4097
- checked,
4098
- bubbles
4099
- ]);
4100
- return /* @__PURE__ */ u("input", {
4101
- type: "checkbox",
4102
- "aria-hidden": true,
4103
- defaultChecked: checked,
4104
- ...props,
4105
- tabIndex: -1,
4102
+ }, [context.open, present]);
4103
+ return /* @__PURE__ */ u(Primitive.div, {
4104
+ "data-state": getState$4(context.open),
4105
+ "data-disabled": context.disabled ? "" : void 0,
4106
+ id: context.contentId,
4107
+ hidden: !isOpen,
4108
+ ...contentProps,
4106
4109
  ref: composedRefs,
4107
4110
  style: {
4108
- ...props.style,
4109
- ...controlSize,
4110
- position: "absolute",
4111
- pointerEvents: "none",
4112
- opacity: 0,
4113
- margin: 0
4114
- }
4111
+ [`--radix-collapsible-content-height`]: height ? `${height}px` : void 0,
4112
+ [`--radix-collapsible-content-width`]: width ? `${width}px` : void 0,
4113
+ ...props.style
4114
+ },
4115
+ children: isOpen && children
4115
4116
  });
4116
4117
  });
4117
- SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME$2;
4118
- function getState$3(checked) {
4119
- return checked ? "checked" : "unchecked";
4120
- }
4121
- var Root$3 = Switch;
4122
- var Thumb = SwitchThumb;
4123
- //#endregion
4124
- //#region src/components/primitives/radix-switch.tsx
4125
- function RadixSwitch({ "aria-labelledby": ariaLabelledBy, checked, className, disabled = false, id, name, onCheckedChange, thumbClassName }) {
4126
- return /* @__PURE__ */ u(Root$3, {
4127
- "aria-labelledby": ariaLabelledBy,
4128
- checked,
4129
- className,
4130
- disabled,
4131
- id,
4132
- name,
4133
- onCheckedChange,
4134
- children: /* @__PURE__ */ u(Thumb, { className: thumbClassName })
4135
- });
4136
- }
4137
- //#endregion
4138
- //#region src/tabs/coordinator-admin/data/target-group.ts
4139
- function adminTargetStorageKey(coordinatorUrl) {
4140
- return `${ADMIN_TARGET_GROUP_KEY}:${String(coordinatorUrl || "").trim()}`;
4141
- }
4142
- function readStoredAdminTargetGroup(coordinatorUrl) {
4143
- try {
4144
- return localStorage.getItem(adminTargetStorageKey(coordinatorUrl)) || "";
4145
- } catch {
4146
- return "";
4147
- }
4148
- }
4149
- function writeStoredAdminTargetGroup(coordinatorUrl, groupId) {
4150
- try {
4151
- localStorage.setItem(adminTargetStorageKey(coordinatorUrl), groupId);
4152
- } catch {}
4153
- }
4154
- function currentAdminTargetGroup() {
4155
- return String(state.coordinatorAdminTargetGroup || "").trim();
4156
- }
4157
- function setAdminTargetGroup(groupId) {
4158
- state.coordinatorAdminTargetGroup = groupId;
4159
- writeStoredAdminTargetGroup(state.lastCoordinatorAdminStatus?.coordinator_url || null, groupId);
4160
- }
4161
- function availableCoordinatorGroups() {
4162
- return (Array.isArray(state.lastCoordinatorAdminGroups) ? state.lastCoordinatorAdminGroups : []).map((group) => ({
4163
- archived_at: group.archived_at ?? null,
4164
- display_name: group.display_name ?? null,
4165
- group_id: String(group.group_id || "").trim()
4166
- })).filter((group) => group.group_id);
4167
- }
4168
- function reconcileGroupRenameDrafts() {
4169
- const next = /* @__PURE__ */ new Map();
4170
- for (const group of availableCoordinatorGroups()) next.set(group.group_id, group.display_name || group.group_id);
4171
- coordinatorAdminState.groupRenameDrafts.clear();
4172
- for (const [groupId, name] of next.entries()) coordinatorAdminState.groupRenameDrafts.set(groupId, name);
4173
- }
4174
- function currentAdminTargetGroupRecord() {
4175
- const target = currentAdminTargetGroup();
4176
- return availableCoordinatorGroups().find((group) => group.group_id === target) || null;
4177
- }
4178
- function resolveAdminTargetGroup() {
4179
- const status = state.lastCoordinatorAdminStatus;
4180
- const groups = availableCoordinatorGroups();
4181
- const configured = String(status?.active_group || "").trim();
4182
- const stored = readStoredAdminTargetGroup(status?.coordinator_url || null);
4183
- const current = currentAdminTargetGroup();
4184
- const availableIds = new Set(groups.map((group) => group.group_id));
4185
- const candidate = current || stored || configured || groups[0]?.group_id || "";
4186
- const resolved = candidate && (availableIds.size === 0 || availableIds.has(candidate)) ? candidate : configured || groups[0]?.group_id || "";
4187
- setAdminTargetGroup(resolved);
4188
- return resolved;
4189
- }
4190
- function reconcileDeviceRenameDrafts() {
4191
- const next = /* @__PURE__ */ new Map();
4192
- const items = Array.isArray(state.lastCoordinatorAdminDevices) ? state.lastCoordinatorAdminDevices : [];
4193
- for (const item of items) {
4194
- const deviceId = String(item.device_id || "").trim();
4195
- if (!deviceId) continue;
4196
- next.set(deviceId, String(item.display_name || ""));
4197
- }
4198
- coordinatorAdminState.deviceRenameDrafts.clear();
4199
- for (const [deviceId, name] of next.entries()) coordinatorAdminState.deviceRenameDrafts.set(deviceId, name);
4200
- }
4201
- //#endregion
4202
- //#region src/tabs/coordinator-admin/components/groups-panel.ts
4203
- function renderGroupsPanel(deps) {
4204
- const { summary, createGroup, runGroup, renderShell, reloadData } = deps;
4205
- const configuredGroup = String(state.lastCoordinatorAdminStatus?.active_group || "").trim();
4206
- const selectedGroup = currentAdminTargetGroup();
4207
- const groups = availableCoordinatorGroups();
4208
- const activeGroups = groups.filter((group) => !group.archived_at);
4209
- const archivedGroups = groups.filter((group) => group.archived_at);
4210
- const visibleGroups = coordinatorAdminState.showArchivedGroups ? groups : activeGroups;
4211
- const targetExists = selectedGroup ? groups.some((group) => group.group_id === selectedGroup) : false;
4212
- const countParts = [`${activeGroups.length} active`];
4213
- if (archivedGroups.length) countParts.push(`${archivedGroups.length} archived`);
4214
- return _$3(RadixTabsContent, {
4215
- className: "coordinator-admin-panel",
4216
- value: "groups"
4217
- }, _$3("h3", null, "Groups"), _$3("p", { class: "peer-submeta" }, selectedGroup ? `Managing ${selectedGroup}${configuredGroup && configuredGroup !== selectedGroup ? ` · this node uses ${configuredGroup} for discovery` : ""}` : configuredGroup ? `This node uses ${configuredGroup} for discovery. Select a group below to manage it.` : "No group selected yet. Create one or select an existing group to manage."), groups.length ? _$3("p", { class: "peer-submeta" }, countParts.join(" · ")) : null, !targetExists && selectedGroup ? _$3("div", { class: "peer-meta coordinator-admin-inline-warning" }, `The selected admin target group (${selectedGroup}) is configured locally but does not exist in the coordinator yet. Create it below or switch to another group once one exists.`) : null, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New group id"), _$3(TextInput, {
4218
- class: "peer-scope-input",
4219
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
4220
- onInput: (event) => {
4221
- coordinatorAdminState.createGroupId = String(event.currentTarget.value || "");
4222
- },
4223
- placeholder: "team-alpha",
4224
- type: "text",
4225
- value: coordinatorAdminState.createGroupId
4226
- })), _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
4227
- class: "peer-scope-input",
4228
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
4229
- onInput: (event) => {
4230
- coordinatorAdminState.createGroupDisplayName = String(event.currentTarget.value || "");
4231
- },
4232
- placeholder: "Team Alpha",
4233
- type: "text",
4234
- value: coordinatorAdminState.createGroupDisplayName
4235
- }))), _$3("div", { class: "section-actions coordinator-admin-groups-toolbar" }, _$3("div", { class: "coordinator-admin-primary-actions" }, _$3("button", {
4236
- class: "settings-button",
4237
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
4238
- onClick: () => createGroup(),
4239
- type: "button"
4240
- }, coordinatorAdminState.groupActionPendingKind === "create" ? "Creating…" : "Create group")), _$3("div", { class: "coordinator-admin-secondary-actions" }, _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
4241
- class: "section-meta",
4242
- id: "coordinatorAdminShowArchivedLabel"
4243
- }, "Show archived"), _$3(RadixSwitch, {
4244
- "aria-labelledby": "coordinatorAdminShowArchivedLabel",
4245
- checked: coordinatorAdminState.showArchivedGroups,
4246
- className: "coordinator-admin-switch",
4247
- disabled: summary.readiness !== "ready",
4248
- onCheckedChange: (checked) => {
4249
- coordinatorAdminState.showArchivedGroups = checked;
4250
- renderShell();
4251
- },
4252
- thumbClassName: "coordinator-admin-switch-thumb"
4253
- })))), !visibleGroups.length ? _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, summary.readiness === "ready" ? coordinatorAdminState.showArchivedGroups ? "No coordinator groups are available yet." : "No active groups yet. Create one to get started." : "Group browsing will appear here once setup is complete.") : _$3("div", { class: "coordinator-admin-request-list" }, visibleGroups.map((group) => {
4254
- const selected = group.group_id === selectedGroup;
4255
- const pending = coordinatorAdminState.groupActionPendingId === group.group_id;
4256
- const archived = Boolean(group.archived_at);
4257
- const draftName = coordinatorAdminState.groupRenameDrafts.get(group.group_id) ?? group.display_name ?? group.group_id;
4258
- return _$3("div", {
4259
- class: "peer-card",
4260
- key: group.group_id
4261
- }, _$3("div", { class: "peer-title" }, _$3("strong", null, draftName)), _$3("div", { class: "peer-meta" }, `Group ID: ${group.group_id}`), _$3("div", { class: "peer-submeta" }, archived ? "Archived" : "Active"), configuredGroup === group.group_id ? _$3("div", { class: "peer-submeta" }, "This node is configured to use this group for coordinator-backed discovery.") : null, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
4262
- class: "peer-scope-input",
4263
- disabled: summary.readiness !== "ready" || pending,
4264
- onInput: (event) => {
4265
- coordinatorAdminState.groupRenameDrafts.set(group.group_id, String(event.currentTarget.value || ""));
4266
- },
4267
- type: "text",
4268
- value: draftName
4269
- })), _$3("div", { class: "peer-actions" }, _$3("button", {
4270
- class: "settings-button",
4271
- disabled: summary.readiness !== "ready" || selected,
4272
- onClick: () => {
4273
- setAdminTargetGroup(group.group_id);
4274
- reloadData();
4275
- },
4276
- type: "button"
4277
- }, selected ? "Managing" : "Manage"), _$3("button", {
4278
- class: "settings-button",
4279
- disabled: summary.readiness !== "ready" || pending,
4280
- onClick: () => runGroup(group.group_id, draftName, "rename"),
4281
- type: "button"
4282
- }, pending && coordinatorAdminState.groupActionPendingKind === "rename" ? "Renaming…" : "Rename"), _$3("button", {
4283
- class: archived ? "settings-button" : "settings-button danger",
4284
- disabled: summary.readiness !== "ready" || pending,
4285
- onClick: () => runGroup(group.group_id, group.display_name || group.group_id, archived ? "unarchive" : "archive"),
4286
- type: "button"
4287
- }, pending && coordinatorAdminState.groupActionPendingKind === (archived ? "unarchive" : "archive") ? archived ? "Restoring…" : "Archiving…" : archived ? "Unarchive" : "Archive")));
4288
- })));
4289
- }
4290
- //#endregion
4291
- //#region ../../node_modules/.pnpm/@radix-ui+number@1.1.1/node_modules/@radix-ui/number/dist/index.mjs
4292
- function clamp$1(value, [min, max]) {
4293
- return Math.min(max, Math.max(min, value));
4118
+ function getState$4(open) {
4119
+ return open ? "open" : "closed";
4294
4120
  }
4121
+ var Root$3 = Collapsible;
4122
+ var Trigger$4 = CollapsibleTrigger;
4123
+ var Content$2 = CollapsibleContent;
4295
4124
  //#endregion
4296
4125
  //#region ../../node_modules/.pnpm/@radix-ui+react-focus-guards@1.1.3_react@19.2.4/node_modules/@radix-ui/react-focus-guards/dist/index.mjs
4297
4126
  var count = 0;
@@ -4532,7 +4361,7 @@
4532
4361
  bottom: "top",
4533
4362
  top: "bottom"
4534
4363
  };
4535
- function clamp(start, value, end) {
4364
+ function clamp$1(start, value, end) {
4536
4365
  return max(start, min(value, end));
4537
4366
  }
4538
4367
  function evaluate(value, param) {
@@ -4842,7 +4671,7 @@
4842
4671
  const min$1 = minPadding;
4843
4672
  const max = clientSize - arrowDimensions[length] - maxPadding;
4844
4673
  const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
4845
- const offset = clamp(min$1, center, max);
4674
+ const offset = clamp$1(min$1, center, max);
4846
4675
  const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
4847
4676
  const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max : 0;
4848
4677
  return {
@@ -5068,14 +4897,14 @@
5068
4897
  const maxSide = mainAxis === "y" ? "bottom" : "right";
5069
4898
  const min = mainAxisCoord + overflow[minSide];
5070
4899
  const max = mainAxisCoord - overflow[maxSide];
5071
- mainAxisCoord = clamp(min, mainAxisCoord, max);
4900
+ mainAxisCoord = clamp$1(min, mainAxisCoord, max);
5072
4901
  }
5073
4902
  if (checkCrossAxis) {
5074
4903
  const minSide = crossAxis === "y" ? "top" : "left";
5075
4904
  const maxSide = crossAxis === "y" ? "bottom" : "right";
5076
4905
  const min = crossAxisCoord + overflow[minSide];
5077
4906
  const max = crossAxisCoord - overflow[maxSide];
5078
- crossAxisCoord = clamp(min, crossAxisCoord, max);
4907
+ crossAxisCoord = clamp$1(min, crossAxisCoord, max);
5079
4908
  }
5080
4909
  const limitedCoords = limiter.fn({
5081
4910
  ...state,
@@ -6177,6 +6006,42 @@
6177
6006
  Arrow$1.displayName = NAME;
6178
6007
  var Root$2 = Arrow$1;
6179
6008
  //#endregion
6009
+ //#region ../../node_modules/.pnpm/@radix-ui+react-use-size@1.1.1_react@19.2.4/node_modules/@radix-ui/react-use-size/dist/index.mjs
6010
+ function useSize(element) {
6011
+ const [size, setSize] = d$2(void 0);
6012
+ useLayoutEffect2(() => {
6013
+ if (element) {
6014
+ setSize({
6015
+ width: element.offsetWidth,
6016
+ height: element.offsetHeight
6017
+ });
6018
+ const resizeObserver = new ResizeObserver((entries) => {
6019
+ if (!Array.isArray(entries)) return;
6020
+ if (!entries.length) return;
6021
+ const entry = entries[0];
6022
+ let width;
6023
+ let height;
6024
+ if ("borderBoxSize" in entry) {
6025
+ const borderSizeEntry = entry["borderBoxSize"];
6026
+ const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry;
6027
+ width = borderSize["inlineSize"];
6028
+ height = borderSize["blockSize"];
6029
+ } else {
6030
+ width = element.offsetWidth;
6031
+ height = element.offsetHeight;
6032
+ }
6033
+ setSize({
6034
+ width,
6035
+ height
6036
+ });
6037
+ });
6038
+ resizeObserver.observe(element, { box: "border-box" });
6039
+ return () => resizeObserver.unobserve(element);
6040
+ } else setSize(void 0);
6041
+ }, [element]);
6042
+ return size;
6043
+ }
6044
+ //#endregion
6180
6045
  //#region ../../node_modules/.pnpm/@radix-ui+react-popper@1.2.8_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-popper/dist/index.mjs
6181
6046
  var POPPER_NAME = "Popper";
6182
6047
  var [createPopperContext, createPopperScope] = createContextScope(POPPER_NAME);
@@ -6192,10 +6057,10 @@
6192
6057
  });
6193
6058
  };
6194
6059
  Popper.displayName = POPPER_NAME;
6195
- var ANCHOR_NAME$1 = "PopperAnchor";
6060
+ var ANCHOR_NAME$2 = "PopperAnchor";
6196
6061
  var PopperAnchor = D((props, forwardedRef) => {
6197
6062
  const { __scopePopper, virtualRef, ...anchorProps } = props;
6198
- const context = usePopperContext(ANCHOR_NAME$1, __scopePopper);
6063
+ const context = usePopperContext(ANCHOR_NAME$2, __scopePopper);
6199
6064
  const ref = A$1(null);
6200
6065
  const composedRefs = useComposedRefs(forwardedRef, ref);
6201
6066
  const anchorRef = A$1(null);
@@ -6209,7 +6074,7 @@
6209
6074
  ref: composedRefs
6210
6075
  });
6211
6076
  });
6212
- PopperAnchor.displayName = ANCHOR_NAME$1;
6077
+ PopperAnchor.displayName = ANCHOR_NAME$2;
6213
6078
  var CONTENT_NAME$6 = "PopperContent";
6214
6079
  var [PopperContentProvider, useContentContext] = createPopperContext(CONTENT_NAME$6);
6215
6080
  var PopperContent = D((props, forwardedRef) => {
@@ -6328,7 +6193,7 @@
6328
6193
  });
6329
6194
  });
6330
6195
  PopperContent.displayName = CONTENT_NAME$6;
6331
- var ARROW_NAME$4 = "PopperArrow";
6196
+ var ARROW_NAME$5 = "PopperArrow";
6332
6197
  var OPPOSITE_SIDE = {
6333
6198
  top: "bottom",
6334
6199
  right: "left",
@@ -6337,7 +6202,7 @@
6337
6202
  };
6338
6203
  var PopperArrow = D(function PopperArrow2(props, forwardedRef) {
6339
6204
  const { __scopePopper, ...arrowProps } = props;
6340
- const contentContext = useContentContext(ARROW_NAME$4, __scopePopper);
6205
+ const contentContext = useContentContext(ARROW_NAME$5, __scopePopper);
6341
6206
  const baseSide = OPPOSITE_SIDE[contentContext.placedSide];
6342
6207
  return /* @__PURE__ */ u("span", {
6343
6208
  ref: contentContext.onArrowChange,
@@ -6370,7 +6235,7 @@
6370
6235
  })
6371
6236
  });
6372
6237
  });
6373
- PopperArrow.displayName = ARROW_NAME$4;
6238
+ PopperArrow.displayName = ARROW_NAME$5;
6374
6239
  function isNotNull(value) {
6375
6240
  return value !== null;
6376
6241
  }
@@ -6415,9 +6280,9 @@
6415
6280
  const [side, align = "center"] = placement.split("-");
6416
6281
  return [side, align];
6417
6282
  }
6418
- var Root2$3 = Popper;
6283
+ var Root2$4 = Popper;
6419
6284
  var Anchor = PopperAnchor;
6420
- var Content$2 = PopperContent;
6285
+ var Content$1 = PopperContent;
6421
6286
  var Arrow = PopperArrow;
6422
6287
  //#endregion
6423
6288
  //#region ../../node_modules/.pnpm/aria-hidden@1.2.6/node_modules/aria-hidden/dist/es2015/index.js
@@ -7226,17 +7091,919 @@
7226
7091
  return shadowParent;
7227
7092
  }
7228
7093
  //#endregion
7229
- //#region ../../node_modules/.pnpm/react-remove-scroll@2.7.2_react@19.2.4/node_modules/react-remove-scroll/dist/es2015/sidecar.js
7230
- var sidecar_default = exportSidecar(effectCar, RemoveScrollSideCar);
7231
- //#endregion
7232
- //#region ../../node_modules/.pnpm/react-remove-scroll@2.7.2_react@19.2.4/node_modules/react-remove-scroll/dist/es2015/Combination.js
7233
- var ReactRemoveScroll = D(function(props, ref) {
7234
- return _$3(RemoveScroll, __assign({}, props, {
7235
- ref,
7236
- sideCar: sidecar_default
7237
- }));
7238
- });
7239
- ReactRemoveScroll.classNames = RemoveScroll.classNames;
7094
+ //#region ../../node_modules/.pnpm/react-remove-scroll@2.7.2_react@19.2.4/node_modules/react-remove-scroll/dist/es2015/sidecar.js
7095
+ var sidecar_default = exportSidecar(effectCar, RemoveScrollSideCar);
7096
+ //#endregion
7097
+ //#region ../../node_modules/.pnpm/react-remove-scroll@2.7.2_react@19.2.4/node_modules/react-remove-scroll/dist/es2015/Combination.js
7098
+ var ReactRemoveScroll = D(function(props, ref) {
7099
+ return _$3(RemoveScroll, __assign({}, props, {
7100
+ ref,
7101
+ sideCar: sidecar_default
7102
+ }));
7103
+ });
7104
+ ReactRemoveScroll.classNames = RemoveScroll.classNames;
7105
+ //#endregion
7106
+ //#region ../../node_modules/.pnpm/@radix-ui+react-popover@1.1.15_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-popover/dist/index.mjs
7107
+ var POPOVER_NAME = "Popover";
7108
+ var [createPopoverContext, createPopoverScope] = createContextScope(POPOVER_NAME, [createPopperScope]);
7109
+ var usePopperScope$3 = createPopperScope();
7110
+ var [PopoverProvider, usePopoverContext] = createPopoverContext(POPOVER_NAME);
7111
+ var Popover = (props) => {
7112
+ const { __scopePopover, children, open: openProp, defaultOpen, onOpenChange, modal = false } = props;
7113
+ const popperScope = usePopperScope$3(__scopePopover);
7114
+ const triggerRef = A$1(null);
7115
+ const [hasCustomAnchor, setHasCustomAnchor] = d$2(false);
7116
+ const [open, setOpen] = useControllableState({
7117
+ prop: openProp,
7118
+ defaultProp: defaultOpen ?? false,
7119
+ onChange: onOpenChange,
7120
+ caller: POPOVER_NAME
7121
+ });
7122
+ return /* @__PURE__ */ u(Root2$4, {
7123
+ ...popperScope,
7124
+ children: /* @__PURE__ */ u(PopoverProvider, {
7125
+ scope: __scopePopover,
7126
+ contentId: useId(),
7127
+ triggerRef,
7128
+ open,
7129
+ onOpenChange: setOpen,
7130
+ onOpenToggle: q$2(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
7131
+ hasCustomAnchor,
7132
+ onCustomAnchorAdd: q$2(() => setHasCustomAnchor(true), []),
7133
+ onCustomAnchorRemove: q$2(() => setHasCustomAnchor(false), []),
7134
+ modal,
7135
+ children
7136
+ })
7137
+ });
7138
+ };
7139
+ Popover.displayName = POPOVER_NAME;
7140
+ var ANCHOR_NAME$1 = "PopoverAnchor";
7141
+ var PopoverAnchor = D((props, forwardedRef) => {
7142
+ const { __scopePopover, ...anchorProps } = props;
7143
+ const context = usePopoverContext(ANCHOR_NAME$1, __scopePopover);
7144
+ const popperScope = usePopperScope$3(__scopePopover);
7145
+ const { onCustomAnchorAdd, onCustomAnchorRemove } = context;
7146
+ y$2(() => {
7147
+ onCustomAnchorAdd();
7148
+ return () => onCustomAnchorRemove();
7149
+ }, [onCustomAnchorAdd, onCustomAnchorRemove]);
7150
+ return /* @__PURE__ */ u(Anchor, {
7151
+ ...popperScope,
7152
+ ...anchorProps,
7153
+ ref: forwardedRef
7154
+ });
7155
+ });
7156
+ PopoverAnchor.displayName = ANCHOR_NAME$1;
7157
+ var TRIGGER_NAME$4 = "PopoverTrigger";
7158
+ var PopoverTrigger = D((props, forwardedRef) => {
7159
+ const { __scopePopover, ...triggerProps } = props;
7160
+ const context = usePopoverContext(TRIGGER_NAME$4, __scopePopover);
7161
+ const popperScope = usePopperScope$3(__scopePopover);
7162
+ const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);
7163
+ const trigger = /* @__PURE__ */ u(Primitive.button, {
7164
+ type: "button",
7165
+ "aria-haspopup": "dialog",
7166
+ "aria-expanded": context.open,
7167
+ "aria-controls": context.contentId,
7168
+ "data-state": getState$3(context.open),
7169
+ ...triggerProps,
7170
+ ref: composedTriggerRef,
7171
+ onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
7172
+ });
7173
+ return context.hasCustomAnchor ? trigger : /* @__PURE__ */ u(Anchor, {
7174
+ asChild: true,
7175
+ ...popperScope,
7176
+ children: trigger
7177
+ });
7178
+ });
7179
+ PopoverTrigger.displayName = TRIGGER_NAME$4;
7180
+ var PORTAL_NAME$5 = "PopoverPortal";
7181
+ var [PortalProvider$3, usePortalContext$3] = createPopoverContext(PORTAL_NAME$5, { forceMount: void 0 });
7182
+ var PopoverPortal = (props) => {
7183
+ const { __scopePopover, forceMount, children, container } = props;
7184
+ const context = usePopoverContext(PORTAL_NAME$5, __scopePopover);
7185
+ return /* @__PURE__ */ u(PortalProvider$3, {
7186
+ scope: __scopePopover,
7187
+ forceMount,
7188
+ children: /* @__PURE__ */ u(Presence, {
7189
+ present: forceMount || context.open,
7190
+ children: /* @__PURE__ */ u(Portal$5, {
7191
+ asChild: true,
7192
+ container,
7193
+ children
7194
+ })
7195
+ })
7196
+ });
7197
+ };
7198
+ PopoverPortal.displayName = PORTAL_NAME$5;
7199
+ var CONTENT_NAME$5 = "PopoverContent";
7200
+ var PopoverContent = D((props, forwardedRef) => {
7201
+ const portalContext = usePortalContext$3(CONTENT_NAME$5, props.__scopePopover);
7202
+ const { forceMount = portalContext.forceMount, ...contentProps } = props;
7203
+ const context = usePopoverContext(CONTENT_NAME$5, props.__scopePopover);
7204
+ return /* @__PURE__ */ u(Presence, {
7205
+ present: forceMount || context.open,
7206
+ children: context.modal ? /* @__PURE__ */ u(PopoverContentModal, {
7207
+ ...contentProps,
7208
+ ref: forwardedRef
7209
+ }) : /* @__PURE__ */ u(PopoverContentNonModal, {
7210
+ ...contentProps,
7211
+ ref: forwardedRef
7212
+ })
7213
+ });
7214
+ });
7215
+ PopoverContent.displayName = CONTENT_NAME$5;
7216
+ var Slot$3 = /* @__PURE__ */ createSlot("PopoverContent.RemoveScroll");
7217
+ var PopoverContentModal = D((props, forwardedRef) => {
7218
+ const context = usePopoverContext(CONTENT_NAME$5, props.__scopePopover);
7219
+ const contentRef = A$1(null);
7220
+ const composedRefs = useComposedRefs(forwardedRef, contentRef);
7221
+ const isRightClickOutsideRef = A$1(false);
7222
+ y$2(() => {
7223
+ const content = contentRef.current;
7224
+ if (content) return hideOthers(content);
7225
+ }, []);
7226
+ return /* @__PURE__ */ u(ReactRemoveScroll, {
7227
+ as: Slot$3,
7228
+ allowPinchZoom: true,
7229
+ children: /* @__PURE__ */ u(PopoverContentImpl, {
7230
+ ...props,
7231
+ ref: composedRefs,
7232
+ trapFocus: context.open,
7233
+ disableOutsidePointerEvents: true,
7234
+ onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
7235
+ event.preventDefault();
7236
+ if (!isRightClickOutsideRef.current) context.triggerRef.current?.focus();
7237
+ }),
7238
+ onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {
7239
+ const originalEvent = event.detail.originalEvent;
7240
+ const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
7241
+ isRightClickOutsideRef.current = originalEvent.button === 2 || ctrlLeftClick;
7242
+ }, { checkForDefaultPrevented: false }),
7243
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, (event) => event.preventDefault(), { checkForDefaultPrevented: false })
7244
+ })
7245
+ });
7246
+ });
7247
+ var PopoverContentNonModal = D((props, forwardedRef) => {
7248
+ const context = usePopoverContext(CONTENT_NAME$5, props.__scopePopover);
7249
+ const hasInteractedOutsideRef = A$1(false);
7250
+ const hasPointerDownOutsideRef = A$1(false);
7251
+ return /* @__PURE__ */ u(PopoverContentImpl, {
7252
+ ...props,
7253
+ ref: forwardedRef,
7254
+ trapFocus: false,
7255
+ disableOutsidePointerEvents: false,
7256
+ onCloseAutoFocus: (event) => {
7257
+ props.onCloseAutoFocus?.(event);
7258
+ if (!event.defaultPrevented) {
7259
+ if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();
7260
+ event.preventDefault();
7261
+ }
7262
+ hasInteractedOutsideRef.current = false;
7263
+ hasPointerDownOutsideRef.current = false;
7264
+ },
7265
+ onInteractOutside: (event) => {
7266
+ props.onInteractOutside?.(event);
7267
+ if (!event.defaultPrevented) {
7268
+ hasInteractedOutsideRef.current = true;
7269
+ if (event.detail.originalEvent.type === "pointerdown") hasPointerDownOutsideRef.current = true;
7270
+ }
7271
+ const target = event.target;
7272
+ if (context.triggerRef.current?.contains(target)) event.preventDefault();
7273
+ if (event.detail.originalEvent.type === "focusin" && hasPointerDownOutsideRef.current) event.preventDefault();
7274
+ }
7275
+ });
7276
+ });
7277
+ var PopoverContentImpl = D((props, forwardedRef) => {
7278
+ const { __scopePopover, trapFocus, onOpenAutoFocus, onCloseAutoFocus, disableOutsidePointerEvents, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, ...contentProps } = props;
7279
+ const context = usePopoverContext(CONTENT_NAME$5, __scopePopover);
7280
+ const popperScope = usePopperScope$3(__scopePopover);
7281
+ useFocusGuards();
7282
+ return /* @__PURE__ */ u(FocusScope, {
7283
+ asChild: true,
7284
+ loop: true,
7285
+ trapped: trapFocus,
7286
+ onMountAutoFocus: onOpenAutoFocus,
7287
+ onUnmountAutoFocus: onCloseAutoFocus,
7288
+ children: /* @__PURE__ */ u(DismissableLayer, {
7289
+ asChild: true,
7290
+ disableOutsidePointerEvents,
7291
+ onInteractOutside,
7292
+ onEscapeKeyDown,
7293
+ onPointerDownOutside,
7294
+ onFocusOutside,
7295
+ onDismiss: () => context.onOpenChange(false),
7296
+ children: /* @__PURE__ */ u(Content$1, {
7297
+ "data-state": getState$3(context.open),
7298
+ role: "dialog",
7299
+ id: context.contentId,
7300
+ ...popperScope,
7301
+ ...contentProps,
7302
+ ref: forwardedRef,
7303
+ style: {
7304
+ ...contentProps.style,
7305
+ "--radix-popover-content-transform-origin": "var(--radix-popper-transform-origin)",
7306
+ "--radix-popover-content-available-width": "var(--radix-popper-available-width)",
7307
+ "--radix-popover-content-available-height": "var(--radix-popper-available-height)",
7308
+ "--radix-popover-trigger-width": "var(--radix-popper-anchor-width)",
7309
+ "--radix-popover-trigger-height": "var(--radix-popper-anchor-height)"
7310
+ }
7311
+ })
7312
+ })
7313
+ });
7314
+ });
7315
+ var CLOSE_NAME$1 = "PopoverClose";
7316
+ var PopoverClose = D((props, forwardedRef) => {
7317
+ const { __scopePopover, ...closeProps } = props;
7318
+ const context = usePopoverContext(CLOSE_NAME$1, __scopePopover);
7319
+ return /* @__PURE__ */ u(Primitive.button, {
7320
+ type: "button",
7321
+ ...closeProps,
7322
+ ref: forwardedRef,
7323
+ onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))
7324
+ });
7325
+ });
7326
+ PopoverClose.displayName = CLOSE_NAME$1;
7327
+ var ARROW_NAME$4 = "PopoverArrow";
7328
+ var PopoverArrow = D((props, forwardedRef) => {
7329
+ const { __scopePopover, ...arrowProps } = props;
7330
+ return /* @__PURE__ */ u(Arrow, {
7331
+ ...usePopperScope$3(__scopePopover),
7332
+ ...arrowProps,
7333
+ ref: forwardedRef
7334
+ });
7335
+ });
7336
+ PopoverArrow.displayName = ARROW_NAME$4;
7337
+ function getState$3(open) {
7338
+ return open ? "open" : "closed";
7339
+ }
7340
+ var Root2$3 = Popover;
7341
+ var Anchor2$1 = PopoverAnchor;
7342
+ var Trigger$3 = PopoverTrigger;
7343
+ var Portal$4 = PopoverPortal;
7344
+ var Content2$4 = PopoverContent;
7345
+ //#endregion
7346
+ //#region src/components/primitives/project-scope-picker.tsx
7347
+ function normalize$1(value) {
7348
+ return value.trim();
7349
+ }
7350
+ function ProjectScopePicker({ values, onValuesChange, availableProjects, placeholder, emptyLabel, disabled, "aria-labelledby": ariaLabelledby }) {
7351
+ const [open, setOpen] = d$2(false);
7352
+ const [query, setQuery] = d$2("");
7353
+ const [activeIndex, setActiveIndex] = d$2(0);
7354
+ const inputRef = A$1(null);
7355
+ const allKnown = T$1(() => {
7356
+ const seen = /* @__PURE__ */ new Set();
7357
+ const out = [];
7358
+ for (const item of [...availableProjects, ...values]) {
7359
+ const trimmed = normalize$1(item);
7360
+ if (!trimmed || seen.has(trimmed)) continue;
7361
+ seen.add(trimmed);
7362
+ out.push(trimmed);
7363
+ }
7364
+ return out.sort((a, b) => a.localeCompare(b));
7365
+ }, [availableProjects, values]);
7366
+ const trimmedQuery = normalize$1(query);
7367
+ const loweredQuery = trimmedQuery.toLowerCase();
7368
+ const filtered = T$1(() => {
7369
+ if (!loweredQuery) return allKnown;
7370
+ return allKnown.filter((project) => project.toLowerCase().includes(loweredQuery));
7371
+ }, [allKnown, loweredQuery]);
7372
+ const exactMatchExists = trimmedQuery ? allKnown.some((project) => project.toLowerCase() === loweredQuery) : false;
7373
+ const showCreateRow = Boolean(trimmedQuery) && !exactMatchExists;
7374
+ const rowCount = filtered.length + (showCreateRow ? 1 : 0);
7375
+ y$2(() => {
7376
+ if (activeIndex >= rowCount) setActiveIndex(Math.max(0, rowCount - 1));
7377
+ }, [rowCount, activeIndex]);
7378
+ y$2(() => {
7379
+ if (!open) return;
7380
+ const raf = requestAnimationFrame(() => inputRef.current?.focus());
7381
+ return () => cancelAnimationFrame(raf);
7382
+ }, [open]);
7383
+ const toggleProject = (project) => {
7384
+ if (values.includes(project)) onValuesChange(values.filter((value) => value !== project));
7385
+ else onValuesChange(Array.from(new Set([...values, project])));
7386
+ };
7387
+ const createProject = (project) => {
7388
+ const trimmed = normalize$1(project);
7389
+ if (!trimmed) return;
7390
+ onValuesChange(Array.from(new Set([...values, trimmed])));
7391
+ setQuery("");
7392
+ setActiveIndex(0);
7393
+ };
7394
+ const activateRow = (index) => {
7395
+ if (index < filtered.length) {
7396
+ const project = filtered[index];
7397
+ if (project) toggleProject(project);
7398
+ return;
7399
+ }
7400
+ if (showCreateRow) createProject(trimmedQuery);
7401
+ };
7402
+ const handleSearchKeyDown = (event) => {
7403
+ if (event.key === "ArrowDown") {
7404
+ event.preventDefault();
7405
+ setActiveIndex((prev) => Math.min(rowCount - 1, prev + 1));
7406
+ return;
7407
+ }
7408
+ if (event.key === "ArrowUp") {
7409
+ event.preventDefault();
7410
+ setActiveIndex((prev) => Math.max(0, prev - 1));
7411
+ return;
7412
+ }
7413
+ if (event.key === "Enter") {
7414
+ event.preventDefault();
7415
+ activateRow(activeIndex);
7416
+ return;
7417
+ }
7418
+ };
7419
+ const removeValue = (value) => {
7420
+ onValuesChange(values.filter((existing) => existing !== value));
7421
+ };
7422
+ return /* @__PURE__ */ u("div", {
7423
+ class: "project-scope-picker",
7424
+ children: [/* @__PURE__ */ u("ul", {
7425
+ "aria-labelledby": ariaLabelledby,
7426
+ class: "project-scope-picker-selected",
7427
+ children: values.length === 0 ? /* @__PURE__ */ u("li", {
7428
+ class: "project-scope-picker-selected-empty",
7429
+ children: emptyLabel || "No projects selected."
7430
+ }) : values.map((value) => /* @__PURE__ */ u("li", {
7431
+ class: "project-scope-picker-selected-chip",
7432
+ children: [/* @__PURE__ */ u("span", { children: value }), !disabled ? /* @__PURE__ */ u("button", {
7433
+ "aria-label": `Remove ${value}`,
7434
+ class: "project-scope-picker-selected-remove",
7435
+ onClick: () => removeValue(value),
7436
+ type: "button",
7437
+ children: "×"
7438
+ }) : null]
7439
+ }, value))
7440
+ }), /* @__PURE__ */ u(Root2$3, {
7441
+ onOpenChange: (next) => {
7442
+ setOpen(next);
7443
+ if (!next) {
7444
+ setQuery("");
7445
+ setActiveIndex(0);
7446
+ }
7447
+ },
7448
+ open,
7449
+ children: [/* @__PURE__ */ u(Trigger$3, {
7450
+ asChild: true,
7451
+ children: /* @__PURE__ */ u("button", {
7452
+ class: "project-scope-picker-trigger settings-button",
7453
+ disabled,
7454
+ type: "button",
7455
+ children: [/* @__PURE__ */ u("span", {
7456
+ "aria-hidden": "true",
7457
+ children: "+"
7458
+ }), /* @__PURE__ */ u("span", { children: placeholder || "Add project" })]
7459
+ })
7460
+ }), /* @__PURE__ */ u(Portal$4, { children: /* @__PURE__ */ u(Content2$4, {
7461
+ align: "start",
7462
+ class: "project-scope-picker-popover",
7463
+ sideOffset: 6,
7464
+ children: [/* @__PURE__ */ u("input", {
7465
+ "aria-label": "Search projects",
7466
+ class: "project-scope-picker-search",
7467
+ onInput: (event) => {
7468
+ setQuery(event.currentTarget.value);
7469
+ setActiveIndex(0);
7470
+ },
7471
+ onKeyDown: handleSearchKeyDown,
7472
+ placeholder: "Search or create…",
7473
+ ref: inputRef,
7474
+ type: "text",
7475
+ value: query
7476
+ }), /* @__PURE__ */ u("div", {
7477
+ class: "project-scope-picker-results",
7478
+ role: "listbox",
7479
+ children: [
7480
+ filtered.length === 0 && !showCreateRow ? /* @__PURE__ */ u("div", {
7481
+ class: "project-scope-picker-empty-row",
7482
+ children: "No projects yet. Type a name to create one."
7483
+ }) : null,
7484
+ filtered.map((project, index) => {
7485
+ const selected = values.includes(project);
7486
+ return /* @__PURE__ */ u("button", {
7487
+ "aria-selected": selected,
7488
+ class: index === activeIndex ? "project-scope-picker-row project-scope-picker-row--active" : "project-scope-picker-row",
7489
+ onClick: () => {
7490
+ setActiveIndex(index);
7491
+ toggleProject(project);
7492
+ },
7493
+ onMouseEnter: () => setActiveIndex(index),
7494
+ role: "option",
7495
+ type: "button",
7496
+ children: [/* @__PURE__ */ u("span", {
7497
+ class: "project-scope-picker-row-check",
7498
+ "aria-hidden": "true",
7499
+ children: selected ? "✓" : ""
7500
+ }), /* @__PURE__ */ u("span", {
7501
+ class: "project-scope-picker-row-label",
7502
+ children: project
7503
+ })]
7504
+ }, project);
7505
+ }),
7506
+ showCreateRow ? /* @__PURE__ */ u("button", {
7507
+ "aria-selected": false,
7508
+ class: activeIndex === filtered.length ? "project-scope-picker-row project-scope-picker-row--create project-scope-picker-row--active" : "project-scope-picker-row project-scope-picker-row--create",
7509
+ onClick: () => createProject(trimmedQuery),
7510
+ onMouseEnter: () => setActiveIndex(filtered.length),
7511
+ role: "option",
7512
+ type: "button",
7513
+ children: [/* @__PURE__ */ u("span", {
7514
+ class: "project-scope-picker-row-check",
7515
+ "aria-hidden": "true",
7516
+ children: "+"
7517
+ }), /* @__PURE__ */ u("span", {
7518
+ class: "project-scope-picker-row-label",
7519
+ children: `Create "${trimmedQuery}"`
7520
+ })]
7521
+ }) : null
7522
+ ]
7523
+ })]
7524
+ }) })]
7525
+ })]
7526
+ });
7527
+ }
7528
+ //#endregion
7529
+ //#region ../../node_modules/.pnpm/@radix-ui+react-use-previous@1.1.1_react@19.2.4/node_modules/@radix-ui/react-use-previous/dist/index.mjs
7530
+ function usePrevious(value) {
7531
+ const ref = A$1({
7532
+ value,
7533
+ previous: value
7534
+ });
7535
+ return T$1(() => {
7536
+ if (ref.current.value !== value) {
7537
+ ref.current.previous = ref.current.value;
7538
+ ref.current.value = value;
7539
+ }
7540
+ return ref.current.previous;
7541
+ }, [value]);
7542
+ }
7543
+ //#endregion
7544
+ //#region ../../node_modules/.pnpm/@radix-ui+react-switch@1.2.6_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-switch/dist/index.mjs
7545
+ var SWITCH_NAME = "Switch";
7546
+ var [createSwitchContext, createSwitchScope] = createContextScope(SWITCH_NAME);
7547
+ var [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME);
7548
+ var Switch = D((props, forwardedRef) => {
7549
+ const { __scopeSwitch, name, checked: checkedProp, defaultChecked, required, disabled, value = "on", onCheckedChange, form, ...switchProps } = props;
7550
+ const [button, setButton] = d$2(null);
7551
+ const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
7552
+ const hasConsumerStoppedPropagationRef = A$1(false);
7553
+ const isFormControl = button ? form || !!button.closest("form") : true;
7554
+ const [checked, setChecked] = useControllableState({
7555
+ prop: checkedProp,
7556
+ defaultProp: defaultChecked ?? false,
7557
+ onChange: onCheckedChange,
7558
+ caller: SWITCH_NAME
7559
+ });
7560
+ return /* @__PURE__ */ u(SwitchProvider, {
7561
+ scope: __scopeSwitch,
7562
+ checked,
7563
+ disabled,
7564
+ children: [/* @__PURE__ */ u(Primitive.button, {
7565
+ type: "button",
7566
+ role: "switch",
7567
+ "aria-checked": checked,
7568
+ "aria-required": required,
7569
+ "data-state": getState$2(checked),
7570
+ "data-disabled": disabled ? "" : void 0,
7571
+ disabled,
7572
+ value,
7573
+ ...switchProps,
7574
+ ref: composedRefs,
7575
+ onClick: composeEventHandlers(props.onClick, (event) => {
7576
+ setChecked((prevChecked) => !prevChecked);
7577
+ if (isFormControl) {
7578
+ hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
7579
+ if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
7580
+ }
7581
+ })
7582
+ }), isFormControl && /* @__PURE__ */ u(SwitchBubbleInput, {
7583
+ control: button,
7584
+ bubbles: !hasConsumerStoppedPropagationRef.current,
7585
+ name,
7586
+ value,
7587
+ checked,
7588
+ required,
7589
+ disabled,
7590
+ form,
7591
+ style: { transform: "translateX(-100%)" }
7592
+ })]
7593
+ });
7594
+ });
7595
+ Switch.displayName = SWITCH_NAME;
7596
+ var THUMB_NAME = "SwitchThumb";
7597
+ var SwitchThumb = D((props, forwardedRef) => {
7598
+ const { __scopeSwitch, ...thumbProps } = props;
7599
+ const context = useSwitchContext(THUMB_NAME, __scopeSwitch);
7600
+ return /* @__PURE__ */ u(Primitive.span, {
7601
+ "data-state": getState$2(context.checked),
7602
+ "data-disabled": context.disabled ? "" : void 0,
7603
+ ...thumbProps,
7604
+ ref: forwardedRef
7605
+ });
7606
+ });
7607
+ SwitchThumb.displayName = THUMB_NAME;
7608
+ var BUBBLE_INPUT_NAME$2 = "SwitchBubbleInput";
7609
+ var SwitchBubbleInput = D(({ __scopeSwitch, control, checked, bubbles = true, ...props }, forwardedRef) => {
7610
+ const ref = A$1(null);
7611
+ const composedRefs = useComposedRefs(ref, forwardedRef);
7612
+ const prevChecked = usePrevious(checked);
7613
+ const controlSize = useSize(control);
7614
+ y$2(() => {
7615
+ const input = ref.current;
7616
+ if (!input) return;
7617
+ const inputProto = window.HTMLInputElement.prototype;
7618
+ const setChecked = Object.getOwnPropertyDescriptor(inputProto, "checked").set;
7619
+ if (prevChecked !== checked && setChecked) {
7620
+ const event = new Event("click", { bubbles });
7621
+ setChecked.call(input, checked);
7622
+ input.dispatchEvent(event);
7623
+ }
7624
+ }, [
7625
+ prevChecked,
7626
+ checked,
7627
+ bubbles
7628
+ ]);
7629
+ return /* @__PURE__ */ u("input", {
7630
+ type: "checkbox",
7631
+ "aria-hidden": true,
7632
+ defaultChecked: checked,
7633
+ ...props,
7634
+ tabIndex: -1,
7635
+ ref: composedRefs,
7636
+ style: {
7637
+ ...props.style,
7638
+ ...controlSize,
7639
+ position: "absolute",
7640
+ pointerEvents: "none",
7641
+ opacity: 0,
7642
+ margin: 0
7643
+ }
7644
+ });
7645
+ });
7646
+ SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME$2;
7647
+ function getState$2(checked) {
7648
+ return checked ? "checked" : "unchecked";
7649
+ }
7650
+ var Root$1 = Switch;
7651
+ var Thumb = SwitchThumb;
7652
+ //#endregion
7653
+ //#region src/components/primitives/radix-switch.tsx
7654
+ function RadixSwitch({ "aria-labelledby": ariaLabelledBy, checked, className, disabled = false, id, name, onCheckedChange, thumbClassName }) {
7655
+ return /* @__PURE__ */ u(Root$1, {
7656
+ "aria-labelledby": ariaLabelledBy,
7657
+ checked,
7658
+ className,
7659
+ disabled,
7660
+ id,
7661
+ name,
7662
+ onCheckedChange,
7663
+ children: /* @__PURE__ */ u(Thumb, { className: thumbClassName })
7664
+ });
7665
+ }
7666
+ //#endregion
7667
+ //#region src/lib/notice.ts
7668
+ /**
7669
+ * Legacy signature kept for callsite stability. Now delegates to the Radix
7670
+ * Toast host (mounted once at app boot). Historically rendered via a static
7671
+ * #globalNotice div; that markup is gone — ToastHost owns the UI.
7672
+ */
7673
+ function showGlobalNotice(message, type = "success") {
7674
+ pushToast(message, type);
7675
+ }
7676
+ //#endregion
7677
+ //#region src/tabs/coordinator-admin/data/target-group.ts
7678
+ function adminTargetStorageKey(coordinatorUrl) {
7679
+ return `${ADMIN_TARGET_GROUP_KEY}:${String(coordinatorUrl || "").trim()}`;
7680
+ }
7681
+ function readStoredAdminTargetGroup(coordinatorUrl) {
7682
+ try {
7683
+ return localStorage.getItem(adminTargetStorageKey(coordinatorUrl)) || "";
7684
+ } catch {
7685
+ return "";
7686
+ }
7687
+ }
7688
+ function writeStoredAdminTargetGroup(coordinatorUrl, groupId) {
7689
+ try {
7690
+ localStorage.setItem(adminTargetStorageKey(coordinatorUrl), groupId);
7691
+ } catch {}
7692
+ }
7693
+ function currentAdminTargetGroup() {
7694
+ return String(state.coordinatorAdminTargetGroup || "").trim();
7695
+ }
7696
+ function setAdminTargetGroup(groupId) {
7697
+ state.coordinatorAdminTargetGroup = groupId;
7698
+ writeStoredAdminTargetGroup(state.lastCoordinatorAdminStatus?.coordinator_url || null, groupId);
7699
+ }
7700
+ function availableCoordinatorGroups() {
7701
+ return (Array.isArray(state.lastCoordinatorAdminGroups) ? state.lastCoordinatorAdminGroups : []).map((group) => ({
7702
+ archived_at: group.archived_at ?? null,
7703
+ display_name: group.display_name ?? null,
7704
+ group_id: String(group.group_id || "").trim()
7705
+ })).filter((group) => group.group_id);
7706
+ }
7707
+ function reconcileGroupRenameDrafts() {
7708
+ const next = /* @__PURE__ */ new Map();
7709
+ for (const group of availableCoordinatorGroups()) next.set(group.group_id, group.display_name || group.group_id);
7710
+ coordinatorAdminState.groupRenameDrafts.clear();
7711
+ for (const [groupId, name] of next.entries()) coordinatorAdminState.groupRenameDrafts.set(groupId, name);
7712
+ }
7713
+ function currentAdminTargetGroupRecord() {
7714
+ const target = currentAdminTargetGroup();
7715
+ return availableCoordinatorGroups().find((group) => group.group_id === target) || null;
7716
+ }
7717
+ function resolveAdminTargetGroup() {
7718
+ const status = state.lastCoordinatorAdminStatus;
7719
+ const groups = availableCoordinatorGroups();
7720
+ const configured = String(status?.active_group || "").trim();
7721
+ const stored = readStoredAdminTargetGroup(status?.coordinator_url || null);
7722
+ const current = currentAdminTargetGroup();
7723
+ const availableIds = new Set(groups.map((group) => group.group_id));
7724
+ const candidate = current || stored || configured || groups[0]?.group_id || "";
7725
+ const resolved = candidate && (availableIds.size === 0 || availableIds.has(candidate)) ? candidate : configured || groups[0]?.group_id || "";
7726
+ setAdminTargetGroup(resolved);
7727
+ return resolved;
7728
+ }
7729
+ function reconcileDeviceRenameDrafts() {
7730
+ const next = /* @__PURE__ */ new Map();
7731
+ const items = Array.isArray(state.lastCoordinatorAdminDevices) ? state.lastCoordinatorAdminDevices : [];
7732
+ for (const item of items) {
7733
+ const deviceId = String(item.device_id || "").trim();
7734
+ if (!deviceId) continue;
7735
+ next.set(deviceId, String(item.display_name || ""));
7736
+ }
7737
+ coordinatorAdminState.deviceRenameDrafts.clear();
7738
+ for (const [deviceId, name] of next.entries()) coordinatorAdminState.deviceRenameDrafts.set(deviceId, name);
7739
+ }
7740
+ //#endregion
7741
+ //#region src/tabs/coordinator-admin/components/groups-panel.ts
7742
+ function ChevronRightIcon$1() {
7743
+ return _$3("svg", {
7744
+ "aria-hidden": "true",
7745
+ fill: "none",
7746
+ stroke: "currentColor",
7747
+ "stroke-linecap": "round",
7748
+ "stroke-linejoin": "round",
7749
+ "stroke-width": "2",
7750
+ viewBox: "0 0 24 24",
7751
+ xmlns: "http://www.w3.org/2000/svg"
7752
+ }, _$3("title", null, "Chevron"), _$3("path", { d: "m9 18 6-6-6-6" }));
7753
+ }
7754
+ function emptyDraft() {
7755
+ return {
7756
+ projects_include: [],
7757
+ projects_exclude: [],
7758
+ auto_seed_scope: true,
7759
+ loaded: false,
7760
+ saving: false,
7761
+ error: ""
7762
+ };
7763
+ }
7764
+ async function openGroupPreferences(groupId, renderShell) {
7765
+ const draft = emptyDraft();
7766
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, draft);
7767
+ coordinatorAdminState.groupPreferencesOpen.add(groupId);
7768
+ renderShell();
7769
+ try {
7770
+ const prefs = await loadCoordinatorGroupPreferences(groupId);
7771
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7772
+ projects_include: Array.isArray(prefs.projects_include) ? [...prefs.projects_include] : [],
7773
+ projects_exclude: Array.isArray(prefs.projects_exclude) ? [...prefs.projects_exclude] : [],
7774
+ auto_seed_scope: prefs.auto_seed_scope,
7775
+ loaded: true,
7776
+ saving: false,
7777
+ error: ""
7778
+ });
7779
+ } catch (error) {
7780
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7781
+ ...draft,
7782
+ loaded: true,
7783
+ error: error instanceof Error ? error.message : "Failed to load preferences."
7784
+ });
7785
+ }
7786
+ renderShell();
7787
+ }
7788
+ function closeGroupPreferences(groupId, renderShell) {
7789
+ coordinatorAdminState.groupPreferencesOpen.delete(groupId);
7790
+ coordinatorAdminState.groupPreferencesDrafts.delete(groupId);
7791
+ renderShell();
7792
+ }
7793
+ async function saveGroupPreferences(groupId, renderShell) {
7794
+ const initial = coordinatorAdminState.groupPreferencesDrafts.get(groupId);
7795
+ if (!initial) return;
7796
+ if (initial.saving) return;
7797
+ const payload = {
7798
+ projects_include: initial.projects_include.length > 0 ? [...initial.projects_include] : null,
7799
+ projects_exclude: initial.projects_exclude.length > 0 ? [...initial.projects_exclude] : null,
7800
+ auto_seed_scope: initial.auto_seed_scope
7801
+ };
7802
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7803
+ ...initial,
7804
+ saving: true,
7805
+ error: ""
7806
+ });
7807
+ renderShell();
7808
+ try {
7809
+ await saveCoordinatorGroupPreferences(groupId, payload);
7810
+ showGlobalNotice("Group scope defaults saved. New peers enrolled through this team will use these defaults.");
7811
+ closeGroupPreferences(groupId, renderShell);
7812
+ } catch (error) {
7813
+ const latest = coordinatorAdminState.groupPreferencesDrafts.get(groupId);
7814
+ if (!latest) return;
7815
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7816
+ ...latest,
7817
+ saving: false,
7818
+ error: error instanceof Error ? error.message : "Failed to save preferences."
7819
+ });
7820
+ renderShell();
7821
+ }
7822
+ }
7823
+ function renderGroupPreferencesEditor(groupId, renderShell, ready) {
7824
+ const draft = coordinatorAdminState.groupPreferencesDrafts.get(groupId);
7825
+ if (!draft) return null;
7826
+ if (!draft.loaded) return _$3("div", { class: "peer-submeta" }, "Loading scope defaults…");
7827
+ const autoSeedLabelId = `coord-admin-scope-autoseed-${groupId}`;
7828
+ const includeLabelId = `coord-admin-scope-include-${groupId}`;
7829
+ const excludeLabelId = `coord-admin-scope-exclude-${groupId}`;
7830
+ const fieldsDisabled = !ready || draft.saving || !draft.auto_seed_scope;
7831
+ return _$3(k$3, null, _$3("h4", { class: "coordinator-admin-drawer-title" }, "Scope defaults"), _$3("div", { class: "peer-submeta" }, "When enabled, new peers enrolled through this team start with the project filters below. Existing peers are unchanged."), _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
7832
+ class: "section-meta",
7833
+ id: autoSeedLabelId
7834
+ }, "Auto-seed scope on new peers"), _$3(RadixSwitch, {
7835
+ "aria-labelledby": autoSeedLabelId,
7836
+ checked: draft.auto_seed_scope,
7837
+ className: "coordinator-admin-switch",
7838
+ disabled: !ready || draft.saving,
7839
+ onCheckedChange: (checked) => {
7840
+ const current = coordinatorAdminState.groupPreferencesDrafts.get(groupId) ?? draft;
7841
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7842
+ ...current,
7843
+ auto_seed_scope: checked
7844
+ });
7845
+ renderShell();
7846
+ },
7847
+ thumbClassName: "coordinator-admin-switch-thumb"
7848
+ })), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: includeLabelId }, "Include projects"), _$3(ProjectScopePicker, {
7849
+ "aria-labelledby": includeLabelId,
7850
+ availableProjects: coordinatorAdminState.availableProjects,
7851
+ disabled: fieldsDisabled,
7852
+ emptyLabel: "All projects allowed.",
7853
+ onValuesChange: (next) => {
7854
+ const current = coordinatorAdminState.groupPreferencesDrafts.get(groupId) ?? draft;
7855
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7856
+ ...current,
7857
+ projects_include: next
7858
+ });
7859
+ renderShell();
7860
+ },
7861
+ placeholder: "Add project",
7862
+ values: draft.projects_include
7863
+ }), _$3("span", { class: "peer-submeta" }, "Leave empty to allow every project. Type to search or create a new name.")), _$3("div", { class: "coordinator-admin-field" }, _$3("span", { id: excludeLabelId }, "Exclude projects"), _$3(ProjectScopePicker, {
7864
+ "aria-labelledby": excludeLabelId,
7865
+ availableProjects: coordinatorAdminState.availableProjects,
7866
+ disabled: fieldsDisabled,
7867
+ emptyLabel: "Nothing excluded.",
7868
+ onValuesChange: (next) => {
7869
+ const current = coordinatorAdminState.groupPreferencesDrafts.get(groupId) ?? draft;
7870
+ coordinatorAdminState.groupPreferencesDrafts.set(groupId, {
7871
+ ...current,
7872
+ projects_exclude: next
7873
+ });
7874
+ renderShell();
7875
+ },
7876
+ placeholder: "Add project",
7877
+ values: draft.projects_exclude
7878
+ })), draft.error ? _$3("div", { class: "peer-submeta coordinator-admin-error" }, draft.error) : null, _$3("div", { class: "peer-actions" }, _$3("button", {
7879
+ class: "settings-button",
7880
+ disabled: !ready || draft.saving,
7881
+ onClick: () => void saveGroupPreferences(groupId, renderShell),
7882
+ type: "button"
7883
+ }, draft.saving ? "Saving…" : "Save defaults"), _$3("button", {
7884
+ class: "settings-button",
7885
+ disabled: draft.saving,
7886
+ onClick: () => closeGroupPreferences(groupId, renderShell),
7887
+ type: "button"
7888
+ }, "Cancel")));
7889
+ }
7890
+ function renderGroupsPanel(deps) {
7891
+ const { summary, createGroup, runGroup, renderShell, reloadData } = deps;
7892
+ const configuredGroup = String(state.lastCoordinatorAdminStatus?.active_group || "").trim();
7893
+ const selectedGroup = currentAdminTargetGroup();
7894
+ const groups = availableCoordinatorGroups();
7895
+ const activeGroups = groups.filter((group) => !group.archived_at);
7896
+ const archivedGroups = groups.filter((group) => group.archived_at);
7897
+ const visibleGroups = coordinatorAdminState.showArchivedGroups ? groups : activeGroups;
7898
+ const targetExists = selectedGroup ? groups.some((group) => group.group_id === selectedGroup) : false;
7899
+ const countParts = [`${activeGroups.length} active`];
7900
+ if (archivedGroups.length) countParts.push(`${archivedGroups.length} archived`);
7901
+ return _$3(RadixTabsContent, {
7902
+ className: "coordinator-admin-panel",
7903
+ value: "groups"
7904
+ }, _$3("h3", null, "Groups"), _$3("p", { class: "peer-submeta" }, selectedGroup ? `Managing ${selectedGroup}${configuredGroup && configuredGroup !== selectedGroup ? ` · this node uses ${configuredGroup} for discovery` : ""}` : configuredGroup ? `This node uses ${configuredGroup} for discovery. Select a group below to manage it.` : "No group selected yet. Create one or select an existing group to manage."), groups.length ? _$3("p", { class: "peer-submeta" }, countParts.join(" · ")) : null, !targetExists && selectedGroup ? _$3("div", { class: "peer-meta coordinator-admin-inline-warning" }, `The selected admin target group (${selectedGroup}) is configured locally but does not exist in the coordinator yet. Create it below or switch to another group once one exists.`) : null, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New group id"), _$3(TextInput, {
7905
+ class: "peer-scope-input",
7906
+ disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
7907
+ onInput: (event) => {
7908
+ coordinatorAdminState.createGroupId = String(event.currentTarget.value || "");
7909
+ },
7910
+ placeholder: "team-alpha",
7911
+ type: "text",
7912
+ value: coordinatorAdminState.createGroupId
7913
+ })), _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
7914
+ class: "peer-scope-input",
7915
+ disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
7916
+ onInput: (event) => {
7917
+ coordinatorAdminState.createGroupDisplayName = String(event.currentTarget.value || "");
7918
+ },
7919
+ placeholder: "Team Alpha",
7920
+ type: "text",
7921
+ value: coordinatorAdminState.createGroupDisplayName
7922
+ }))), _$3("div", { class: "section-actions coordinator-admin-groups-toolbar" }, _$3("div", { class: "coordinator-admin-primary-actions" }, _$3("button", {
7923
+ class: "settings-button",
7924
+ disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
7925
+ onClick: () => createGroup(),
7926
+ type: "button"
7927
+ }, coordinatorAdminState.groupActionPendingKind === "create" ? "Creating…" : "Create group")), _$3("div", { class: "coordinator-admin-secondary-actions" }, _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
7928
+ class: "section-meta",
7929
+ id: "coordinatorAdminShowArchivedLabel"
7930
+ }, "Show archived"), _$3(RadixSwitch, {
7931
+ "aria-labelledby": "coordinatorAdminShowArchivedLabel",
7932
+ checked: coordinatorAdminState.showArchivedGroups,
7933
+ className: "coordinator-admin-switch",
7934
+ disabled: summary.readiness !== "ready",
7935
+ onCheckedChange: (checked) => {
7936
+ coordinatorAdminState.showArchivedGroups = checked;
7937
+ renderShell();
7938
+ },
7939
+ thumbClassName: "coordinator-admin-switch-thumb"
7940
+ })))), !visibleGroups.length ? _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, summary.readiness === "ready" ? coordinatorAdminState.showArchivedGroups ? "No coordinator groups are available yet." : "No active groups yet. Create one to get started." : "Group browsing will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, visibleGroups.map((group) => {
7941
+ const selected = group.group_id === selectedGroup;
7942
+ const pending = coordinatorAdminState.groupActionPendingId === group.group_id;
7943
+ const archived = Boolean(group.archived_at);
7944
+ const draftName = coordinatorAdminState.groupRenameDrafts.get(group.group_id) ?? group.display_name ?? group.group_id;
7945
+ const scopeOpen = coordinatorAdminState.groupPreferencesOpen.has(group.group_id);
7946
+ return _$3("div", {
7947
+ class: "peer-card peer-card--padded",
7948
+ key: group.group_id
7949
+ }, _$3("div", { class: "peer-title" }, _$3("strong", null, draftName)), _$3("div", { class: "peer-meta" }, `Group ID: ${group.group_id}`), _$3("div", { class: "peer-submeta" }, archived ? "Archived" : "Active"), configuredGroup === group.group_id ? _$3("div", { class: "peer-submeta" }, "This node is configured to use this group for coordinator-backed discovery.") : null, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
7950
+ class: "peer-scope-input",
7951
+ disabled: summary.readiness !== "ready" || pending,
7952
+ onInput: (event) => {
7953
+ coordinatorAdminState.groupRenameDrafts.set(group.group_id, String(event.currentTarget.value || ""));
7954
+ },
7955
+ type: "text",
7956
+ value: draftName
7957
+ })), _$3("div", { class: "peer-actions" }, _$3("button", {
7958
+ class: "settings-button",
7959
+ disabled: summary.readiness !== "ready" || selected,
7960
+ onClick: () => {
7961
+ setAdminTargetGroup(group.group_id);
7962
+ reloadData();
7963
+ },
7964
+ type: "button"
7965
+ }, selected ? "Managing" : "Manage"), _$3("button", {
7966
+ class: "settings-button",
7967
+ disabled: summary.readiness !== "ready" || pending,
7968
+ onClick: () => runGroup(group.group_id, draftName, "rename"),
7969
+ type: "button"
7970
+ }, pending && coordinatorAdminState.groupActionPendingKind === "rename" ? "Renaming…" : "Rename"), _$3("button", {
7971
+ "aria-expanded": scopeOpen,
7972
+ "aria-controls": `coord-admin-scope-drawer-${group.group_id}`,
7973
+ class: "settings-button coordinator-admin-scope-trigger",
7974
+ "data-state": scopeOpen ? "open" : "closed",
7975
+ disabled: summary.readiness !== "ready" || pending,
7976
+ onClick: () => {
7977
+ if (scopeOpen) closeGroupPreferences(group.group_id, renderShell);
7978
+ else openGroupPreferences(group.group_id, renderShell);
7979
+ },
7980
+ type: "button"
7981
+ }, _$3("span", null, "Scope defaults"), _$3("span", {
7982
+ "aria-hidden": "true",
7983
+ class: "device-row-chevron"
7984
+ }, _$3(ChevronRightIcon$1, null))), _$3("button", {
7985
+ class: archived ? "settings-button" : "settings-button danger",
7986
+ disabled: summary.readiness !== "ready" || pending,
7987
+ onClick: () => runGroup(group.group_id, group.display_name || group.group_id, archived ? "unarchive" : "archive"),
7988
+ type: "button"
7989
+ }, pending && coordinatorAdminState.groupActionPendingKind === (archived ? "unarchive" : "archive") ? archived ? "Restoring…" : "Archiving…" : archived ? "Unarchive" : "Archive")), _$3(Root$3, {
7990
+ open: scopeOpen,
7991
+ onOpenChange: (open) => {
7992
+ if (open) openGroupPreferences(group.group_id, renderShell);
7993
+ else closeGroupPreferences(group.group_id, renderShell);
7994
+ }
7995
+ }, _$3(Content$2, {
7996
+ "aria-label": `Scope defaults for ${draftName}`,
7997
+ class: "coordinator-admin-group-preferences",
7998
+ id: `coord-admin-scope-drawer-${group.group_id}`
7999
+ }, scopeOpen ? renderGroupPreferencesEditor(group.group_id, renderShell, summary.readiness === "ready") : null)));
8000
+ })));
8001
+ }
8002
+ //#endregion
8003
+ //#region ../../node_modules/.pnpm/@radix-ui+number@1.1.1/node_modules/@radix-ui/number/dist/index.mjs
8004
+ function clamp(value, [min, max]) {
8005
+ return Math.min(max, Math.max(min, value));
8006
+ }
7240
8007
  //#endregion
7241
8008
  //#region ../../node_modules/.pnpm/@radix-ui+react-select@2.2.6_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-select/dist/index.mjs
7242
8009
  var OPEN_KEYS = [
@@ -7275,7 +8042,7 @@
7275
8042
  const isFormControl = trigger ? form || !!trigger.closest("form") : true;
7276
8043
  const [nativeOptionsSet, setNativeOptionsSet] = d$2(/* @__PURE__ */ new Set());
7277
8044
  const nativeSelectKey = Array.from(nativeOptionsSet).map((option) => option.props.value).join(";");
7278
- return /* @__PURE__ */ u(Root2$3, {
8045
+ return /* @__PURE__ */ u(Root2$4, {
7279
8046
  ...popperScope,
7280
8047
  children: /* @__PURE__ */ u(SelectProvider, {
7281
8048
  required,
@@ -7326,11 +8093,11 @@
7326
8093
  });
7327
8094
  };
7328
8095
  Select.displayName = SELECT_NAME;
7329
- var TRIGGER_NAME$4 = "SelectTrigger";
8096
+ var TRIGGER_NAME$3 = "SelectTrigger";
7330
8097
  var SelectTrigger = D((props, forwardedRef) => {
7331
8098
  const { __scopeSelect, disabled = false, ...triggerProps } = props;
7332
8099
  const popperScope = usePopperScope$2(__scopeSelect);
7333
- const context = useSelectContext(TRIGGER_NAME$4, __scopeSelect);
8100
+ const context = useSelectContext(TRIGGER_NAME$3, __scopeSelect);
7334
8101
  const isDisabled = context.disabled || disabled;
7335
8102
  const composedRefs = useComposedRefs(forwardedRef, context.onTriggerChange);
7336
8103
  const getItems = useCollection$1(__scopeSelect);
@@ -7392,7 +8159,7 @@
7392
8159
  })
7393
8160
  });
7394
8161
  });
7395
- SelectTrigger.displayName = TRIGGER_NAME$4;
8162
+ SelectTrigger.displayName = TRIGGER_NAME$3;
7396
8163
  var VALUE_NAME = "SelectValue";
7397
8164
  var SelectValue = D((props, forwardedRef) => {
7398
8165
  const { __scopeSelect, className, style, children, placeholder = "", ...valueProps } = props;
@@ -7424,15 +8191,15 @@
7424
8191
  SelectIcon.displayName = ICON_NAME;
7425
8192
  var PORTAL_NAME$4 = "SelectPortal";
7426
8193
  var SelectPortal = (props) => {
7427
- return /* @__PURE__ */ u(Portal$4, {
8194
+ return /* @__PURE__ */ u(Portal$5, {
7428
8195
  asChild: true,
7429
8196
  ...props
7430
8197
  });
7431
8198
  };
7432
8199
  SelectPortal.displayName = PORTAL_NAME$4;
7433
- var CONTENT_NAME$5 = "SelectContent";
8200
+ var CONTENT_NAME$4 = "SelectContent";
7434
8201
  var SelectContent = D((props, forwardedRef) => {
7435
- const context = useSelectContext(CONTENT_NAME$5, props.__scopeSelect);
8202
+ const context = useSelectContext(CONTENT_NAME$4, props.__scopeSelect);
7436
8203
  const [fragment, setFragment] = d$2();
7437
8204
  useLayoutEffect2(() => {
7438
8205
  setFragment(new DocumentFragment());
@@ -7452,14 +8219,14 @@
7452
8219
  ref: forwardedRef
7453
8220
  });
7454
8221
  });
7455
- SelectContent.displayName = CONTENT_NAME$5;
8222
+ SelectContent.displayName = CONTENT_NAME$4;
7456
8223
  var CONTENT_MARGIN = 10;
7457
- var [SelectContentProvider, useSelectContentContext] = createSelectContext(CONTENT_NAME$5);
8224
+ var [SelectContentProvider, useSelectContentContext] = createSelectContext(CONTENT_NAME$4);
7458
8225
  var CONTENT_IMPL_NAME = "SelectContentImpl";
7459
8226
  var Slot$2 = /* @__PURE__ */ createSlot("SelectContent.RemoveScroll");
7460
8227
  var SelectContentImpl = D((props, forwardedRef) => {
7461
8228
  const { __scopeSelect, position = "item-aligned", onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, side, sideOffset, align, alignOffset, arrowPadding, collisionBoundary, collisionPadding, sticky, hideWhenDetached, avoidCollisions, ...contentProps } = props;
7462
- const context = useSelectContext(CONTENT_NAME$5, __scopeSelect);
8229
+ const context = useSelectContext(CONTENT_NAME$4, __scopeSelect);
7463
8230
  const [content, setContent] = d$2(null);
7464
8231
  const [viewport, setViewport] = d$2(null);
7465
8232
  const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node));
@@ -7649,8 +8416,8 @@
7649
8416
  var ITEM_ALIGNED_POSITION_NAME = "SelectItemAlignedPosition";
7650
8417
  var SelectItemAlignedPosition = D((props, forwardedRef) => {
7651
8418
  const { __scopeSelect, onPlaced, ...popperProps } = props;
7652
- const context = useSelectContext(CONTENT_NAME$5, __scopeSelect);
7653
- const contentContext = useSelectContentContext(CONTENT_NAME$5, __scopeSelect);
8419
+ const context = useSelectContext(CONTENT_NAME$4, __scopeSelect);
8420
+ const contentContext = useSelectContentContext(CONTENT_NAME$4, __scopeSelect);
7654
8421
  const [contentWrapper, setContentWrapper] = d$2(null);
7655
8422
  const [content, setContent] = d$2(null);
7656
8423
  const composedRefs = useComposedRefs(forwardedRef, (node) => setContent(node));
@@ -7671,7 +8438,7 @@
7671
8438
  const minContentWidth = triggerRect.width + leftDelta;
7672
8439
  const contentWidth = Math.max(minContentWidth, contentRect.width);
7673
8440
  const rightEdge = window.innerWidth - CONTENT_MARGIN;
7674
- const clampedLeft = clamp$1(left, [CONTENT_MARGIN, Math.max(CONTENT_MARGIN, rightEdge - contentWidth)]);
8441
+ const clampedLeft = clamp(left, [CONTENT_MARGIN, Math.max(CONTENT_MARGIN, rightEdge - contentWidth)]);
7675
8442
  contentWrapper.style.minWidth = minContentWidth + "px";
7676
8443
  contentWrapper.style.left = clampedLeft + "px";
7677
8444
  } else {
@@ -7681,7 +8448,7 @@
7681
8448
  const minContentWidth = triggerRect.width + rightDelta;
7682
8449
  const contentWidth = Math.max(minContentWidth, contentRect.width);
7683
8450
  const leftEdge = window.innerWidth - CONTENT_MARGIN;
7684
- const clampedRight = clamp$1(right, [CONTENT_MARGIN, Math.max(CONTENT_MARGIN, leftEdge - contentWidth)]);
8451
+ const clampedRight = clamp(right, [CONTENT_MARGIN, Math.max(CONTENT_MARGIN, leftEdge - contentWidth)]);
7685
8452
  contentWrapper.style.minWidth = minContentWidth + "px";
7686
8453
  contentWrapper.style.right = clampedRight + "px";
7687
8454
  }
@@ -7775,7 +8542,7 @@
7775
8542
  var POPPER_POSITION_NAME = "SelectPopperPosition";
7776
8543
  var SelectPopperPosition = D((props, forwardedRef) => {
7777
8544
  const { __scopeSelect, align = "start", collisionPadding = CONTENT_MARGIN, ...popperProps } = props;
7778
- return /* @__PURE__ */ u(Content$2, {
8545
+ return /* @__PURE__ */ u(Content$1, {
7779
8546
  ...usePopperScope$2(__scopeSelect),
7780
8547
  ...popperProps,
7781
8548
  ref: forwardedRef,
@@ -7793,7 +8560,7 @@
7793
8560
  });
7794
8561
  });
7795
8562
  SelectPopperPosition.displayName = POPPER_POSITION_NAME;
7796
- var [SelectViewportProvider, useSelectViewportContext] = createSelectContext(CONTENT_NAME$5, {});
8563
+ var [SelectViewportProvider, useSelectViewportContext] = createSelectContext(CONTENT_NAME$4, {});
7797
8564
  var VIEWPORT_NAME = "SelectViewport";
7798
8565
  var SelectViewport = D((props, forwardedRef) => {
7799
8566
  const { __scopeSelect, nonce, ...viewportProps } = props;
@@ -8174,7 +8941,7 @@
8174
8941
  return array.map((_, index) => array[(startIndex + index) % array.length]);
8175
8942
  }
8176
8943
  var Root2$2 = Select;
8177
- var Trigger$3 = SelectTrigger;
8944
+ var Trigger$2 = SelectTrigger;
8178
8945
  var Value = SelectValue;
8179
8946
  var Icon = SelectIcon;
8180
8947
  var Portal$3 = SelectPortal;
@@ -8225,7 +8992,7 @@
8225
8992
  disabled,
8226
8993
  onValueChange: (nextValue) => onValueChange(decodeValue(nextValue)),
8227
8994
  value: value ? encodeValue(value) : void 0,
8228
- children: [/* @__PURE__ */ u(Trigger$3, {
8995
+ children: [/* @__PURE__ */ u(Trigger$2, {
8229
8996
  "aria-label": ariaLabel,
8230
8997
  className: triggerClassName ?? className,
8231
8998
  "data-value": value,
@@ -8334,13 +9101,13 @@
8334
9101
  return _$3(RadixTabsContent, {
8335
9102
  className: "coordinator-admin-panel",
8336
9103
  value: "join-requests"
8337
- }, _$3("h3", null, "Pending join requests"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Approve or deny teammate join requests from the dedicated operator surface instead of burying them in Sync." : "Finish setup first. Join request review stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No pending join requests right now." : "Join request review will appear here once setup is complete.") : _$3("div", { class: "coordinator-admin-request-list" }, items.map((item) => {
9104
+ }, _$3("h3", null, "Pending join requests"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Approve or deny teammate join requests from the dedicated operator surface instead of burying them in Sync." : "Finish setup first. Join request review stays disabled until coordinator admin is ready."), !items.length ? _$3("div", { class: "peer-meta" }, summary.readiness === "ready" ? "No pending join requests right now." : "Join request review will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, items.map((item) => {
8338
9105
  const requestId = String(item.request_id || "").trim();
8339
9106
  const deviceId = String(item.device_id || "unknown-device");
8340
9107
  const displayName = String(item.display_name || deviceId);
8341
9108
  const pending = coordinatorAdminState.joinReviewPendingId === requestId;
8342
9109
  return _$3("div", {
8343
- class: "peer-card",
9110
+ class: "peer-card peer-card--padded",
8344
9111
  key: requestId || deviceId
8345
9112
  }, _$3("div", { class: "peer-title" }, _$3("strong", null, displayName)), _$3("div", { class: "peer-meta" }, `Device: ${deviceId}`), _$3("div", { class: "peer-actions" }, _$3("button", {
8346
9113
  class: "settings-button",
@@ -8356,16 +9123,6 @@
8356
9123
  })));
8357
9124
  }
8358
9125
  //#endregion
8359
- //#region src/lib/notice.ts
8360
- /**
8361
- * Legacy signature kept for callsite stability. Now delegates to the Radix
8362
- * Toast host (mounted once at app boot). Historically rendered via a static
8363
- * #globalNotice div; that markup is gone — ToastHost owns the UI.
8364
- */
8365
- function showGlobalNotice(message, type = "success") {
8366
- pushToast(message, type);
8367
- }
8368
- //#endregion
8369
9126
  //#region ../../node_modules/.pnpm/@radix-ui+react-dialog@1.1.15_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-dialog/dist/index.mjs
8370
9127
  var DIALOG_NAME = "Dialog";
8371
9128
  var [createDialogContext, createDialogScope] = createContextScope(DIALOG_NAME);
@@ -8395,23 +9152,23 @@
8395
9152
  });
8396
9153
  };
8397
9154
  Dialog.displayName = DIALOG_NAME;
8398
- var TRIGGER_NAME$3 = "DialogTrigger";
9155
+ var TRIGGER_NAME$2 = "DialogTrigger";
8399
9156
  var DialogTrigger = D((props, forwardedRef) => {
8400
9157
  const { __scopeDialog, ...triggerProps } = props;
8401
- const context = useDialogContext(TRIGGER_NAME$3, __scopeDialog);
9158
+ const context = useDialogContext(TRIGGER_NAME$2, __scopeDialog);
8402
9159
  const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);
8403
9160
  return /* @__PURE__ */ u(Primitive.button, {
8404
9161
  type: "button",
8405
9162
  "aria-haspopup": "dialog",
8406
9163
  "aria-expanded": context.open,
8407
9164
  "aria-controls": context.contentId,
8408
- "data-state": getState$2(context.open),
9165
+ "data-state": getState$1(context.open),
8409
9166
  ...triggerProps,
8410
9167
  ref: composedTriggerRef,
8411
9168
  onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
8412
9169
  });
8413
9170
  });
8414
- DialogTrigger.displayName = TRIGGER_NAME$3;
9171
+ DialogTrigger.displayName = TRIGGER_NAME$2;
8415
9172
  var PORTAL_NAME$3 = "DialogPortal";
8416
9173
  var [PortalProvider$2, usePortalContext$2] = createDialogContext(PORTAL_NAME$3, { forceMount: void 0 });
8417
9174
  var DialogPortal = (props) => {
@@ -8422,7 +9179,7 @@
8422
9179
  forceMount,
8423
9180
  children: L.map(children, (child) => /* @__PURE__ */ u(Presence, {
8424
9181
  present: forceMount || context.open,
8425
- children: /* @__PURE__ */ u(Portal$4, {
9182
+ children: /* @__PURE__ */ u(Portal$5, {
8426
9183
  asChild: true,
8427
9184
  container,
8428
9185
  children: child
@@ -8454,7 +9211,7 @@
8454
9211
  allowPinchZoom: true,
8455
9212
  shards: [context.contentRef],
8456
9213
  children: /* @__PURE__ */ u(Primitive.div, {
8457
- "data-state": getState$2(context.open),
9214
+ "data-state": getState$1(context.open),
8458
9215
  ...overlayProps,
8459
9216
  ref: forwardedRef,
8460
9217
  style: {
@@ -8464,11 +9221,11 @@
8464
9221
  })
8465
9222
  });
8466
9223
  });
8467
- var CONTENT_NAME$4 = "DialogContent";
9224
+ var CONTENT_NAME$3 = "DialogContent";
8468
9225
  var DialogContent = D((props, forwardedRef) => {
8469
- const portalContext = usePortalContext$2(CONTENT_NAME$4, props.__scopeDialog);
9226
+ const portalContext = usePortalContext$2(CONTENT_NAME$3, props.__scopeDialog);
8470
9227
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
8471
- const context = useDialogContext(CONTENT_NAME$4, props.__scopeDialog);
9228
+ const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
8472
9229
  return /* @__PURE__ */ u(Presence, {
8473
9230
  present: forceMount || context.open,
8474
9231
  children: context.modal ? /* @__PURE__ */ u(DialogContentModal, {
@@ -8480,9 +9237,9 @@
8480
9237
  })
8481
9238
  });
8482
9239
  });
8483
- DialogContent.displayName = CONTENT_NAME$4;
9240
+ DialogContent.displayName = CONTENT_NAME$3;
8484
9241
  var DialogContentModal = D((props, forwardedRef) => {
8485
- const context = useDialogContext(CONTENT_NAME$4, props.__scopeDialog);
9242
+ const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
8486
9243
  const contentRef = A$1(null);
8487
9244
  const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef);
8488
9245
  y$2(() => {
@@ -8507,7 +9264,7 @@
8507
9264
  });
8508
9265
  });
8509
9266
  var DialogContentNonModal = D((props, forwardedRef) => {
8510
- const context = useDialogContext(CONTENT_NAME$4, props.__scopeDialog);
9267
+ const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
8511
9268
  const hasInteractedOutsideRef = A$1(false);
8512
9269
  const hasPointerDownOutsideRef = A$1(false);
8513
9270
  return /* @__PURE__ */ u(DialogContentImpl, {
@@ -8538,7 +9295,7 @@
8538
9295
  });
8539
9296
  var DialogContentImpl = D((props, forwardedRef) => {
8540
9297
  const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
8541
- const context = useDialogContext(CONTENT_NAME$4, __scopeDialog);
9298
+ const context = useDialogContext(CONTENT_NAME$3, __scopeDialog);
8542
9299
  const contentRef = A$1(null);
8543
9300
  const composedRefs = useComposedRefs(forwardedRef, contentRef);
8544
9301
  useFocusGuards();
@@ -8553,7 +9310,7 @@
8553
9310
  id: context.contentId,
8554
9311
  "aria-describedby": context.descriptionId,
8555
9312
  "aria-labelledby": context.titleId,
8556
- "data-state": getState$2(context.open),
9313
+ "data-state": getState$1(context.open),
8557
9314
  ...contentProps,
8558
9315
  ref: composedRefs,
8559
9316
  onDismiss: () => context.onOpenChange(false)
@@ -8597,12 +9354,12 @@
8597
9354
  });
8598
9355
  });
8599
9356
  DialogClose.displayName = CLOSE_NAME;
8600
- function getState$2(open) {
9357
+ function getState$1(open) {
8601
9358
  return open ? "open" : "closed";
8602
9359
  }
8603
9360
  var TITLE_WARNING_NAME = "DialogTitleWarning";
8604
9361
  var [WarningProvider, useWarningContext] = createContext2(TITLE_WARNING_NAME, {
8605
- contentName: CONTENT_NAME$4,
9362
+ contentName: CONTENT_NAME$3,
8606
9363
  titleName: TITLE_NAME,
8607
9364
  docsSlug: "dialog"
8608
9365
  });
@@ -8635,14 +9392,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8635
9392
  ]);
8636
9393
  return null;
8637
9394
  };
8638
- var Root$1 = Dialog;
9395
+ var Root = Dialog;
8639
9396
  var Portal$2 = DialogPortal;
8640
9397
  var Overlay = DialogOverlay;
8641
- var Content$1 = DialogContent;
9398
+ var Content = DialogContent;
8642
9399
  //#endregion
8643
9400
  //#region src/components/primitives/radix-dialog.tsx
8644
9401
  function RadixDialog({ ariaDescribedby, ariaLabelledby, children, contentClassName, contentId, modal = true, onCloseAutoFocus, onEscapeKeyDown, onInteractOutside, onOpenAutoFocus, onOpenChange, open, overlayClassName, overlayId, slotId }) {
8645
- return /* @__PURE__ */ u(Root$1, {
9402
+ return /* @__PURE__ */ u(Root, {
8646
9403
  modal,
8647
9404
  open,
8648
9405
  onOpenChange,
@@ -8652,7 +9409,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8652
9409
  className: overlayClassName,
8653
9410
  id: overlayId
8654
9411
  })
8655
- }), /* @__PURE__ */ u(Content$1, {
9412
+ }), /* @__PURE__ */ u(Content, {
8656
9413
  "aria-describedby": ariaDescribedby,
8657
9414
  "aria-labelledby": ariaLabelledby,
8658
9415
  asChild: true,
@@ -8716,6 +9473,125 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8716
9473
  return tone === "danger" ? "sync-dialog-confirm danger" : "sync-dialog-confirm";
8717
9474
  }
8718
9475
  //#endregion
9476
+ //#region src/components/primitives/autocomplete-input.tsx
9477
+ var AutocompleteInput = D(function AutocompleteInput({ value, onValueChange, suggestions, onSubmit, maxSuggestions = 20, onKeyDown, onFocus, onBlur, className, ...inputProps }, externalRef) {
9478
+ const inputRef = A$1(null);
9479
+ F$2(externalRef, () => inputRef.current, []);
9480
+ const [open, setOpen] = d$2(false);
9481
+ const [activeIndex, setActiveIndex] = d$2(-1);
9482
+ const filtered = T$1(() => {
9483
+ const q = value.trim().toLowerCase();
9484
+ return (q ? suggestions.filter((s) => s.toLowerCase().includes(q)) : suggestions).slice(0, maxSuggestions);
9485
+ }, [
9486
+ value,
9487
+ suggestions,
9488
+ maxSuggestions
9489
+ ]);
9490
+ y$2(() => {
9491
+ if (activeIndex >= filtered.length) setActiveIndex(filtered.length - 1);
9492
+ }, [filtered.length, activeIndex]);
9493
+ const shouldOpen = open && filtered.length > 0;
9494
+ const commit = (selection) => {
9495
+ onValueChange(selection);
9496
+ setOpen(false);
9497
+ setActiveIndex(-1);
9498
+ inputRef.current?.focus();
9499
+ };
9500
+ const handleKeyDown = (event) => {
9501
+ if (event.key === "ArrowDown") {
9502
+ event.preventDefault();
9503
+ setOpen(true);
9504
+ setActiveIndex((i) => filtered.length === 0 ? -1 : Math.min(i + 1, filtered.length - 1));
9505
+ return;
9506
+ }
9507
+ if (event.key === "ArrowUp") {
9508
+ event.preventDefault();
9509
+ if (!open) setOpen(true);
9510
+ setActiveIndex((i) => Math.max(i - 1, -1));
9511
+ return;
9512
+ }
9513
+ if (event.key === "Escape" && shouldOpen) {
9514
+ event.preventDefault();
9515
+ setOpen(false);
9516
+ setActiveIndex(-1);
9517
+ return;
9518
+ }
9519
+ if ((event.key === "Tab" || event.key === "Enter") && activeIndex >= 0) {
9520
+ const pick = filtered[activeIndex];
9521
+ if (pick) {
9522
+ event.preventDefault();
9523
+ commit(pick);
9524
+ return;
9525
+ }
9526
+ }
9527
+ if (event.key === "Enter" && onSubmit) {
9528
+ event.preventDefault();
9529
+ onSubmit();
9530
+ return;
9531
+ }
9532
+ onKeyDown?.(event);
9533
+ };
9534
+ return /* @__PURE__ */ u(Root2$3, {
9535
+ open: shouldOpen,
9536
+ onOpenChange: setOpen,
9537
+ children: [/* @__PURE__ */ u(Anchor2$1, {
9538
+ asChild: true,
9539
+ children: /* @__PURE__ */ u("input", {
9540
+ ...inputProps,
9541
+ ref: inputRef,
9542
+ className,
9543
+ value,
9544
+ onInput: (event) => {
9545
+ onValueChange(event.currentTarget.value);
9546
+ setOpen(true);
9547
+ setActiveIndex(-1);
9548
+ },
9549
+ onFocus: (event) => {
9550
+ onFocus?.(event);
9551
+ },
9552
+ onBlur: (event) => {
9553
+ window.setTimeout(() => setOpen(false), 120);
9554
+ onBlur?.(event);
9555
+ },
9556
+ onKeyDown: handleKeyDown,
9557
+ role: "combobox",
9558
+ "aria-autocomplete": "list",
9559
+ "aria-expanded": shouldOpen,
9560
+ "aria-controls": "autocompleteListbox",
9561
+ "aria-activedescendant": activeIndex >= 0 ? `autocomplete-option-${activeIndex}` : void 0
9562
+ })
9563
+ }), /* @__PURE__ */ u(Portal$4, { children: /* @__PURE__ */ u(Content2$4, {
9564
+ align: "start",
9565
+ className: "autocomplete-popover",
9566
+ onOpenAutoFocus: (event) => event.preventDefault(),
9567
+ onCloseAutoFocus: (event) => event.preventDefault(),
9568
+ sideOffset: 4,
9569
+ style: { width: "var(--radix-popover-trigger-width)" },
9570
+ children: /* @__PURE__ */ u("div", {
9571
+ className: "autocomplete-listbox",
9572
+ id: "autocompleteListbox",
9573
+ role: "listbox",
9574
+ children: filtered.map((suggestion, index) => {
9575
+ const active = index === activeIndex;
9576
+ return /* @__PURE__ */ u("div", {
9577
+ "aria-selected": active,
9578
+ className: active ? "autocomplete-option active" : "autocomplete-option",
9579
+ id: `autocomplete-option-${index}`,
9580
+ onMouseDown: (event) => {
9581
+ event.preventDefault();
9582
+ commit(suggestion);
9583
+ },
9584
+ onMouseEnter: () => setActiveIndex(index),
9585
+ role: "option",
9586
+ tabIndex: -1,
9587
+ children: suggestion
9588
+ }, suggestion);
9589
+ })
9590
+ })
9591
+ }) })]
9592
+ });
9593
+ });
9594
+ //#endregion
8719
9595
  //#region src/components/primitives/dialog-close-button.tsx
8720
9596
  function DialogCloseButton({ ariaLabel, className = "modal-close-button", onClick, label = "Close" }) {
8721
9597
  return /* @__PURE__ */ u("button", {
@@ -8752,7 +9628,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8752
9628
  type: "button",
8753
9629
  role: "radio",
8754
9630
  "aria-checked": checked,
8755
- "data-state": getState$1(checked),
9631
+ "data-state": getState(checked),
8756
9632
  "data-disabled": disabled ? "" : void 0,
8757
9633
  disabled,
8758
9634
  value,
@@ -8786,7 +9662,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8786
9662
  return /* @__PURE__ */ u(Presence, {
8787
9663
  present: forceMount || context.checked,
8788
9664
  children: /* @__PURE__ */ u(Primitive.span, {
8789
- "data-state": getState$1(context.checked),
9665
+ "data-state": getState(context.checked),
8790
9666
  "data-disabled": context.disabled ? "" : void 0,
8791
9667
  ...indicatorProps,
8792
9668
  ref: forwardedRef
@@ -8833,7 +9709,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
8833
9709
  });
8834
9710
  });
8835
9711
  RadioBubbleInput.displayName = BUBBLE_INPUT_NAME;
8836
- function getState$1(checked) {
9712
+ function getState(checked) {
8837
9713
  return checked ? "checked" : "unchecked";
8838
9714
  }
8839
9715
  var ARROW_KEYS = [
@@ -9149,7 +10025,20 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9149
10025
  }) : null,
9150
10026
  request.kind === "input" ? /* @__PURE__ */ u("div", {
9151
10027
  className: "field",
9152
- children: [/* @__PURE__ */ u(TextInput, {
10028
+ children: [request.suggestions?.length ? /* @__PURE__ */ u(AutocompleteInput, {
10029
+ "aria-describedby": errorText ? `${descriptionId} ${inputErrorId}` : descriptionId,
10030
+ autoFocus: true,
10031
+ className: errorText ? "sync-dialog-input sync-field-error" : "sync-dialog-input",
10032
+ "data-sync-primary-action": "true",
10033
+ onSubmit: submit,
10034
+ onValueChange: (value) => {
10035
+ setInputValue(value);
10036
+ if (errorText) setErrorText(null);
10037
+ },
10038
+ placeholder: request.placeholder,
10039
+ suggestions: request.suggestions,
10040
+ value: inputValue
10041
+ }) : /* @__PURE__ */ u(TextInput, {
9153
10042
  "aria-describedby": errorText ? `${descriptionId} ${inputErrorId}` : descriptionId,
9154
10043
  autoFocus: true,
9155
10044
  className: errorText ? "sync-dialog-input sync-field-error" : "sync-dialog-input",
@@ -9219,6 +10108,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9219
10108
  if (nextOpen) return;
9220
10109
  resolveCurrentDialog(request?.kind === "confirm" ? false : null);
9221
10110
  };
10111
+ const handleInteractOutside = (event) => {
10112
+ const originalTarget = (event.detail?.originalEvent)?.target;
10113
+ if (originalTarget instanceof Element && originalTarget.closest(".autocomplete-popover")) event.preventDefault();
10114
+ };
9222
10115
  const handleOpenAutoFocus = (event) => {
9223
10116
  const legacyPrimary = document.querySelector("#syncDialog [data-sync-primary-action=\"true\"]");
9224
10117
  if (request?.kind === "input" && legacyPrimary) {
@@ -9237,6 +10130,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9237
10130
  ariaLabelledby: titleId,
9238
10131
  contentClassName: "modal",
9239
10132
  contentId: "syncDialog",
10133
+ onInteractOutside: handleInteractOutside,
9240
10134
  onOpenAutoFocus: handleOpenAutoFocus,
9241
10135
  onOpenChange: handleOpenChange,
9242
10136
  open,
@@ -9603,6 +10497,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9603
10497
  state.lastCoordinatorAdminDevices = [];
9604
10498
  coordinatorAdminState.deviceRenameDrafts.clear();
9605
10499
  }
10500
+ try {
10501
+ coordinatorAdminState.availableProjects = await loadProjects$1();
10502
+ } catch {
10503
+ coordinatorAdminState.availableProjects = [];
10504
+ }
9606
10505
  } else {
9607
10506
  state.lastCoordinatorAdminGroups = [];
9608
10507
  coordinatorAdminState.groupRenameDrafts.clear();
@@ -9978,7 +10877,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9978
10877
  }
9979
10878
  };
9980
10879
  }, []);
9981
- return /* @__PURE__ */ u(Root2$3, {
10880
+ return /* @__PURE__ */ u(Root2$4, {
9982
10881
  ...popperScope,
9983
10882
  children: /* @__PURE__ */ u(TooltipContextProvider, {
9984
10883
  scope: __scopeTooltip,
@@ -10010,11 +10909,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10010
10909
  });
10011
10910
  };
10012
10911
  Tooltip$1.displayName = TOOLTIP_NAME;
10013
- var TRIGGER_NAME$2 = "TooltipTrigger";
10912
+ var TRIGGER_NAME$1 = "TooltipTrigger";
10014
10913
  var TooltipTrigger = D((props, forwardedRef) => {
10015
10914
  const { __scopeTooltip, ...triggerProps } = props;
10016
- const context = useTooltipContext(TRIGGER_NAME$2, __scopeTooltip);
10017
- const providerContext = useTooltipProviderContext(TRIGGER_NAME$2, __scopeTooltip);
10915
+ const context = useTooltipContext(TRIGGER_NAME$1, __scopeTooltip);
10916
+ const providerContext = useTooltipProviderContext(TRIGGER_NAME$1, __scopeTooltip);
10018
10917
  const popperScope = usePopperScope$1(__scopeTooltip);
10019
10918
  const composedRefs = useComposedRefs(forwardedRef, A$1(null), context.onTriggerChange);
10020
10919
  const isPointerDownRef = A$1(false);
@@ -10055,7 +10954,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10055
10954
  })
10056
10955
  });
10057
10956
  });
10058
- TooltipTrigger.displayName = TRIGGER_NAME$2;
10957
+ TooltipTrigger.displayName = TRIGGER_NAME$1;
10059
10958
  var PORTAL_NAME$2 = "TooltipPortal";
10060
10959
  var [PortalProvider$1, usePortalContext$1] = createTooltipContext(PORTAL_NAME$2, { forceMount: void 0 });
10061
10960
  var TooltipPortal = (props) => {
@@ -10066,7 +10965,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10066
10965
  forceMount,
10067
10966
  children: /* @__PURE__ */ u(Presence, {
10068
10967
  present: forceMount || context.open,
10069
- children: /* @__PURE__ */ u(Portal$4, {
10968
+ children: /* @__PURE__ */ u(Portal$5, {
10070
10969
  asChild: true,
10071
10970
  container,
10072
10971
  children
@@ -10075,11 +10974,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10075
10974
  });
10076
10975
  };
10077
10976
  TooltipPortal.displayName = PORTAL_NAME$2;
10078
- var CONTENT_NAME$3 = "TooltipContent";
10977
+ var CONTENT_NAME$2 = "TooltipContent";
10079
10978
  var TooltipContent = D((props, forwardedRef) => {
10080
- const portalContext = usePortalContext$1(CONTENT_NAME$3, props.__scopeTooltip);
10979
+ const portalContext = usePortalContext$1(CONTENT_NAME$2, props.__scopeTooltip);
10081
10980
  const { forceMount = portalContext.forceMount, side = "top", ...contentProps } = props;
10082
- const context = useTooltipContext(CONTENT_NAME$3, props.__scopeTooltip);
10981
+ const context = useTooltipContext(CONTENT_NAME$2, props.__scopeTooltip);
10083
10982
  return /* @__PURE__ */ u(Presence, {
10084
10983
  present: forceMount || context.open,
10085
10984
  children: context.disableHoverableContent ? /* @__PURE__ */ u(TooltipContentImpl, {
@@ -10094,8 +10993,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10094
10993
  });
10095
10994
  });
10096
10995
  var TooltipContentHoverable = D((props, forwardedRef) => {
10097
- const context = useTooltipContext(CONTENT_NAME$3, props.__scopeTooltip);
10098
- const providerContext = useTooltipProviderContext(CONTENT_NAME$3, props.__scopeTooltip);
10996
+ const context = useTooltipContext(CONTENT_NAME$2, props.__scopeTooltip);
10997
+ const providerContext = useTooltipProviderContext(CONTENT_NAME$2, props.__scopeTooltip);
10099
10998
  const ref = A$1(null);
10100
10999
  const composedRefs = useComposedRefs(forwardedRef, ref);
10101
11000
  const [pointerGraceArea, setPointerGraceArea] = d$2(null);
@@ -10172,7 +11071,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10172
11071
  var Slottable = /* @__PURE__ */ createSlottable("TooltipContent");
10173
11072
  var TooltipContentImpl = D((props, forwardedRef) => {
10174
11073
  const { __scopeTooltip, children, "aria-label": ariaLabel, onEscapeKeyDown, onPointerDownOutside, ...contentProps } = props;
10175
- const context = useTooltipContext(CONTENT_NAME$3, __scopeTooltip);
11074
+ const context = useTooltipContext(CONTENT_NAME$2, __scopeTooltip);
10176
11075
  const popperScope = usePopperScope$1(__scopeTooltip);
10177
11076
  const { onClose } = context;
10178
11077
  y$2(() => {
@@ -10195,7 +11094,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10195
11094
  onPointerDownOutside,
10196
11095
  onFocusOutside: (event) => event.preventDefault(),
10197
11096
  onDismiss: onClose,
10198
- children: /* @__PURE__ */ u(Content$2, {
11097
+ children: /* @__PURE__ */ u(Content$1, {
10199
11098
  "data-state": context.stateAttribute,
10200
11099
  ...popperScope,
10201
11100
  ...contentProps,
@@ -10220,7 +11119,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10220
11119
  })
10221
11120
  });
10222
11121
  });
10223
- TooltipContent.displayName = CONTENT_NAME$3;
11122
+ TooltipContent.displayName = CONTENT_NAME$2;
10224
11123
  var ARROW_NAME$2 = "TooltipArrow";
10225
11124
  var TooltipArrow = D((props, forwardedRef) => {
10226
11125
  const { __scopeTooltip, ...arrowProps } = props;
@@ -10364,7 +11263,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10364
11263
  }
10365
11264
  var Provider = TooltipProvider$1;
10366
11265
  var Root3$1 = Tooltip$1;
10367
- var Trigger$2 = TooltipTrigger;
11266
+ var Trigger$1 = TooltipTrigger;
10368
11267
  var Portal$1 = TooltipPortal;
10369
11268
  var Content2$2 = TooltipContent;
10370
11269
  var Arrow2$1 = TooltipArrow;
@@ -10397,7 +11296,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10397
11296
  */
10398
11297
  function Tooltip({ children, label, side = "top", align = "center", sideOffset = 6, asChild = true, disabled = false }) {
10399
11298
  if (disabled) return /* @__PURE__ */ u(k$3, { children });
10400
- return /* @__PURE__ */ u(Root3$1, { children: [/* @__PURE__ */ u(Trigger$2, {
11299
+ return /* @__PURE__ */ u(Root3$1, { children: [/* @__PURE__ */ u(Trigger$1, {
10401
11300
  asChild,
10402
11301
  children
10403
11302
  }), /* @__PURE__ */ u(Portal$1, { children: /* @__PURE__ */ u(Content2$2, {
@@ -10942,7 +11841,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10942
11841
  document.removeEventListener("pointermove", handlePointer, { capture: true });
10943
11842
  };
10944
11843
  }, []);
10945
- return /* @__PURE__ */ u(Root2$3, {
11844
+ return /* @__PURE__ */ u(Root2$4, {
10946
11845
  ...popperScope,
10947
11846
  children: /* @__PURE__ */ u(MenuProvider, {
10948
11847
  scope: __scopeMenu,
@@ -10982,7 +11881,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10982
11881
  forceMount,
10983
11882
  children: /* @__PURE__ */ u(Presence, {
10984
11883
  present: forceMount || context.open,
10985
- children: /* @__PURE__ */ u(Portal$4, {
11884
+ children: /* @__PURE__ */ u(Portal$5, {
10986
11885
  asChild: true,
10987
11886
  container,
10988
11887
  children
@@ -10991,13 +11890,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10991
11890
  });
10992
11891
  };
10993
11892
  MenuPortal.displayName = PORTAL_NAME$1;
10994
- var CONTENT_NAME$2 = "MenuContent";
10995
- var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME$2);
11893
+ var CONTENT_NAME$1 = "MenuContent";
11894
+ var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME$1);
10996
11895
  var MenuContent = D((props, forwardedRef) => {
10997
- const portalContext = usePortalContext(CONTENT_NAME$2, props.__scopeMenu);
11896
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
10998
11897
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
10999
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
11000
- const rootContext = useMenuRootContext(CONTENT_NAME$2, props.__scopeMenu);
11898
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
11899
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
11001
11900
  return /* @__PURE__ */ u(Collection.Provider, {
11002
11901
  scope: props.__scopeMenu,
11003
11902
  children: /* @__PURE__ */ u(Presence, {
@@ -11016,7 +11915,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11016
11915
  });
11017
11916
  });
11018
11917
  var MenuRootContentModal = D((props, forwardedRef) => {
11019
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
11918
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
11020
11919
  const ref = A$1(null);
11021
11920
  const composedRefs = useComposedRefs(forwardedRef, ref);
11022
11921
  y$2(() => {
@@ -11034,7 +11933,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11034
11933
  });
11035
11934
  });
11036
11935
  var MenuRootContentNonModal = D((props, forwardedRef) => {
11037
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
11936
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
11038
11937
  return /* @__PURE__ */ u(MenuContentImpl, {
11039
11938
  ...props,
11040
11939
  ref: forwardedRef,
@@ -11047,8 +11946,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11047
11946
  var Slot = /* @__PURE__ */ createSlot("MenuContent.ScrollLock");
11048
11947
  var MenuContentImpl = D((props, forwardedRef) => {
11049
11948
  const { __scopeMenu, loop = false, trapFocus, onOpenAutoFocus, onCloseAutoFocus, disableOutsidePointerEvents, onEntryFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, onDismiss, disableOutsideScroll, ...contentProps } = props;
11050
- const context = useMenuContext(CONTENT_NAME$2, __scopeMenu);
11051
- const rootContext = useMenuRootContext(CONTENT_NAME$2, __scopeMenu);
11949
+ const context = useMenuContext(CONTENT_NAME$1, __scopeMenu);
11950
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, __scopeMenu);
11052
11951
  const popperScope = usePopperScope(__scopeMenu);
11053
11952
  const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
11054
11953
  const getItems = useCollection(__scopeMenu);
@@ -11135,7 +12034,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11135
12034
  if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
11136
12035
  }),
11137
12036
  preventScrollOnEntryFocus: true,
11138
- children: /* @__PURE__ */ u(Content$2, {
12037
+ children: /* @__PURE__ */ u(Content$1, {
11139
12038
  role: "menu",
11140
12039
  "aria-orientation": "vertical",
11141
12040
  "data-state": getOpenState(context.open),
@@ -11185,7 +12084,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11185
12084
  })
11186
12085
  });
11187
12086
  });
11188
- MenuContent.displayName = CONTENT_NAME$2;
12087
+ MenuContent.displayName = CONTENT_NAME$1;
11189
12088
  var GROUP_NAME$1 = "MenuGroup";
11190
12089
  var MenuGroup = D((props, forwardedRef) => {
11191
12090
  const { __scopeMenu, ...groupProps } = props;
@@ -11395,7 +12294,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11395
12294
  if (parentMenuContext.open === false) handleOpenChange(false);
11396
12295
  return () => handleOpenChange(false);
11397
12296
  }, [parentMenuContext.open, handleOpenChange]);
11398
- return /* @__PURE__ */ u(Root2$3, {
12297
+ return /* @__PURE__ */ u(Root2$4, {
11399
12298
  ...popperScope,
11400
12299
  children: /* @__PURE__ */ u(MenuProvider, {
11401
12300
  scope: __scopeMenu,
@@ -11521,10 +12420,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11521
12420
  MenuSubTrigger.displayName = SUB_TRIGGER_NAME$1;
11522
12421
  var SUB_CONTENT_NAME$1 = "MenuSubContent";
11523
12422
  var MenuSubContent = D((props, forwardedRef) => {
11524
- const portalContext = usePortalContext(CONTENT_NAME$2, props.__scopeMenu);
12423
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
11525
12424
  const { forceMount = portalContext.forceMount, ...subContentProps } = props;
11526
- const context = useMenuContext(CONTENT_NAME$2, props.__scopeMenu);
11527
- const rootContext = useMenuRootContext(CONTENT_NAME$2, props.__scopeMenu);
12425
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
12426
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
11528
12427
  const subContext = useMenuSubContext(SUB_CONTENT_NAME$1, props.__scopeMenu);
11529
12428
  const ref = A$1(null);
11530
12429
  const composedRefs = useComposedRefs(forwardedRef, ref);
@@ -11674,10 +12573,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11674
12573
  });
11675
12574
  };
11676
12575
  DropdownMenu.displayName = DROPDOWN_MENU_NAME;
11677
- var TRIGGER_NAME$1 = "DropdownMenuTrigger";
12576
+ var TRIGGER_NAME = "DropdownMenuTrigger";
11678
12577
  var DropdownMenuTrigger = D((props, forwardedRef) => {
11679
12578
  const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
11680
- const context = useDropdownMenuContext(TRIGGER_NAME$1, __scopeDropdownMenu);
12579
+ const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
11681
12580
  return /* @__PURE__ */ u(Anchor2, {
11682
12581
  asChild: true,
11683
12582
  ...useMenuScope(__scopeDropdownMenu),
@@ -11711,7 +12610,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11711
12610
  })
11712
12611
  });
11713
12612
  });
11714
- DropdownMenuTrigger.displayName = TRIGGER_NAME$1;
12613
+ DropdownMenuTrigger.displayName = TRIGGER_NAME;
11715
12614
  var PORTAL_NAME = "DropdownMenuPortal";
11716
12615
  var DropdownMenuPortal = (props) => {
11717
12616
  const { __scopeDropdownMenu, ...portalProps } = props;
@@ -11721,10 +12620,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11721
12620
  });
11722
12621
  };
11723
12622
  DropdownMenuPortal.displayName = PORTAL_NAME;
11724
- var CONTENT_NAME$1 = "DropdownMenuContent";
12623
+ var CONTENT_NAME = "DropdownMenuContent";
11725
12624
  var DropdownMenuContent = D((props, forwardedRef) => {
11726
12625
  const { __scopeDropdownMenu, ...contentProps } = props;
11727
- const context = useDropdownMenuContext(CONTENT_NAME$1, __scopeDropdownMenu);
12626
+ const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
11728
12627
  const menuScope = useMenuScope(__scopeDropdownMenu);
11729
12628
  const hasInteractedOutsideRef = A$1(false);
11730
12629
  return /* @__PURE__ */ u(Content2$1, {
@@ -11754,7 +12653,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11754
12653
  }
11755
12654
  });
11756
12655
  });
11757
- DropdownMenuContent.displayName = CONTENT_NAME$1;
12656
+ DropdownMenuContent.displayName = CONTENT_NAME;
11758
12657
  var GROUP_NAME = "DropdownMenuGroup";
11759
12658
  var DropdownMenuGroup = D((props, forwardedRef) => {
11760
12659
  const { __scopeDropdownMenu, ...groupProps } = props;
@@ -11874,14 +12773,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11874
12773
  });
11875
12774
  DropdownMenuSubContent.displayName = SUB_CONTENT_NAME;
11876
12775
  var Root2 = DropdownMenu;
11877
- var Trigger$1 = DropdownMenuTrigger;
12776
+ var Trigger = DropdownMenuTrigger;
11878
12777
  var Portal2 = DropdownMenuPortal;
11879
12778
  var Content2 = DropdownMenuContent;
11880
12779
  var Item2 = DropdownMenuItem;
11881
12780
  //#endregion
11882
12781
  //#region src/tabs/feed/components/FeedItemMenu.tsx
11883
- function FeedItemMenu({ disabled, onForget, title }) {
11884
- return _$3(Root2, null, _$3(Trigger$1, { asChild: true }, _$3("button", {
12782
+ function FeedItemMenu({ assignProjectDisabled, disabled, onAssignProject, onForget, title }) {
12783
+ return _$3(Root2, null, _$3(Trigger, { asChild: true }, _$3("button", {
11885
12784
  "aria-label": `Actions for ${title}`,
11886
12785
  className: "feed-menu-trigger",
11887
12786
  type: "button"
@@ -11891,6 +12790,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11891
12790
  side: "bottom",
11892
12791
  sideOffset: 4
11893
12792
  }, _$3(Item2, {
12793
+ className: "feed-menu-item",
12794
+ disabled: assignProjectDisabled,
12795
+ onSelect: () => onAssignProject()
12796
+ }, assignProjectDisabled ? "Moving…" : "Assign to project…"), _$3(Item2, {
11894
12797
  className: "feed-menu-item danger",
11895
12798
  disabled,
11896
12799
  onSelect: () => onForget()
@@ -11967,6 +12870,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11967
12870
  const [selectedVisibility, setSelectedVisibility] = d$2(visibility === "shared" ? "shared" : "private");
11968
12871
  const [savingVisibility, setSavingVisibility] = d$2(false);
11969
12872
  const [deletingMemory, setDeletingMemory] = d$2(false);
12873
+ const [movingProject, setMovingProject] = d$2(false);
11970
12874
  const summarySections = summaryObj ? renderSummarySections(summaryObj) : [];
11971
12875
  y$2(() => {
11972
12876
  if (!observationData) return;
@@ -12027,6 +12931,47 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
12027
12931
  setSavingVisibility(false);
12028
12932
  }
12029
12933
  }
12934
+ async function moveProject() {
12935
+ const currentProject = String(item.project || "").trim();
12936
+ const initialValue = currentProject;
12937
+ const titleText = String(displayTitle || "this memory").trim();
12938
+ const truncatedTitle = titleText.length > 80 ? `${titleText.slice(0, 79).trimEnd()}…` : titleText;
12939
+ const description = currentProject ? `Move "${truncatedTitle}" from "${currentProject}" to another project. Pick an existing project or type a new name. Every memory in the same session will be reassigned together.` : `Assign a project to "${truncatedTitle}". Pick an existing project or type a new name. Every memory in the same session will be reassigned together.`;
12940
+ let suggestions = [];
12941
+ try {
12942
+ suggestions = (await loadProjects$1()).filter((p) => p && p !== currentProject);
12943
+ } catch {}
12944
+ const nextProject = await openSyncInputDialog({
12945
+ title: "Assign to project",
12946
+ description,
12947
+ initialValue,
12948
+ placeholder: "Pick one or type a new project name",
12949
+ suggestions,
12950
+ confirmLabel: "Move",
12951
+ cancelLabel: "Cancel",
12952
+ validate: (value) => {
12953
+ const trimmed = value.trim();
12954
+ if (!trimmed) return "Enter a project name.";
12955
+ if (trimmed === currentProject) return "Already assigned to this project.";
12956
+ return null;
12957
+ }
12958
+ });
12959
+ if (nextProject == null) return;
12960
+ const target = nextProject.trim();
12961
+ if (!target || target === currentProject) return;
12962
+ setMovingProject(true);
12963
+ try {
12964
+ const result = await moveMemoryProject(memoryId, target);
12965
+ const count = Number(result.moved_memory_count || 1);
12966
+ showGlobalNotice(count > 1 ? `Moved ${count} memories from this session to "${result.project}".` : `Moved to "${result.project}".`);
12967
+ await onReload();
12968
+ onViewRefresh();
12969
+ } catch (error) {
12970
+ showGlobalNotice(error instanceof Error ? error.message : "Failed to move memory.", "warning");
12971
+ } finally {
12972
+ setMovingProject(false);
12973
+ }
12974
+ }
12030
12975
  async function forgetMemory$1() {
12031
12976
  const titleText = String(displayTitle || "this memory").trim();
12032
12977
  if (!await openSyncConfirmDialog({
@@ -12072,7 +13017,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
12072
13017
  label: formatDate(createdAtRaw),
12073
13018
  side: "left"
12074
13019
  }, _$3("div", { className: "small feed-age" }, relative)), Boolean(item.owned_by_self) && memoryId > 0 ? _$3(FeedItemMenu, {
13020
+ assignProjectDisabled: movingProject,
12075
13021
  disabled: deletingMemory,
13022
+ onAssignProject: () => void moveProject(),
12076
13023
  onForget: () => void forgetMemory$1(),
12077
13024
  title: String(displayTitle || "memory")
12078
13025
  }) : null)), _$3("div", { className: "feed-provenance" }, _$3(ProvenanceChip, {
@@ -12678,15 +13625,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
12678
13625
  const pct = total && total > 0 ? ` (${Math.round(100 * current / total)}%)` : "";
12679
13626
  const progress = total && total > 0 ? `${current.toLocaleString()}/${total.toLocaleString()} ${unit}${pct}` : `${current.toLocaleString()} ${unit}`;
12680
13627
  const isFailed = job.status === "failed";
12681
- const detail = isFailed ? String(job.error || "unknown error").trim() : void 0;
13628
+ const isCompleted = job.status === "completed";
13629
+ const value = isFailed ? "Failed" : isCompleted ? "Complete" : progress;
13630
+ const detail = isFailed ? String(job.error || "unknown error").trim() : isCompleted ? progress : void 0;
12682
13631
  return buildHealthCard({
12683
13632
  key: String(job.kind || job.title || "background-maintenance"),
12684
13633
  label: String(job.title || job.kind || "Background maintenance"),
12685
- value: isFailed ? "Failed" : progress,
13634
+ value,
12686
13635
  detail,
12687
- icon: isFailed ? "alert-triangle" : "loader",
13636
+ icon: isFailed ? "alert-triangle" : isCompleted ? "check-circle" : "loader",
12688
13637
  className: isFailed ? "status-attention" : void 0,
12689
- title: isFailed ? `Error: ${job.error || "unknown"}` : `${String(job.title || "Maintenance")} in progress`
13638
+ title: isFailed ? `Error: ${job.error || "unknown"}` : isCompleted ? `${String(job.title || "Maintenance")} finished` : `${String(job.title || "Maintenance")} in progress`
12690
13639
  });
12691
13640
  });
12692
13641
  renderHealthCards(healthGrid, [
@@ -12990,7 +13939,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
12990
13939
  observerSimpleTemperature: "observer_simple_temperature",
12991
13940
  observerRichModel: "observer_rich_model",
12992
13941
  observerRichTemperature: "observer_rich_temperature",
12993
- observerRichOpenAIUseResponses: "observer_rich_openai_use_responses",
12994
13942
  observerRichReasoningEffort: "observer_rich_reasoning_effort",
12995
13943
  observerRichReasoningSummary: "observer_rich_reasoning_summary",
12996
13944
  observerRichMaxOutputTokens: "observer_rich_max_output_tokens",
@@ -13032,7 +13980,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13032
13980
  observerSimpleTemperature: "",
13033
13981
  observerRichModel: "",
13034
13982
  observerRichTemperature: "",
13035
- observerRichOpenAIUseResponses: false,
13036
13983
  observerRichReasoningEffort: "",
13037
13984
  observerRichReasoningSummary: "",
13038
13985
  observerRichMaxOutputTokens: "",
@@ -13208,8 +14155,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13208
14155
  }
13209
14156
  case "sync_enabled":
13210
14157
  case "sync_mdns":
13211
- case "observer_tier_routing_enabled":
13212
- case "observer_rich_openai_use_responses": return asBooleanValue(cfg[key]);
14158
+ case "observer_tier_routing_enabled": return asBooleanValue(cfg[key]);
13213
14159
  default: return hasOwn(cfg, key) ? cfg[key] : "";
13214
14160
  }
13215
14161
  }
@@ -13280,7 +14226,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13280
14226
  observer_simple_temperature: simpleTemperature,
13281
14227
  observer_rich_model: normalizeTextValue(values.observerRichModel),
13282
14228
  observer_rich_temperature: richTemperature,
13283
- observer_rich_openai_use_responses: values.observerRichOpenAIUseResponses,
13284
14229
  observer_rich_reasoning_effort: normalizeTextValue(values.observerRichReasoningEffort),
13285
14230
  observer_rich_reasoning_summary: normalizeTextValue(values.observerRichReasoningSummary),
13286
14231
  observer_rich_max_output_tokens: richMaxOutputTokens,
@@ -13326,7 +14271,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13326
14271
  observerSimpleTemperature: asInputString(effectiveOrConfigured(config, effective, "observer_simple_temperature")),
13327
14272
  observerRichModel: asInputString(effectiveOrConfigured(config, effective, "observer_rich_model")),
13328
14273
  observerRichTemperature: asInputString(effectiveOrConfigured(config, effective, "observer_rich_temperature")),
13329
- observerRichOpenAIUseResponses: asBooleanValue(effectiveOrConfigured(config, effective, "observer_rich_openai_use_responses")),
13330
14274
  observerRichReasoningEffort: asInputString(effectiveOrConfigured(config, effective, "observer_rich_reasoning_effort")),
13331
14275
  observerRichReasoningSummary: asInputString(effectiveOrConfigured(config, effective, "observer_rich_reasoning_summary")),
13332
14276
  observerRichMaxOutputTokens: asInputString(effectiveOrConfigured(config, effective, "observer_rich_max_output_tokens")),
@@ -13364,17 +14308,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13364
14308
  ].some((key) => hasOwn(envOverrides, key)) ? "Env override" : inferred.source}: ${inferred.model}`;
13365
14309
  }
13366
14310
  function getTieredRoutingHelperText$1(values) {
13367
- if (!values.observerTierRoutingEnabled) return "Off: codemem uses the base observer settings from the Connection tab for all batches.";
13368
- return "On: codemem can route simpler batches to a lighter model and richer batches to a higher-quality configuration.";
14311
+ if (!values.observerTierRoutingEnabled) return "Off: codemem uses the base observer settings from the Connection tab for all batches. Explicit user settings always win over built-in routing defaults.";
14312
+ return "On: codemem routes simpler batches to a lighter model and richer batches to a higher-quality configuration. Rich-tier OpenAI requests default to the Responses transport, and Claude sidecar runtimes route both tiers through the local Claude CLI.";
13369
14313
  }
13370
14314
  function getObserverModelLabel$1(values) {
13371
14315
  return values.observerTierRoutingEnabled ? "Base model fallback" : "Model";
13372
14316
  }
13373
14317
  function getObserverModelTooltip$1(values) {
13374
- return values.observerTierRoutingEnabled ? "Tiered routing is enabled, so Processing controls the simple/rich models. This base model is only a fallback." : "Leave blank to use a recommended model for your selected mode/provider.";
14318
+ return values.observerTierRoutingEnabled ? "Tiered routing is enabled, so Processing controls the simple/rich models. This base model is only a fallback, and explicit settings override built-in defaults." : "Leave blank to use a recommended model for your selected mode/provider.";
13375
14319
  }
13376
14320
  function getObserverModelDescription$1(values) {
13377
- return values.observerTierRoutingEnabled ? "Tiered routing is active. Use this only as a fallback while the Processing tab owns simple/rich model selection." : "Default: `gpt-5.1-codex-mini` for Direct API; `claude-4.5-haiku` for Local Claude session.";
14321
+ return values.observerTierRoutingEnabled ? "Tiered routing is active. Use this only as a fallback while the Processing tab owns simple/rich model selection and explicit tier settings override built-in defaults." : "Default: `gpt-5.1-codex-mini` for Direct API; `claude-4.5-haiku` for Local Claude session.";
13378
14322
  }
13379
14323
  function hiddenUnlessAdvanced$1(showAdvanced) {
13380
14324
  return !showAdvanced;
@@ -14352,7 +15296,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14352
15296
  }),
14353
15297
  /* @__PURE__ */ u(SettingsHint, {
14354
15298
  hidden: !showTieredRouting || hiddenUnlessAdvanced(),
14355
- children: "These advanced routing values are only useful when you are tuning model cost, latency, or output quality for a known workload."
15299
+ children: "These advanced routing values are only useful when you are tuning model cost, latency, or output quality for a known workload. If a selected path cannot honor the requested tier settings, codemem falls back visibly instead of silently pretending it worked."
14356
15300
  }),
14357
15301
  /* @__PURE__ */ u(Field, {
14358
15302
  hidden: !showTieredRouting,
@@ -14365,7 +15309,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14365
15309
  }), /* @__PURE__ */ u("button", {
14366
15310
  "aria-label": "About simple tier model",
14367
15311
  className: "help-icon",
14368
- "data-tooltip": "Used for lighter replay batches. Leave blank to keep codemem's routing defaults or base observer fallback.",
15312
+ "data-tooltip": "Used for lighter replay batches. Leave blank to keep codemem's routing defaults. Explicit simple-tier values override the built-in defaults.",
14369
15313
  type: "button",
14370
15314
  children: "?"
14371
15315
  })]
@@ -14393,7 +15337,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14393
15337
  }), /* @__PURE__ */ u("button", {
14394
15338
  "aria-label": "About rich tier model",
14395
15339
  className: "help-icon",
14396
- "data-tooltip": "Used for larger or more complex replay batches. Leave blank to keep codemem's rich-tier defaults.",
15340
+ "data-tooltip": "Used for larger or more complex replay batches. Leave blank to keep codemem's rich-tier defaults. Explicit rich-tier values override the built-in defaults.",
14397
15341
  type: "button",
14398
15342
  children: "?"
14399
15343
  })]
@@ -14410,14 +15354,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14410
15354
  })
14411
15355
  ]
14412
15356
  }),
14413
- /* @__PURE__ */ u(SettingsSwitchRow, {
14414
- checked: values.observerRichOpenAIUseResponses,
14415
- className: "field",
14416
- hidden: !showTieredRouting,
14417
- id: "observerRichOpenAIUseResponses",
14418
- label: "Use OpenAI Responses API for rich tier",
14419
- onCheckedChange: onSwitchInput("observerRichOpenAIUseResponses")
14420
- }),
14421
15357
  /* @__PURE__ */ u(Field, {
14422
15358
  className: "field settings-advanced",
14423
15359
  hidden: !showTieredRouting || hiddenUnlessAdvanced(),
@@ -15067,22 +16003,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15067
16003
  function isRecord(value) {
15068
16004
  return typeof value === "object" && value !== null;
15069
16005
  }
16006
+ function noPairingCommand(payloadText, hintText) {
16007
+ state.pairingCommandRaw = "";
16008
+ return {
16009
+ payloadText,
16010
+ hintText
16011
+ };
16012
+ }
15070
16013
  function pairingView(payload) {
15071
- if (!isRecord(payload)) {
15072
- state.pairingCommandRaw = "";
15073
- return {
15074
- payloadText: "Pairing not available",
15075
- hintText: "Enable sync and retry."
15076
- };
15077
- }
16014
+ if (!isRecord(payload)) return noPairingCommand("Pairing not available", "Enable sync and retry.");
15078
16015
  const pairingPayload = payload;
15079
- if (pairingPayload.redacted) {
15080
- state.pairingCommandRaw = "";
15081
- return {
15082
- payloadText: "Pairing payload hidden",
15083
- hintText: "Diagnostics are required to view the pairing payload."
15084
- };
15085
- }
15086
16016
  const safePayload = {
15087
16017
  ...pairingPayload,
15088
16018
  addresses: Array.isArray(pairingPayload.addresses) ? pairingPayload.addresses : []
@@ -15196,122 +16126,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15196
16126
  if (hintMount) renderIntoSyncMount(hintMount, /* @__PURE__ */ u(PairingText, { text: view.hintText }));
15197
16127
  }
15198
16128
  //#endregion
15199
- //#region ../../node_modules/.pnpm/@radix-ui+react-collapsible@1.1.12_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@radix-ui/react-collapsible/dist/index.mjs
15200
- var COLLAPSIBLE_NAME = "Collapsible";
15201
- var [createCollapsibleContext, createCollapsibleScope] = createContextScope(COLLAPSIBLE_NAME);
15202
- var [CollapsibleProvider, useCollapsibleContext] = createCollapsibleContext(COLLAPSIBLE_NAME);
15203
- var Collapsible = D((props, forwardedRef) => {
15204
- const { __scopeCollapsible, open: openProp, defaultOpen, disabled, onOpenChange, ...collapsibleProps } = props;
15205
- const [open, setOpen] = useControllableState({
15206
- prop: openProp,
15207
- defaultProp: defaultOpen ?? false,
15208
- onChange: onOpenChange,
15209
- caller: COLLAPSIBLE_NAME
15210
- });
15211
- return /* @__PURE__ */ u(CollapsibleProvider, {
15212
- scope: __scopeCollapsible,
15213
- disabled,
15214
- contentId: useId(),
15215
- open,
15216
- onOpenToggle: q$2(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
15217
- children: /* @__PURE__ */ u(Primitive.div, {
15218
- "data-state": getState(open),
15219
- "data-disabled": disabled ? "" : void 0,
15220
- ...collapsibleProps,
15221
- ref: forwardedRef
15222
- })
15223
- });
15224
- });
15225
- Collapsible.displayName = COLLAPSIBLE_NAME;
15226
- var TRIGGER_NAME = "CollapsibleTrigger";
15227
- var CollapsibleTrigger = D((props, forwardedRef) => {
15228
- const { __scopeCollapsible, ...triggerProps } = props;
15229
- const context = useCollapsibleContext(TRIGGER_NAME, __scopeCollapsible);
15230
- return /* @__PURE__ */ u(Primitive.button, {
15231
- type: "button",
15232
- "aria-controls": context.contentId,
15233
- "aria-expanded": context.open || false,
15234
- "data-state": getState(context.open),
15235
- "data-disabled": context.disabled ? "" : void 0,
15236
- disabled: context.disabled,
15237
- ...triggerProps,
15238
- ref: forwardedRef,
15239
- onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
15240
- });
15241
- });
15242
- CollapsibleTrigger.displayName = TRIGGER_NAME;
15243
- var CONTENT_NAME = "CollapsibleContent";
15244
- var CollapsibleContent = D((props, forwardedRef) => {
15245
- const { forceMount, ...contentProps } = props;
15246
- const context = useCollapsibleContext(CONTENT_NAME, props.__scopeCollapsible);
15247
- return /* @__PURE__ */ u(Presence, {
15248
- present: forceMount || context.open,
15249
- children: ({ present }) => /* @__PURE__ */ u(CollapsibleContentImpl, {
15250
- ...contentProps,
15251
- ref: forwardedRef,
15252
- present
15253
- })
15254
- });
15255
- });
15256
- CollapsibleContent.displayName = CONTENT_NAME;
15257
- var CollapsibleContentImpl = D((props, forwardedRef) => {
15258
- const { __scopeCollapsible, present, children, ...contentProps } = props;
15259
- const context = useCollapsibleContext(CONTENT_NAME, __scopeCollapsible);
15260
- const [isPresent, setIsPresent] = d$2(present);
15261
- const ref = A$1(null);
15262
- const composedRefs = useComposedRefs(forwardedRef, ref);
15263
- const heightRef = A$1(0);
15264
- const height = heightRef.current;
15265
- const widthRef = A$1(0);
15266
- const width = widthRef.current;
15267
- const isOpen = context.open || isPresent;
15268
- const isMountAnimationPreventedRef = A$1(isOpen);
15269
- const originalStylesRef = A$1(void 0);
15270
- y$2(() => {
15271
- const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);
15272
- return () => cancelAnimationFrame(rAF);
15273
- }, []);
15274
- useLayoutEffect2(() => {
15275
- const node = ref.current;
15276
- if (node) {
15277
- originalStylesRef.current = originalStylesRef.current || {
15278
- transitionDuration: node.style.transitionDuration,
15279
- animationName: node.style.animationName
15280
- };
15281
- node.style.transitionDuration = "0s";
15282
- node.style.animationName = "none";
15283
- const rect = node.getBoundingClientRect();
15284
- heightRef.current = rect.height;
15285
- widthRef.current = rect.width;
15286
- if (!isMountAnimationPreventedRef.current) {
15287
- node.style.transitionDuration = originalStylesRef.current.transitionDuration;
15288
- node.style.animationName = originalStylesRef.current.animationName;
15289
- }
15290
- setIsPresent(present);
15291
- }
15292
- }, [context.open, present]);
15293
- return /* @__PURE__ */ u(Primitive.div, {
15294
- "data-state": getState(context.open),
15295
- "data-disabled": context.disabled ? "" : void 0,
15296
- id: context.contentId,
15297
- hidden: !isOpen,
15298
- ...contentProps,
15299
- ref: composedRefs,
15300
- style: {
15301
- [`--radix-collapsible-content-height`]: height ? `${height}px` : void 0,
15302
- [`--radix-collapsible-content-width`]: width ? `${width}px` : void 0,
15303
- ...props.style
15304
- },
15305
- children: isOpen && children
15306
- });
15307
- });
15308
- function getState(open) {
15309
- return open ? "open" : "closed";
15310
- }
15311
- var Root = Collapsible;
15312
- var Trigger = CollapsibleTrigger;
15313
- var Content = CollapsibleContent;
15314
- //#endregion
15315
16129
  //#region src/tabs/sync/components/sync-disclosure.tsx
15316
16130
  function SyncDisclosure({ open, onOpenChange, triggerId, triggerClassName, closedLabel, openLabel, contentId, contentClassName, contentHost = null, children }) {
15317
16131
  const triggerRef = A$1(null);
@@ -15339,7 +16153,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15339
16153
  (contentRef.current?.querySelector("button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])"))?.focus();
15340
16154
  });
15341
16155
  }, [open]);
15342
- const content = /* @__PURE__ */ u(Content, {
16156
+ const content = /* @__PURE__ */ u(Content$2, {
15343
16157
  forceMount: true,
15344
16158
  asChild: true,
15345
16159
  children: /* @__PURE__ */ u("div", {
@@ -15350,10 +16164,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15350
16164
  children
15351
16165
  })
15352
16166
  });
15353
- return /* @__PURE__ */ u(Root, {
16167
+ return /* @__PURE__ */ u(Root$3, {
15354
16168
  open,
15355
16169
  onOpenChange,
15356
- children: [/* @__PURE__ */ u(Trigger, {
16170
+ children: [/* @__PURE__ */ u(Trigger$4, {
15357
16171
  asChild: true,
15358
16172
  children: /* @__PURE__ */ u("button", {
15359
16173
  ref: triggerRef,
@@ -15464,8 +16278,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15464
16278
  onOpenChange,
15465
16279
  triggerId: "syncPairingToggle",
15466
16280
  triggerClassName: "settings-button",
15467
- closedLabel: "Show pairing",
15468
- openLabel: "Hide pairing",
16281
+ closedLabel: "Show pairing command",
16282
+ openLabel: "Hide pairing command",
15469
16283
  contentId: "syncPairing",
15470
16284
  contentClassName: "pairing-card",
15471
16285
  contentHost,
@@ -15826,12 +16640,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15826
16640
  title: trustSummary?.state === "needs-repairing" ? `${name} needs re-pairing` : `${name} needs review`,
15827
16641
  summary: detail
15828
16642
  }));
15829
- } else if (device.peer && peerStatus === "offline") attentionItems.push(createRepairItem({
15830
- id: device.deviceId,
15831
- name,
15832
- title: `${name} is offline`,
15833
- summary: "This device is offline or unreachable right now. Retry later, or review the local record if it should have been available."
15834
- }));
16643
+ }
15835
16644
  if (device.peer && trustSummary?.state === "trusted-by-you") attentionItems.push(createReviewItem({
15836
16645
  id: device.deviceId,
15837
16646
  key: "other-device-trust",
@@ -15897,6 +16706,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15897
16706
  function setTeamInvitePanelOpen(v) {
15898
16707
  teamInvitePanelOpen = v;
15899
16708
  }
16709
+ var teamJoinPanelOpen = false;
16710
+ function setTeamJoinPanelOpen(v) {
16711
+ teamJoinPanelOpen = v;
16712
+ }
15900
16713
  var openPeerScopeEditors = /* @__PURE__ */ new Set();
15901
16714
  var pendingPeerScopeReviewIds = /* @__PURE__ */ new Set();
15902
16715
  var freshPeerScopeReviewIds = /* @__PURE__ */ new Set();
@@ -15972,9 +16785,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15972
16785
  const unique = Array.from(new Set(addresses.filter(Boolean)));
15973
16786
  return typeof unique[0] === "string" ? unique[0] : "";
15974
16787
  }
15975
- function parseScopeList(value) {
15976
- return value.split(",").map((item) => item.trim()).filter(Boolean);
15977
- }
15978
16788
  function actorLabel(actor) {
15979
16789
  if (!actor || typeof actor !== "object") return "Unknown person";
15980
16790
  const displayName = String(actor.display_name || "").trim();
@@ -16020,53 +16830,203 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16020
16830
  if (!targetActorId || !target) return "Choose which person should keep these devices.";
16021
16831
  return `Merge into ${actorDisplayLabel(target)}. Assigned devices move now; existing memories keep their current provenance.`;
16022
16832
  }
16023
- function createChipEditor(initialValues, placeholder, emptyLabel) {
16833
+ function createChipEditor(initialValues, placeholder, emptyLabel, availableProjects = []) {
16024
16834
  let values = [...initialValues];
16025
- const container = el("div", "peer-scope-editor");
16026
- const chips = el("div", "peer-scope-chips");
16027
- const input = el("input", "peer-scope-input");
16028
- input.placeholder = placeholder;
16029
- const syncChips = () => {
16030
- chips.textContent = "";
16835
+ let query = "";
16836
+ let activeIndex = 0;
16837
+ let popoverOpen = false;
16838
+ const container = el("div", "project-scope-picker");
16839
+ const selectedList = el("ul", "project-scope-picker-selected");
16840
+ const trigger = el("button", "project-scope-picker-trigger settings-button");
16841
+ trigger.type = "button";
16842
+ const triggerLabel = el("span", null, placeholder || "Add project");
16843
+ const triggerPlus = el("span", null, "+");
16844
+ triggerPlus.setAttribute("aria-hidden", "true");
16845
+ trigger.append(triggerPlus, triggerLabel);
16846
+ trigger.setAttribute("aria-haspopup", "listbox");
16847
+ trigger.setAttribute("aria-expanded", "false");
16848
+ const popover = el("div", "project-scope-picker-popover project-scope-picker-popover--inline");
16849
+ popover.hidden = true;
16850
+ const search = el("input", "project-scope-picker-search");
16851
+ search.type = "text";
16852
+ search.placeholder = "Search or create…";
16853
+ search.setAttribute("aria-label", "Search projects");
16854
+ const results = el("div", "project-scope-picker-results");
16855
+ results.setAttribute("role", "listbox");
16856
+ popover.append(search, results);
16857
+ const knownPool = () => {
16858
+ const seen = /* @__PURE__ */ new Set();
16859
+ const out = [];
16860
+ for (const item of [...availableProjects, ...values]) {
16861
+ const trimmed = item.trim();
16862
+ if (!trimmed || seen.has(trimmed)) continue;
16863
+ seen.add(trimmed);
16864
+ out.push(trimmed);
16865
+ }
16866
+ return out.sort((a, b) => a.localeCompare(b));
16867
+ };
16868
+ const filteredRows = () => {
16869
+ const all = knownPool();
16870
+ const q = query.trim().toLowerCase();
16871
+ if (!q) return all;
16872
+ return all.filter((project) => project.toLowerCase().includes(q));
16873
+ };
16874
+ const shouldShowCreateRow = () => {
16875
+ const q = query.trim();
16876
+ if (!q) return false;
16877
+ return !knownPool().some((project) => project.toLowerCase() === q.toLowerCase());
16878
+ };
16879
+ const toggleValue = (project) => {
16880
+ if (values.includes(project)) values = values.filter((value) => value !== project);
16881
+ else values = Array.from(new Set([...values, project]));
16882
+ renderSelected();
16883
+ renderResults();
16884
+ };
16885
+ const createFromQuery = () => {
16886
+ const trimmed = query.trim();
16887
+ if (!trimmed) return;
16888
+ values = Array.from(new Set([...values, trimmed]));
16889
+ query = "";
16890
+ search.value = "";
16891
+ activeIndex = 0;
16892
+ renderSelected();
16893
+ renderResults();
16894
+ };
16895
+ const activateRow = (index) => {
16896
+ const rows = filteredRows();
16897
+ if (index < rows.length) {
16898
+ const project = rows[index];
16899
+ if (project) toggleValue(project);
16900
+ return;
16901
+ }
16902
+ if (shouldShowCreateRow()) createFromQuery();
16903
+ };
16904
+ const renderSelected = () => {
16905
+ selectedList.textContent = "";
16031
16906
  if (!values.length) {
16032
- chips.appendChild(el("span", "peer-scope-chip empty", emptyLabel));
16907
+ const note = el("li", "project-scope-picker-selected-empty", emptyLabel);
16908
+ selectedList.appendChild(note);
16033
16909
  return;
16034
16910
  }
16035
- values.forEach((value, index) => {
16036
- const chip = el("span", "peer-scope-chip");
16911
+ values.forEach((value) => {
16912
+ const chip = el("li", "project-scope-picker-selected-chip");
16037
16913
  const label = el("span", null, value);
16038
- const remove = el("button", "peer-scope-chip-remove", "x");
16914
+ const remove = el("button", "project-scope-picker-selected-remove", "×");
16039
16915
  remove.type = "button";
16040
16916
  remove.setAttribute("aria-label", `Remove ${value}`);
16041
16917
  remove.addEventListener("click", () => {
16042
- values = values.filter((_, currentIndex) => currentIndex !== index);
16043
- syncChips();
16918
+ values = values.filter((existing) => existing !== value);
16919
+ renderSelected();
16920
+ renderResults();
16044
16921
  });
16045
16922
  chip.append(label, remove);
16046
- chips.appendChild(chip);
16923
+ selectedList.appendChild(chip);
16924
+ });
16925
+ };
16926
+ const renderResults = () => {
16927
+ results.textContent = "";
16928
+ const rows = filteredRows();
16929
+ const withCreate = shouldShowCreateRow();
16930
+ const rowCount = rows.length + (withCreate ? 1 : 0);
16931
+ if (activeIndex >= rowCount) activeIndex = Math.max(0, rowCount - 1);
16932
+ if (!rows.length && !withCreate) {
16933
+ const empty = el("div", "project-scope-picker-empty-row", "No projects yet. Type a name to create one.");
16934
+ results.appendChild(empty);
16935
+ return;
16936
+ }
16937
+ rows.forEach((project, index) => {
16938
+ const selected = values.includes(project);
16939
+ const row = el("button", index === activeIndex ? "project-scope-picker-row project-scope-picker-row--active" : "project-scope-picker-row");
16940
+ row.type = "button";
16941
+ row.setAttribute("role", "option");
16942
+ row.setAttribute("aria-selected", selected ? "true" : "false");
16943
+ const check = el("span", "project-scope-picker-row-check", selected ? "✓" : "");
16944
+ check.setAttribute("aria-hidden", "true");
16945
+ const labelEl = el("span", "project-scope-picker-row-label", project);
16946
+ row.append(check, labelEl);
16947
+ row.addEventListener("click", () => {
16948
+ activeIndex = index;
16949
+ toggleValue(project);
16950
+ });
16951
+ row.addEventListener("mouseenter", () => {
16952
+ activeIndex = index;
16953
+ renderResults();
16954
+ });
16955
+ results.appendChild(row);
16047
16956
  });
16957
+ if (withCreate) {
16958
+ const index = rows.length;
16959
+ const row = el("button", index === activeIndex ? "project-scope-picker-row project-scope-picker-row--create project-scope-picker-row--active" : "project-scope-picker-row project-scope-picker-row--create");
16960
+ row.type = "button";
16961
+ row.setAttribute("role", "option");
16962
+ const check = el("span", "project-scope-picker-row-check", "+");
16963
+ check.setAttribute("aria-hidden", "true");
16964
+ const labelEl = el("span", "project-scope-picker-row-label", `Create "${query.trim()}"`);
16965
+ row.append(check, labelEl);
16966
+ row.addEventListener("click", () => createFromQuery());
16967
+ row.addEventListener("mouseenter", () => {
16968
+ activeIndex = index;
16969
+ renderResults();
16970
+ });
16971
+ results.appendChild(row);
16972
+ }
16048
16973
  };
16049
- const commitInput = () => {
16050
- const incoming = parseScopeList(input.value);
16051
- if (incoming.length) {
16052
- values = Array.from(new Set([...values, ...incoming]));
16053
- input.value = "";
16054
- syncChips();
16974
+ const setOpen = (next) => {
16975
+ popoverOpen = next;
16976
+ popover.hidden = !next;
16977
+ trigger.setAttribute("aria-expanded", next ? "true" : "false");
16978
+ if (next) {
16979
+ query = "";
16980
+ search.value = "";
16981
+ activeIndex = 0;
16982
+ renderResults();
16983
+ requestAnimationFrame(() => search.focus());
16055
16984
  }
16056
16985
  };
16057
- input.addEventListener("keydown", (event) => {
16058
- if (event.key === "Enter" || event.key === ",") {
16986
+ trigger.addEventListener("click", (event) => {
16987
+ event.stopPropagation();
16988
+ setOpen(!popoverOpen);
16989
+ });
16990
+ search.addEventListener("input", () => {
16991
+ query = search.value;
16992
+ activeIndex = 0;
16993
+ renderResults();
16994
+ });
16995
+ search.addEventListener("keydown", (event) => {
16996
+ const rowCount = filteredRows().length + (shouldShowCreateRow() ? 1 : 0);
16997
+ if (event.key === "ArrowDown") {
16998
+ event.preventDefault();
16999
+ activeIndex = Math.min(rowCount - 1, activeIndex + 1);
17000
+ renderResults();
17001
+ return;
17002
+ }
17003
+ if (event.key === "ArrowUp") {
16059
17004
  event.preventDefault();
16060
- commitInput();
17005
+ activeIndex = Math.max(0, activeIndex - 1);
17006
+ renderResults();
17007
+ return;
17008
+ }
17009
+ if (event.key === "Enter") {
17010
+ event.preventDefault();
17011
+ activateRow(activeIndex);
17012
+ return;
16061
17013
  }
16062
- if (event.key === "Backspace" && !input.value && values.length) {
16063
- values = values.slice(0, -1);
16064
- syncChips();
17014
+ if (event.key === "Escape") {
17015
+ event.preventDefault();
17016
+ setOpen(false);
16065
17017
  }
16066
17018
  });
16067
- input.addEventListener("blur", commitInput);
16068
- syncChips();
16069
- container.append(chips, input);
17019
+ const onDocumentClick = (event) => {
17020
+ if (!popoverOpen) return;
17021
+ const target = event.target;
17022
+ if (!target) return;
17023
+ if (container.contains(target)) return;
17024
+ setOpen(false);
17025
+ };
17026
+ document.addEventListener("click", onDocumentClick);
17027
+ container.append(selectedList, trigger, popover);
17028
+ renderSelected();
17029
+ renderResults();
16070
17030
  return {
16071
17031
  element: container,
16072
17032
  values: () => [...values]
@@ -16110,9 +17070,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16110
17070
  const peerLabel = String(matchedPeer?.name || "").trim() || (peerId ? peerId.slice(0, 8) : "unknown");
16111
17071
  const isError = attempt.status === "error";
16112
17072
  const detailParts = [];
16113
- if (isError && attempt.error) detailParts.push(String(attempt.error));
17073
+ const redact = isSyncRedactionEnabled();
17074
+ if (isError && attempt.error) {
17075
+ const errText = String(attempt.error);
17076
+ detailParts.push(redact ? redactIpOctets(errText) : errText);
17077
+ }
16114
17078
  if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
16115
- if (!isSyncRedactionEnabled() && attempt.address) detailParts.push(attempt.address);
17079
+ if (!redact && attempt.address) detailParts.push(attempt.address);
16116
17080
  return {
16117
17081
  status: attempt.status || "unknown",
16118
17082
  peerLabel,
@@ -16166,7 +17130,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16166
17130
  const peerCount = Object.keys(peers).length;
16167
17131
  const syncNoPeers = !syncDisabled && peerCount === 0;
16168
17132
  if (syncMeta) {
16169
- const parts = syncDisabled ? ["Advanced sync is off on this device", "Turn on sync in Settings → Device Sync when you want pairing payloads, peer status, and recent attempt details here"] : syncNoPeers ? ["Advanced sync is ready but idle", "Use Show pairing to connect another device, then this panel will start showing live peer status and recent attempts"] : [
17133
+ const parts = syncDisabled ? ["Advanced sync is off on this device", "Turn on sync in Settings → Device Sync when you want pairing payloads, peer status, and recent attempt details here"] : syncNoPeers ? ["Advanced sync is ready but idle", "Use Show pairing command under People & devices to connect another device, then this panel will start showing live peer status and recent attempts"] : [
16170
17134
  `Advanced state: ${daemonStateLabel}`,
16171
17135
  `Peers: ${peerCount}`,
16172
17136
  lastSync ? `Last sync: ${formatAgeShort(secondsSince(lastSync))} ago` : "Last sync: never"
@@ -16317,7 +17281,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16317
17281
  });
16318
17282
  const pairingCopy = document.getElementById("pairingCopy");
16319
17283
  if (pairingCopy) pairingCopy.onclick = async () => {
16320
- const text = state.pairingCommandRaw || document.getElementById("pairingPayload")?.textContent || "";
17284
+ const text = state.pairingCommandRaw;
16321
17285
  if (text) await copyToClipboard(text, pairingCopy);
16322
17286
  };
16323
17287
  }
@@ -16327,6 +17291,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16327
17291
  const pairingHint = document.getElementById("pairingHint");
16328
17292
  if (!pairingPayloadEl) return;
16329
17293
  renderPairingView(pairingPayloadEl, pairingHint, pairingView(state.pairingPayloadRaw));
17294
+ const pairingCopy = document.getElementById("pairingCopy");
17295
+ if (pairingCopy) pairingCopy.disabled = !state.pairingCommandRaw;
16330
17296
  }
16331
17297
  function renderRedactControl() {
16332
17298
  const mount = document.getElementById(SYNC_REDACT_MOUNT_ID);
@@ -16644,6 +17610,24 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16644
17610
  renderIntoSyncMount(input.meta, /* @__PURE__ */ u(LegacyClaimMeta, { devices }));
16645
17611
  }
16646
17612
  //#endregion
17613
+ //#region src/components/primitives/presence-pip.tsx
17614
+ var DEFAULT_LABEL = {
17615
+ online: "Online",
17616
+ offline: "Offline",
17617
+ degraded: "Degraded",
17618
+ attention: "Action required",
17619
+ syncing: "Syncing",
17620
+ unknown: "Status unknown"
17621
+ };
17622
+ function PresencePip({ state, size = 8, "aria-label": ariaLabel }) {
17623
+ return /* @__PURE__ */ u("span", {
17624
+ "aria-label": ariaLabel ?? DEFAULT_LABEL[state],
17625
+ className: `presence-pip presence-pip--${state}`,
17626
+ role: "img",
17627
+ style: `--presence-pip-size: ${size}px`
17628
+ });
17629
+ }
17630
+ //#endregion
16647
17631
  //#region src/tabs/sync/peer-scope-collapsible.tsx
16648
17632
  function PeerScopeCollapsible({ contentHost, initialOpen, onOpenChange, children }) {
16649
17633
  const [open, setOpen] = d$2(initialOpen);
@@ -16660,17 +17644,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16660
17644
  (contentRef.current?.querySelector("button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])"))?.focus();
16661
17645
  });
16662
17646
  }, [open]);
16663
- return /* @__PURE__ */ u(Root, {
17647
+ return /* @__PURE__ */ u(Root$3, {
16664
17648
  open,
16665
17649
  onOpenChange: setOpen,
16666
- children: [/* @__PURE__ */ u(Trigger, {
17650
+ children: [/* @__PURE__ */ u(Trigger$4, {
16667
17651
  asChild: true,
16668
17652
  children: /* @__PURE__ */ u("button", {
16669
17653
  type: "button",
16670
17654
  className: "settings-button",
16671
17655
  children: open ? "Hide sharing scope" : "Show sharing scope"
16672
17656
  })
16673
- }), contentHost ? $$1(/* @__PURE__ */ u(Content, {
17657
+ }), contentHost ? $$1(/* @__PURE__ */ u(Content$2, {
16674
17658
  forceMount: true,
16675
17659
  ref: contentRef,
16676
17660
  className: `peer-scope-editor-wrap${open ? "" : " collapsed"}`,
@@ -16697,6 +17681,46 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16697
17681
  }
16698
17682
  //#endregion
16699
17683
  //#region src/tabs/sync/components/sync-peers.tsx
17684
+ function ChevronRightIcon() {
17685
+ return /* @__PURE__ */ u("svg", {
17686
+ "aria-hidden": "true",
17687
+ fill: "none",
17688
+ stroke: "currentColor",
17689
+ "stroke-linecap": "round",
17690
+ "stroke-linejoin": "round",
17691
+ "stroke-width": "2",
17692
+ viewBox: "0 0 24 24",
17693
+ xmlns: "http://www.w3.org/2000/svg",
17694
+ children: [/* @__PURE__ */ u("title", { children: "Chevron" }), /* @__PURE__ */ u("path", { d: "m9 18 6-6-6-6" })]
17695
+ });
17696
+ }
17697
+ function presenceForPeer(peer) {
17698
+ switch (derivePeerUiStatus(peer)) {
17699
+ case "connected": return "online";
17700
+ case "offline": return "offline";
17701
+ case "needs-repair": return "attention";
17702
+ default: return "unknown";
17703
+ }
17704
+ }
17705
+ var expandedPeerId = null;
17706
+ var expandTickCounter = 0;
17707
+ var expandListeners = /* @__PURE__ */ new Set();
17708
+ function setExpandedPeer(peerId) {
17709
+ if (expandedPeerId === peerId) return;
17710
+ expandedPeerId = peerId;
17711
+ expandTickCounter += 1;
17712
+ for (const listener of expandListeners) listener(expandTickCounter);
17713
+ }
17714
+ function useExpandedPeer() {
17715
+ const [, setTick] = d$2(0);
17716
+ y$2(() => {
17717
+ expandListeners.add(setTick);
17718
+ return () => {
17719
+ expandListeners.delete(setTick);
17720
+ };
17721
+ }, []);
17722
+ return expandedPeerId;
17723
+ }
16700
17724
  var DIRECTION_GLYPH = {
16701
17725
  bidirectional: {
16702
17726
  glyph: "↕",
@@ -16738,9 +17762,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16738
17762
  const scope = peer.project_scope || {};
16739
17763
  const includeList = listText(scope.include);
16740
17764
  const excludeList = listText(scope.exclude);
16741
- listText(scope.effective_include);
16742
- listText(scope.effective_exclude);
16743
- Boolean(scope.inherits_global);
16744
17765
  const primaryAddress = pickPrimaryAddress(peer.addresses);
16745
17766
  const peerAddresses = Array.isArray(peer.addresses) ? Array.from(new Set(peer.addresses.filter(Boolean).map((value) => String(value)))) : [];
16746
17767
  const addressLine = peerAddresses.length ? peerAddresses.map((address) => isSyncRedactionEnabled() ? redactAddress(address) : address).join(" · ") : "No addresses";
@@ -16781,8 +17802,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16781
17802
  state.lastSyncPeers,
16782
17803
  state.lastSyncViewModel
16783
17804
  ]);
16784
- const includeEditor = T$1(() => createChipEditor(includeList, "Add included project", "All projects"), [peerId, includeList.join("|")]);
16785
- const excludeEditor = T$1(() => createChipEditor(excludeList, "Add excluded project", "No exclusions"), [peerId, excludeList.join("|")]);
17805
+ const includeEditor = T$1(() => createChipEditor(includeList, "Add project", "All projects", state.knownProjects), [
17806
+ peerId,
17807
+ includeList.join("|"),
17808
+ state.knownProjects.join("|")
17809
+ ]);
17810
+ const excludeEditor = T$1(() => createChipEditor(excludeList, "Add project", "No exclusions", state.knownProjects), [
17811
+ peerId,
17812
+ excludeList.join("|"),
17813
+ state.knownProjects.join("|")
17814
+ ]);
16786
17815
  y$2(() => {
16787
17816
  setRenameValue(displayName);
16788
17817
  setFeedback(state.syncPeerFeedbackById.get(peerId) ?? null);
@@ -16924,171 +17953,214 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16924
17953
  setResetScopeBusy(false);
16925
17954
  }
16926
17955
  }
16927
- return /* @__PURE__ */ u("div", {
16928
- ref: cardRef,
16929
- className: "peer-card",
16930
- "data-peer-device-id": peerId || void 0,
16931
- children: [/* @__PURE__ */ u("div", {
16932
- className: "peer-title",
16933
- children: [/* @__PURE__ */ u("div", { children: [
16934
- /* @__PURE__ */ u("strong", {
16935
- title: peerId || void 0,
16936
- children: displayName
16937
- }),
16938
- directionHint ? /* @__PURE__ */ u("span", {
16939
- "aria-label": directionHint.label,
16940
- className: "peer-direction",
16941
- role: "img",
16942
- title: directionHint.label,
16943
- children: directionHint.glyph
16944
- }) : null,
16945
- /* @__PURE__ */ u("div", {
16946
- className: "peer-meta",
16947
- children: [/* @__PURE__ */ u("span", {
16948
- className: `badge ${trustSummary.isWarning ? "badge-offline" : "badge-online"}`,
16949
- children: trustSummary.badgeLabel
16950
- }), pendingScopeReview ? /* @__PURE__ */ u("span", {
16951
- className: "badge actor-badge",
16952
- children: "Needs scope review"
16953
- }) : null]
16954
- })
16955
- ] }), /* @__PURE__ */ u("div", {
16956
- className: "peer-actions",
16957
- children: [
16958
- /* @__PURE__ */ u("button", {
16959
- type: "button",
16960
- className: "settings-button",
16961
- disabled: !primaryAddress || syncBusy,
16962
- onClick: () => void sync(),
16963
- children: syncBusy ? "Syncing…" : "Sync now"
16964
- }),
16965
- /* @__PURE__ */ u("div", {
16966
- className: "sync-labeled-field",
16967
- children: [/* @__PURE__ */ u("label", {
16968
- className: "sync-labeled-field-caption",
16969
- htmlFor: `device-name-${peerId || "unknown"}`,
16970
- children: "Device name"
16971
- }), /* @__PURE__ */ u(TextInput, {
16972
- "aria-label": `Friendly name for ${displayName}`,
16973
- className: "peer-scope-input",
16974
- "data-device-name-input": peerId || void 0,
16975
- disabled: renameBusy,
16976
- id: `device-name-${peerId || "unknown"}`,
16977
- placeholder: "Friendly device name",
16978
- type: "text",
16979
- value: renameValue,
16980
- onInput: (event) => setRenameValue(event.currentTarget.value)
16981
- })]
16982
- }),
16983
- /* @__PURE__ */ u("button", {
16984
- type: "button",
16985
- className: "settings-button",
16986
- disabled: renameBusy,
16987
- onClick: () => void rename(),
16988
- children: renameLabel
16989
- }),
16990
- /* @__PURE__ */ u("button", {
16991
- type: "button",
16992
- className: "settings-button danger",
16993
- disabled: removeBusy,
16994
- onClick: () => void remove(),
16995
- children: removeLabel
16996
- })
16997
- ]
16998
- })]
16999
- }), /* @__PURE__ */ u("div", {
17000
- className: "peer-scope",
17001
- children: [
17002
- scopeReviewRequested ? /* @__PURE__ */ u("div", {
17003
- className: "peer-meta",
17004
- children: "Review this device's sharing rules now if the defaults are too broad."
17005
- }) : pendingScopeReview ? /* @__PURE__ */ u("div", {
17006
- className: "peer-meta",
17007
- children: "Sharing rule review is still pending for this device."
17008
- }) : null,
17009
- /* @__PURE__ */ u("div", {
17010
- className: "peer-scope-summary",
17011
- children: "Device details"
17012
- }),
17013
- /* @__PURE__ */ u("div", {
17014
- className: "peer-addresses",
17015
- children: addressLine
17016
- }),
17017
- /* @__PURE__ */ u("div", {
17018
- className: "peer-meta",
17019
- children: [lastSyncAt ? `Sync: ${formatTimestamp(lastSyncAt)}` : "Sync: never", lastPingAt ? `Ping: ${formatTimestamp(lastPingAt)}` : "Ping: never"].join(" · ")
17020
- }),
17021
- /* @__PURE__ */ u("div", {
17022
- className: "peer-scope-summary",
17023
- children: "Who this device belongs to"
17024
- }),
17025
- /* @__PURE__ */ u("div", {
17026
- className: "peer-meta",
17027
- children: assignmentSummary
17028
- }),
17029
- /* @__PURE__ */ u("div", {
17030
- className: "peer-actor-row",
17031
- children: [/* @__PURE__ */ u("div", {
17032
- className: "sync-radix-select-host sync-actor-select-host",
17033
- children: /* @__PURE__ */ u(RadixSelect, {
17034
- ariaLabel: `Assigned person for ${displayName}`,
17035
- contentClassName: "sync-radix-select-content sync-actor-select-content",
17036
- disabled: applyActorBusy,
17037
- itemClassName: "sync-radix-select-item",
17038
- onValueChange: setSelectedActorId,
17039
- options: actorSelectOptions,
17040
- placeholder: "No person assigned yet",
17041
- triggerClassName: "sync-radix-select-trigger sync-actor-select",
17042
- value: selectedActorId,
17043
- viewportClassName: "sync-radix-select-viewport"
17956
+ const isExpanded = useExpandedPeer() === peerId && peerId !== "";
17957
+ const drawerId = `device-drawer-${peerId || "unknown"}`;
17958
+ const presenceState = presenceForPeer(peer);
17959
+ const syncMetaText = lastSyncAt ? `Sync: ${formatTimestamp(lastSyncAt)}` : "Sync: never";
17960
+ const toggleLabel = `${isExpanded ? "Collapse" : "Expand"} device ${displayName}`;
17961
+ const handleOpenChange = (open) => {
17962
+ if (open) setExpandedPeer(peerId);
17963
+ else if (expandedPeerId === peerId) setExpandedPeer(null);
17964
+ };
17965
+ return /* @__PURE__ */ u(Root$3, {
17966
+ asChild: true,
17967
+ open: isExpanded,
17968
+ onOpenChange: handleOpenChange,
17969
+ children: /* @__PURE__ */ u("div", {
17970
+ ref: cardRef,
17971
+ className: "peer-card",
17972
+ "data-peer-device-id": peerId || void 0,
17973
+ children: [/* @__PURE__ */ u(Trigger$4, {
17974
+ asChild: true,
17975
+ children: /* @__PURE__ */ u("button", {
17976
+ "aria-label": toggleLabel,
17977
+ className: "device-row-head device-row-head--trigger",
17978
+ type: "button",
17979
+ children: [
17980
+ /* @__PURE__ */ u(PresencePip, { state: presenceState }),
17981
+ /* @__PURE__ */ u("span", {
17982
+ className: "device-row-name",
17983
+ title: peerId || void 0,
17984
+ children: displayName
17985
+ }),
17986
+ directionHint ? /* @__PURE__ */ u("span", {
17987
+ "aria-label": directionHint.label,
17988
+ className: "peer-direction",
17989
+ role: "img",
17990
+ title: directionHint.label,
17991
+ children: directionHint.glyph
17992
+ }) : null,
17993
+ /* @__PURE__ */ u("span", {
17994
+ className: "device-row-chips",
17995
+ children: [
17996
+ /* @__PURE__ */ u("span", {
17997
+ className: `badge ${trustSummary.isWarning ? "badge-offline" : "badge-online"}`,
17998
+ children: trustSummary.badgeLabel
17999
+ }),
18000
+ pendingScopeReview ? /* @__PURE__ */ u("span", {
18001
+ className: "badge actor-badge",
18002
+ children: "Needs scope review"
18003
+ }) : null,
18004
+ peer.discovered_via_group_id ? /* @__PURE__ */ u("span", {
18005
+ className: "badge actor-badge",
18006
+ title: `Discovered through coordinator group ${peer.discovered_via_group_id}`,
18007
+ children: `via ${peer.discovered_via_group_id}`
18008
+ }) : null
18009
+ ]
18010
+ }),
18011
+ /* @__PURE__ */ u("span", {
18012
+ className: "device-row-meta",
18013
+ children: syncMetaText
18014
+ }),
18015
+ /* @__PURE__ */ u("span", {
18016
+ "aria-hidden": "true",
18017
+ className: "device-row-chevron",
18018
+ children: /* @__PURE__ */ u(ChevronRightIcon, {})
17044
18019
  })
17045
- }), /* @__PURE__ */ u("button", {
17046
- type: "button",
17047
- className: "settings-button",
17048
- disabled: applyActorBusy,
17049
- onClick: () => void savePerson(),
17050
- children: applyActorLabel
17051
- })]
17052
- }),
17053
- /* @__PURE__ */ u("div", {
17054
- className: "peer-scope-summary",
17055
- children: "Advanced sharing scope"
17056
- }),
17057
- /* @__PURE__ */ u("div", {
17058
- className: "peer-meta",
17059
- children: "Review or tighten what this device can share when you need more than the global defaults."
17060
- }),
17061
- /* @__PURE__ */ u(PeerScopeCollapsible, {
17062
- contentHost: scopeHost,
17063
- initialOpen: scopeEditorOpen,
17064
- onOpenChange: (open) => {
17065
- if (open) openPeerScopeEditors.add(peerId);
17066
- else openPeerScopeEditors.delete(peerId);
17067
- },
17068
- children: /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ u("div", {
17069
- className: "peer-scope-row",
17070
- children: [/* @__PURE__ */ u(ExistingElementSlot$1, { element: includeEditor.element }), /* @__PURE__ */ u(ExistingElementSlot$1, { element: excludeEditor.element })]
17071
- }), /* @__PURE__ */ u("div", {
17072
- className: "peer-scope-actions",
17073
- children: [/* @__PURE__ */ u("button", {
18020
+ ]
18021
+ })
18022
+ }), /* @__PURE__ */ u(Content$2, {
18023
+ "aria-label": `Device actions for ${displayName}`,
18024
+ className: "device-row-drawer",
18025
+ id: drawerId,
18026
+ children: [/* @__PURE__ */ u("div", {
18027
+ className: "peer-actions",
18028
+ children: [
18029
+ /* @__PURE__ */ u("button", {
17074
18030
  type: "button",
17075
18031
  className: "settings-button",
17076
- disabled: saveScopeBusy,
17077
- onClick: () => void saveScope(),
17078
- children: saveScopeLabel
17079
- }), /* @__PURE__ */ u("button", {
18032
+ disabled: !primaryAddress || syncBusy,
18033
+ onClick: () => void sync(),
18034
+ children: syncBusy ? "Syncing…" : "Sync now"
18035
+ }),
18036
+ /* @__PURE__ */ u("div", {
18037
+ className: "sync-labeled-field",
18038
+ children: [/* @__PURE__ */ u("label", {
18039
+ className: "sync-labeled-field-caption",
18040
+ htmlFor: `device-name-${peerId || "unknown"}`,
18041
+ children: "Device name"
18042
+ }), /* @__PURE__ */ u(TextInput, {
18043
+ "aria-label": `Friendly name for ${displayName}`,
18044
+ className: "peer-scope-input",
18045
+ "data-device-name-input": peerId || void 0,
18046
+ disabled: renameBusy,
18047
+ id: `device-name-${peerId || "unknown"}`,
18048
+ placeholder: "Friendly device name",
18049
+ type: "text",
18050
+ value: renameValue,
18051
+ onInput: (event) => setRenameValue(event.currentTarget.value)
18052
+ })]
18053
+ }),
18054
+ /* @__PURE__ */ u("button", {
17080
18055
  type: "button",
17081
18056
  className: "settings-button",
17082
- disabled: resetScopeBusy,
17083
- onClick: () => void resetScope(),
17084
- children: resetScopeLabel
17085
- })]
17086
- })] })
17087
- }),
17088
- /* @__PURE__ */ u(SyncInlineFeedback, { feedback }),
17089
- /* @__PURE__ */ u("div", { ref: setScopeHost })
17090
- ]
17091
- })]
18057
+ disabled: renameBusy,
18058
+ onClick: () => void rename(),
18059
+ children: renameLabel
18060
+ }),
18061
+ /* @__PURE__ */ u("button", {
18062
+ type: "button",
18063
+ className: "settings-button danger",
18064
+ disabled: removeBusy,
18065
+ onClick: () => void remove(),
18066
+ children: removeLabel
18067
+ })
18068
+ ]
18069
+ }), /* @__PURE__ */ u("div", {
18070
+ className: "peer-scope",
18071
+ children: [
18072
+ scopeReviewRequested ? /* @__PURE__ */ u("div", {
18073
+ className: "peer-meta",
18074
+ children: "Review this device's sharing rules now if the defaults are too broad."
18075
+ }) : pendingScopeReview ? /* @__PURE__ */ u("div", {
18076
+ className: "peer-meta",
18077
+ children: "Sharing rule review is still pending for this device."
18078
+ }) : null,
18079
+ /* @__PURE__ */ u("div", {
18080
+ className: "peer-scope-summary",
18081
+ children: "Device details"
18082
+ }),
18083
+ /* @__PURE__ */ u("div", {
18084
+ className: "peer-addresses",
18085
+ children: addressLine
18086
+ }),
18087
+ /* @__PURE__ */ u("div", {
18088
+ className: "peer-meta",
18089
+ children: [lastSyncAt ? `Sync: ${formatTimestamp(lastSyncAt)}` : "Sync: never", lastPingAt ? `Ping: ${formatTimestamp(lastPingAt)}` : "Ping: never"].join(" · ")
18090
+ }),
18091
+ /* @__PURE__ */ u("div", {
18092
+ className: "peer-scope-summary",
18093
+ children: "Who this device belongs to"
18094
+ }),
18095
+ /* @__PURE__ */ u("div", {
18096
+ className: "peer-meta",
18097
+ children: assignmentSummary
18098
+ }),
18099
+ /* @__PURE__ */ u("div", {
18100
+ className: "peer-actor-row",
18101
+ children: [/* @__PURE__ */ u("div", {
18102
+ className: "sync-radix-select-host sync-actor-select-host",
18103
+ children: /* @__PURE__ */ u(RadixSelect, {
18104
+ ariaLabel: `Assigned person for ${displayName}`,
18105
+ contentClassName: "sync-radix-select-content sync-actor-select-content",
18106
+ disabled: applyActorBusy,
18107
+ itemClassName: "sync-radix-select-item",
18108
+ onValueChange: setSelectedActorId,
18109
+ options: actorSelectOptions,
18110
+ placeholder: "No person assigned yet",
18111
+ triggerClassName: "sync-radix-select-trigger sync-actor-select",
18112
+ value: selectedActorId,
18113
+ viewportClassName: "sync-radix-select-viewport"
18114
+ })
18115
+ }), /* @__PURE__ */ u("button", {
18116
+ type: "button",
18117
+ className: "settings-button",
18118
+ disabled: applyActorBusy,
18119
+ onClick: () => void savePerson(),
18120
+ children: applyActorLabel
18121
+ })]
18122
+ }),
18123
+ /* @__PURE__ */ u("div", {
18124
+ className: "peer-scope-summary",
18125
+ children: "Advanced sharing scope"
18126
+ }),
18127
+ /* @__PURE__ */ u("div", {
18128
+ className: "peer-meta",
18129
+ children: "Review or tighten what this device can share when you need more than the global defaults."
18130
+ }),
18131
+ /* @__PURE__ */ u(PeerScopeCollapsible, {
18132
+ contentHost: scopeHost,
18133
+ initialOpen: scopeEditorOpen,
18134
+ onOpenChange: (open) => {
18135
+ if (open) openPeerScopeEditors.add(peerId);
18136
+ else openPeerScopeEditors.delete(peerId);
18137
+ },
18138
+ children: /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ u("div", {
18139
+ className: "peer-scope-row",
18140
+ children: [/* @__PURE__ */ u(ExistingElementSlot$1, { element: includeEditor.element }), /* @__PURE__ */ u(ExistingElementSlot$1, { element: excludeEditor.element })]
18141
+ }), /* @__PURE__ */ u("div", {
18142
+ className: "peer-scope-actions",
18143
+ children: [/* @__PURE__ */ u("button", {
18144
+ type: "button",
18145
+ className: "settings-button",
18146
+ disabled: saveScopeBusy,
18147
+ onClick: () => void saveScope(),
18148
+ children: saveScopeLabel
18149
+ }), /* @__PURE__ */ u("button", {
18150
+ type: "button",
18151
+ className: "settings-button",
18152
+ disabled: resetScopeBusy,
18153
+ onClick: () => void resetScope(),
18154
+ children: resetScopeLabel
18155
+ })]
18156
+ })] })
18157
+ }),
18158
+ /* @__PURE__ */ u(SyncInlineFeedback, { feedback }),
18159
+ /* @__PURE__ */ u("div", { ref: setScopeHost })
18160
+ ]
18161
+ })]
18162
+ })]
18163
+ })
17092
18164
  });
17093
18165
  }
17094
18166
  function SyncPeersList(props) {
@@ -17096,8 +18168,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17096
18168
  const syncStatus = state.lastSyncStatus;
17097
18169
  const syncDisabled = syncStatus?.daemon_state === "disabled" || syncStatus?.enabled === false;
17098
18170
  if (!props.peers.length) return /* @__PURE__ */ u(k$3, { children: [/* @__PURE__ */ u(SyncInlineFeedback, { feedback: sectionFeedback }), /* @__PURE__ */ u(SyncEmptyState, {
17099
- detail: syncDisabled ? "Turn on sync in Settings → Device Sync first, then use Show pairing in Advanced diagnostics to connect another device." : "Use Show pairing in Advanced diagnostics, run the command on the other device, then come back here to name it and decide who it belongs to.",
17100
- title: "No devices connected here yet."
18171
+ detail: syncDisabled ? "Turn on sync in Settings → Device Sync first. Then use Invite a teammate or Paste an invite above to connect another device." : "Use Invite a teammate above to share a join code, or Paste an invite to enroll this device on an existing team.",
18172
+ title: "No teammates yet"
17101
18173
  })] });
17102
18174
  return /* @__PURE__ */ u(k$3, { children: [/* @__PURE__ */ u(SyncInlineFeedback, { feedback: sectionFeedback }), props.peers.map((peer) => {
17103
18175
  const peerId = String(peer.peer_device_id || peer.name || "unknown-peer");
@@ -17392,6 +18464,31 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17392
18464
  });
17393
18465
  }
17394
18466
  //#endregion
18467
+ //#region src/tabs/sync/sync-view-controller.ts
18468
+ function getSyncSubView() {
18469
+ return window.location.hash.replace(/^#/, "") === "sync/diagnostics" ? "diagnostics" : "main";
18470
+ }
18471
+ function applySyncSubView(view = getSyncSubView()) {
18472
+ const main = document.getElementById("syncMainView");
18473
+ const diag = document.getElementById("syncDiagnosticsView");
18474
+ if (!main || !diag) return;
18475
+ if (view === "diagnostics") {
18476
+ main.hidden = true;
18477
+ diag.hidden = false;
18478
+ } else {
18479
+ main.hidden = false;
18480
+ diag.hidden = true;
18481
+ }
18482
+ }
18483
+ var listenerAttached = false;
18484
+ function ensureSyncSubViewListener() {
18485
+ if (listenerAttached) return;
18486
+ listenerAttached = true;
18487
+ window.addEventListener("hashchange", () => {
18488
+ applySyncSubView();
18489
+ });
18490
+ }
18491
+ //#endregion
17395
18492
  //#region src/tabs/sync/team-sync/data/state.ts
17396
18493
  var teamSyncState = {
17397
18494
  invitePolicy: "auto_admit",
@@ -17543,16 +18640,24 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17543
18640
  if (!syncJoinButton || !syncJoinInvite) return;
17544
18641
  const inviteValue = syncJoinInvite.value.trim();
17545
18642
  if (!inviteValue) {
17546
- markFieldError(syncJoinInvite, "Paste a team invite to join.");
18643
+ markFieldError(syncJoinInvite, "Paste a team invite or pairing payload.");
17547
18644
  return;
17548
18645
  }
17549
18646
  clearFieldError(syncJoinInvite);
17550
18647
  syncJoinButton.disabled = true;
17551
- syncJoinButton.textContent = "Joining…";
18648
+ syncJoinButton.textContent = "Accepting…";
17552
18649
  try {
17553
18650
  const result = await importCoordinatorInvite(inviteValue);
17554
18651
  state.lastTeamJoin = result;
17555
- let feedback = {
18652
+ const resultType = typeof result.type === "string" ? result.type : "team_join";
18653
+ let feedback;
18654
+ if (resultType === "pair") {
18655
+ const peerId = String(result.peer_device_id ?? "").trim();
18656
+ feedback = {
18657
+ message: peerId ? `Paired with device ${peerId.slice(0, 8)}. It will appear in People & devices.` : "Paired the device. It will appear in People & devices.",
18658
+ tone: "success"
18659
+ };
18660
+ } else feedback = {
17556
18661
  message: result.status === "pending" ? "Join request sent. Waiting for admin approval." : "Joined the team.",
17557
18662
  tone: "success"
17558
18663
  };
@@ -17563,7 +18668,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17563
18668
  await loadSyncData();
17564
18669
  } catch (error) {
17565
18670
  feedback = {
17566
- message: friendlyError(error, "Joined the team, but this view has not refreshed yet."),
18671
+ message: friendlyError(error, "Accepted the invite, but this view has not refreshed yet."),
17567
18672
  tone: "warning"
17568
18673
  };
17569
18674
  state.syncJoinFlowFeedback = feedback;
@@ -17571,7 +18676,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17571
18676
  }
17572
18677
  } catch (error) {
17573
18678
  state.syncJoinFlowFeedback = {
17574
- message: friendlyError(error, "Failed to import invite. Check that the invite is complete, current, and meant for this team, then try again."),
18679
+ message: friendlyError(error, "Failed to accept. Check that the invite or pairing payload is complete and current, then try again."),
17575
18680
  tone: "warning"
17576
18681
  };
17577
18682
  setJoinFeedbackVisibility();
@@ -17581,7 +18686,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17581
18686
  } finally {
17582
18687
  if (syncJoinButton.disabled) {
17583
18688
  syncJoinButton.disabled = false;
17584
- syncJoinButton.textContent = "Join team";
18689
+ syncJoinButton.textContent = "Accept";
17585
18690
  }
17586
18691
  }
17587
18692
  });
@@ -17660,16 +18765,38 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17660
18765
  })]
17661
18766
  });
17662
18767
  }
17663
- function SyncInviteJoinPanels({ invitePanel, invitePanelOpen, inviteRestoreParent, joinPanel, joinRestoreParent, onToggleInvitePanel, pairedPeerCount, presenceStatus }) {
18768
+ function JoinToggleRow({ joinPanel, joinPanelOpen, joinRestoreParent, onToggle }) {
18769
+ return /* @__PURE__ */ u(k$3, { children: [/* @__PURE__ */ u("div", {
18770
+ className: "sync-action",
18771
+ children: [/* @__PURE__ */ u("div", {
18772
+ className: "sync-action-text",
18773
+ children: ["Accept an invite or pairing.", /* @__PURE__ */ u("span", {
18774
+ className: "sync-action-command",
18775
+ children: "Paste a team invite to join another team, or a pairing payload to connect another device."
18776
+ })]
18777
+ }), /* @__PURE__ */ u("button", {
18778
+ type: "button",
18779
+ className: "settings-button",
18780
+ onClick: onToggle,
18781
+ children: joinPanelOpen ? "Hide paste form" : "Paste invite or pairing"
18782
+ })]
18783
+ }), joinPanel ? /* @__PURE__ */ u(ExistingElementSlot, {
18784
+ element: joinPanel,
18785
+ hidden: !joinPanelOpen,
18786
+ restoreParent: joinRestoreParent
18787
+ }) : null] });
18788
+ }
18789
+ function SyncInviteJoinPanels({ invitePanel, invitePanelOpen, inviteRestoreParent, joinPanel, joinPanelOpen, joinRestoreParent, onToggleInvitePanel, onToggleJoinPanel, pairedPeerCount, presenceStatus }) {
18790
+ const notEnrolled = presenceStatus === "not_enrolled";
17664
18791
  return /* @__PURE__ */ u(k$3, { children: [
17665
- presenceStatus === "not_enrolled" ? /* @__PURE__ */ u(k$3, { children: [
18792
+ notEnrolled ? /* @__PURE__ */ u(k$3, { children: [
17666
18793
  /* @__PURE__ */ u("div", {
17667
18794
  className: "sync-action",
17668
18795
  children: /* @__PURE__ */ u("div", {
17669
18796
  className: "sync-action-text",
17670
18797
  children: ["Join this device.", /* @__PURE__ */ u("span", {
17671
18798
  className: "sync-action-command",
17672
- children: "Paste an invite for this device below to join an existing team."
18799
+ children: "Paste a team invite or pairing payload below to join an existing team or connect another of your devices."
17673
18800
  })]
17674
18801
  })
17675
18802
  }),
@@ -17693,8 +18820,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17693
18820
  })]
17694
18821
  })
17695
18822
  })
17696
- ] }) : null,
17697
- presenceStatus !== "not_enrolled" ? /* @__PURE__ */ u(InviteToggleRow, {
18823
+ ] }) : /* @__PURE__ */ u(k$3, { children: [/* @__PURE__ */ u(JoinToggleRow, {
18824
+ joinPanel,
18825
+ joinPanelOpen,
18826
+ joinRestoreParent,
18827
+ onToggle: onToggleJoinPanel
18828
+ }), /* @__PURE__ */ u("div", {
18829
+ className: "peer-meta",
18830
+ id: "syncJoinFeedback",
18831
+ hidden: true
18832
+ })] }),
18833
+ !notEnrolled ? /* @__PURE__ */ u(InviteToggleRow, {
17698
18834
  invitePanel,
17699
18835
  invitePanelOpen,
17700
18836
  inviteRestoreParent,
@@ -17812,41 +18948,40 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17812
18948
  function DiscoveredDeviceRow({ row, onInspectConflict, onRemoveConflict, onReview }) {
17813
18949
  const [busy, setBusy] = d$2(null);
17814
18950
  const [feedback, setFeedback] = d$2(null);
17815
- const [reviewLabel, setReviewLabel] = d$2(row.actionLabel || "Review device");
18951
+ const defaultReviewLabel = row.actionLabel || "Pair with this device";
18952
+ const [reviewLabel, setReviewLabel] = d$2(defaultReviewLabel);
17816
18953
  const [removeLabel, setRemoveLabel] = d$2("Remove broken device record");
17817
18954
  return /* @__PURE__ */ u("div", {
17818
- className: "actor-row",
18955
+ className: "peer-card peer-card--padded",
17819
18956
  "data-discovered-device-id": row.deviceId,
17820
18957
  children: [
17821
18958
  /* @__PURE__ */ u("div", {
17822
- className: "actor-details",
17823
- children: [/* @__PURE__ */ u("div", {
17824
- className: "actor-title",
17825
- children: [
17826
- /* @__PURE__ */ u("strong", {
17827
- title: row.displayTitle || void 0,
17828
- children: row.displayName
17829
- }),
17830
- /* @__PURE__ */ u("span", {
17831
- className: `badge actor-badge${row.availabilityLabel === "Offline" ? "" : " local"}`,
17832
- children: row.availabilityLabel
17833
- }),
17834
- /* @__PURE__ */ u("span", {
17835
- className: "badge actor-badge",
17836
- children: row.connectionLabel
17837
- }),
17838
- row.approvalBadgeLabel ? /* @__PURE__ */ u("span", {
17839
- className: "badge actor-badge",
17840
- children: row.approvalBadgeLabel
17841
- }) : null
17842
- ]
17843
- }), /* @__PURE__ */ u("div", {
17844
- className: "peer-meta",
17845
- children: row.note
17846
- })]
18959
+ className: "peer-title",
18960
+ children: [
18961
+ /* @__PURE__ */ u("strong", {
18962
+ title: row.displayTitle || void 0,
18963
+ children: row.displayName
18964
+ }),
18965
+ /* @__PURE__ */ u("span", {
18966
+ className: `badge actor-badge${row.availabilityLabel === "Offline" ? "" : " local"}`,
18967
+ children: row.availabilityLabel
18968
+ }),
18969
+ /* @__PURE__ */ u("span", {
18970
+ className: "badge actor-badge",
18971
+ children: row.connectionLabel
18972
+ }),
18973
+ row.approvalBadgeLabel ? /* @__PURE__ */ u("span", {
18974
+ className: "badge actor-badge",
18975
+ children: row.approvalBadgeLabel
18976
+ }) : null
18977
+ ]
17847
18978
  }),
17848
18979
  /* @__PURE__ */ u("div", {
17849
- className: "actor-actions",
18980
+ className: "peer-meta",
18981
+ children: row.note
18982
+ }),
18983
+ /* @__PURE__ */ u("div", {
18984
+ className: "peer-actions",
17850
18985
  children: [
17851
18986
  row.mode === "accept" ? /* @__PURE__ */ u("button", {
17852
18987
  type: "button",
@@ -17855,10 +18990,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17855
18990
  disabled: busy !== null,
17856
18991
  onClick: async () => {
17857
18992
  setBusy("review");
17858
- setReviewLabel("Reviewing…");
18993
+ setReviewLabel("Pairing…");
17859
18994
  try {
17860
18995
  setFeedback(await onReview(row) || null);
17861
- setReviewLabel(row.actionLabel || "Review device");
18996
+ setReviewLabel(row.actionLabel || defaultReviewLabel);
17862
18997
  } catch {
17863
18998
  setReviewLabel("Retry");
17864
18999
  } finally {
@@ -17884,7 +19019,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17884
19019
  children: "Open device details"
17885
19020
  }), /* @__PURE__ */ u("button", {
17886
19021
  type: "button",
17887
- className: "settings-button",
19022
+ className: "settings-button danger",
17888
19023
  "aria-label": `${removeLabel} for ${row.displayName}`,
17889
19024
  disabled: busy !== null,
17890
19025
  onClick: async () => {
@@ -17952,36 +19087,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17952
19087
  children
17953
19088
  ] });
17954
19089
  }
17955
- function TeamStatusPortal({ mount, statusSummary }) {
17956
- return $$1(/* @__PURE__ */ u("div", {
17957
- className: "sync-team-summary",
17958
- children: [
17959
- /* @__PURE__ */ u(SectionHeading, { label: "Overview" }),
17960
- /* @__PURE__ */ u("div", {
17961
- className: "sync-team-status-row",
17962
- children: [/* @__PURE__ */ u("span", {
17963
- className: "sync-team-status-label",
17964
- children: "Current status"
17965
- }), /* @__PURE__ */ u("span", {
17966
- className: statusSummary.badgeClassName,
17967
- children: statusSummary.presenceLabel
17968
- })]
17969
- }),
17970
- statusSummary.headline ? /* @__PURE__ */ u("div", {
17971
- className: "sync-team-headline",
17972
- children: statusSummary.headline
17973
- }) : null,
17974
- statusSummary.detail ? /* @__PURE__ */ u("div", {
17975
- className: "section-meta",
17976
- children: statusSummary.detail
17977
- }) : null,
17978
- /* @__PURE__ */ u("div", {
17979
- className: "sync-team-metrics sync-team-metrics-secondary",
17980
- children: statusSummary.metricsText
17981
- })
17982
- ]
17983
- }), mount);
17984
- }
17985
19090
  function DiscoveredPortal({ mount, rows, onInspectConflict, onRemoveConflict, onReview }) {
17986
19091
  if (!mount || !rows.length && !state.syncDiscoveredFeedback) return null;
17987
19092
  return $$1(/* @__PURE__ */ u(k$3, { children: [
@@ -18019,10 +19124,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18019
19124
  return /* @__PURE__ */ u(k$3, { children: [
18020
19125
  /* @__PURE__ */ u(ActionContent, { ...props }),
18021
19126
  /* @__PURE__ */ u(TeamActionsContent, { children: props.children }),
18022
- /* @__PURE__ */ u(TeamStatusPortal, {
18023
- mount: props.listMount,
18024
- statusSummary: props.statusSummary
18025
- }),
18026
19127
  /* @__PURE__ */ u(PendingRequestsPortal, {
18027
19128
  mount: props.joinRequestsMount,
18028
19129
  requests: props.pendingJoinRequests,
@@ -18092,10 +19193,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18092
19193
  function renderTeamSync() {
18093
19194
  const meta = document.getElementById("syncTeamMeta");
18094
19195
  const setupPanel = document.getElementById("syncSetupPanel");
18095
- const list = document.getElementById("syncTeamStatus");
18096
- const listHeading = list?.previousElementSibling;
18097
19196
  const actions = document.getElementById("syncTeamActions");
18098
- if (!meta || !setupPanel || !list || !actions) return;
19197
+ if (!meta || !setupPanel || !actions) return;
18099
19198
  renderAdminSetupDisclosure();
18100
19199
  renderInvitePolicySelect();
18101
19200
  setInviteOutputVisibility();
@@ -18209,13 +19308,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18209
19308
  };
18210
19309
  const reviewDiscoveredDeviceName = async (suggestedName) => {
18211
19310
  return await openSyncInputDialog({
18212
- title: "Review device",
18213
- description: "Choose a friendly name for this device before connecting it on this machine.",
19311
+ title: "Pair with this device",
19312
+ description: "Choose a friendly name for this device before pairing it on this machine.",
18214
19313
  initialValue: suggestedName,
18215
19314
  placeholder: "Desk Mini",
18216
- confirmLabel: "Connect device",
19315
+ confirmLabel: "Pair",
18217
19316
  cancelLabel: "Cancel",
18218
- validate: (nextValue) => nextValue.trim() ? null : "Enter a device name to connect this device."
19317
+ validate: (nextValue) => nextValue.trim() ? null : "Enter a device name to pair this device."
18219
19318
  });
18220
19319
  };
18221
19320
  const configured = Boolean(coordinator?.configured);
@@ -18224,32 +19323,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18224
19323
  const onlineBadge = document.getElementById("syncOnlineBadge");
18225
19324
  if (onlineBadge) updateSyncOnlineBadge(onlineBadge, configured, String(coordinator?.presence_status || ""));
18226
19325
  if (!configured) {
18227
- teardownTeamSyncRender(actions, [
18228
- list,
18229
- joinRequests,
18230
- discoveredList
18231
- ]);
19326
+ teardownTeamSyncRender(actions, [joinRequests, discoveredList]);
18232
19327
  setupPanel.hidden = false;
18233
- list.hidden = true;
18234
- if (listHeading) listHeading.hidden = true;
18235
19328
  actions.hidden = true;
18236
19329
  if (joinRequests) joinRequests.hidden = true;
18237
19330
  if (discoveredPanel) discoveredPanel.hidden = true;
18238
19331
  return;
18239
19332
  }
18240
19333
  setupPanel.hidden = true;
18241
- list.hidden = false;
18242
- if (listHeading) listHeading.hidden = false;
18243
19334
  actions.hidden = false;
18244
19335
  const presenceStatus = String(coordinator.presence_status || "");
18245
- const presenceLabel = presenceStatus === "posted" ? "Connected" : presenceStatus === "not_enrolled" ? "Needs enrollment" : "Connection error";
18246
19336
  const localPeers = Array.isArray(state.lastSyncPeers) ? state.lastSyncPeers : [];
18247
19337
  const attentionItems = Array.isArray(syncView.attentionItems) ? syncView.attentionItems : [];
18248
- const connectedCount = Number(syncView.summary?.connectedDeviceCount || 0);
18249
- const seenOnTeamCount = Number(syncView.summary?.seenOnTeamCount || 0);
18250
- const offlineTeamDeviceCount = Number(syncView.summary?.offlineTeamDeviceCount || 0);
18251
- const metricParts = [`Connected ${connectedCount}`, `Team ${seenOnTeamCount}`];
18252
- if (offlineTeamDeviceCount > 0) metricParts.push(`Offline ${offlineTeamDeviceCount}`);
18253
19338
  const discoveredRows = (Array.isArray(coordinator.discovered_devices) ? coordinator.discovered_devices : []).map((device) => {
18254
19339
  const deviceId = String(device.device_id || "").trim();
18255
19340
  const displayName = resolveFriendlyDeviceName({
@@ -18297,7 +19382,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18297
19382
  if (mode === "paired") pairedMessage = approvalSummary.state === "waiting-for-other-device" ? approvalSummary.description || "Waiting on the other device." : String(pairedPeer?.last_error || "").toLowerCase().includes("401") && String(pairedPeer?.last_error || "").toLowerCase().includes("unauthorized") ? "Waiting for the other device to trust this one before sync can work." : null;
18298
19383
  return {
18299
19384
  actionMessage,
18300
- actionLabel: approvalSummary.actionLabel || "Review device",
19385
+ actionLabel: approvalSummary.actionLabel || (pairedPeer ? "Review device" : "Pair with this device"),
18301
19386
  approvalBadgeLabel: approvalSummary.badgeLabel,
18302
19387
  availabilityLabel: device.stale ? "Offline" : "Available",
18303
19388
  connectionLabel: hasConflict ? SYNC_TERMINOLOGY.conflicts : pairedPeer ? SYNC_TERMINOLOGY.pairedLocally : "Not connected on this device",
@@ -18314,37 +19399,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18314
19399
  const visibleDiscoveredRows = discoveredRows.filter((row) => row.mode !== "paired" && row.mode !== "none" && row.mode !== "scope-pending");
18315
19400
  const discoveredActionableCount = discoveredRows.filter((row) => row.mode === "accept" || row.mode === "scope-pending").length;
18316
19401
  const actionableCount = attentionItems.length + pendingJoinRequests.length + discoveredActionableCount;
18317
- const attentionParts = [];
18318
- if (attentionItems.length > 0) {
18319
- const repairItems = attentionItems.filter((item) => item.kind === "device-needs-repair");
18320
- const nameItems = attentionItems.filter((item) => item.kind === "name-device");
18321
- const reviewItems = attentionItems.filter((item) => item.kind === "review-team-device");
18322
- const duplicateItems = attentionItems.filter((item) => item.kind === "possible-duplicate-person");
18323
- if (repairItems.length > 0) attentionParts.push(`${repairItems.length} device issue${repairItems.length === 1 ? "" : "s"} to review`);
18324
- if (nameItems.length > 0) attentionParts.push(`${nameItems.length} device${nameItems.length === 1 ? "" : "s"} to name`);
18325
- if (reviewItems.length > 0) attentionParts.push(`${reviewItems.length} device${reviewItems.length === 1 ? "" : "s"} to review`);
18326
- if (duplicateItems.length > 0) attentionParts.push(`${duplicateItems.length} possible duplicate${duplicateItems.length === 1 ? "" : "s"}`);
18327
- }
18328
- if (pendingJoinRequests.length > 0) attentionParts.push(`${pendingJoinRequests.length} join request${pendingJoinRequests.length === 1 ? "" : "s"} to review`);
18329
- if (discoveredActionableCount > 0) attentionParts.push(`${discoveredActionableCount} discovered device${discoveredActionableCount === 1 ? "" : "s"}`);
18330
- const attentionDetail = attentionParts.join(", ");
18331
19402
  const teamLabel = (coordinator.groups || []).join(", ") || "none";
18332
- const statusSummary = {
18333
- badgeClassName: `pill ${presenceStatus === "posted" ? "pill-success" : presenceStatus === "not_enrolled" ? "pill-warning" : "pill-error"}`,
18334
- detail: presenceStatus === "posted" ? actionableCount > 0 ? `Team ${teamLabel}. Work through Needs attention above, then review people and devices.` : `Team ${teamLabel}. Nothing urgent is blocking sync right now.` : presenceStatus === "not_enrolled" ? `Team ${teamLabel}. Enroll this device first, then return here to review the rest of the team.` : `Team ${teamLabel}. Fix the current sync issue first, then verify the rest of the team state.`,
18335
- headline: presenceStatus === "posted" ? actionableCount > 0 ? attentionDetail : "Everything is healthy" : presenceStatus === "not_enrolled" ? "This device is not enrolled in the team yet" : "Sync needs attention",
18336
- metricsText: metricParts.join(" · "),
18337
- presenceLabel
18338
- };
18339
19403
  meta.textContent = presenceStatus === "posted" ? actionableCount > 0 ? `Team: ${teamLabel}. Start with the next step below, then scan the current team status.` : `Team: ${teamLabel}. Team status and device details are below.` : presenceStatus === "not_enrolled" ? `Team: ${teamLabel}. Enroll this device first, then return here to review the rest of the team.` : `Team: ${teamLabel}. Fix the current sync issue first, then use the rest of this card to verify the team state.`;
18340
19404
  if (discoveredPanel) discoveredPanel.hidden = visibleDiscoveredRows.length === 0 && !state.syncDiscoveredFeedback;
18341
- if (discoveredMeta) discoveredMeta.textContent = visibleDiscoveredRows.length ? "Review anything here that still needs trust, follow-up, or approval." : "";
19405
+ if (discoveredMeta) discoveredMeta.textContent = visibleDiscoveredRows.length ? "Pair with a teammate's device to see it appear in People & devices and start syncing." : "";
18342
19406
  if (joinRequests) joinRequests.hidden = pendingJoinRequests.length === 0 && !state.syncJoinRequestsFeedback;
18343
- teardownTeamSyncRender(actions, [
18344
- list,
18345
- joinRequests,
18346
- discoveredList
18347
- ]);
19407
+ teardownTeamSyncRender(actions, [joinRequests, discoveredList]);
18348
19408
  const actionMount = document.createElement("div");
18349
19409
  actionMount.id = TEAM_SYNC_ACTIONS_MOUNT_ID;
18350
19410
  actions.appendChild(actionMount);
@@ -18356,19 +19416,24 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18356
19416
  invitePanelOpen: teamInvitePanelOpen,
18357
19417
  inviteRestoreParent,
18358
19418
  joinPanel,
19419
+ joinPanelOpen: teamJoinPanelOpen,
18359
19420
  joinRestoreParent,
18360
19421
  onToggleInvitePanel: () => {
18361
19422
  if (!invitePanel) return;
18362
19423
  setTeamInvitePanelOpen(!teamInvitePanelOpen);
18363
19424
  renderTeamSync();
18364
19425
  },
19426
+ onToggleJoinPanel: () => {
19427
+ if (!joinPanel) return;
19428
+ setTeamJoinPanelOpen(!teamJoinPanelOpen);
19429
+ renderTeamSync();
19430
+ },
18365
19431
  pairedPeerCount: Number(coordinator.paired_peer_count || 0),
18366
19432
  presenceStatus
18367
19433
  }),
18368
19434
  discoveredListMount: discoveredList,
18369
19435
  discoveredRows: visibleDiscoveredRows,
18370
19436
  joinRequestsMount: joinRequests,
18371
- listMount: list,
18372
19437
  onApproveJoinRequest: async () => null,
18373
19438
  onAttentionAction: async (item) => {
18374
19439
  if (item.kind === "possible-duplicate-person") {
@@ -18471,8 +19536,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18471
19536
  }
18472
19537
  },
18473
19538
  pendingJoinRequests,
18474
- presenceStatus,
18475
- statusSummary
19539
+ presenceStatus
18476
19540
  }));
18477
19541
  }
18478
19542
  //#endregion
@@ -18684,9 +19748,20 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18684
19748
  renderSyncDiagnosticsUnavailable();
18685
19749
  }
18686
19750
  }
19751
+ /**
19752
+ * Called after `/api/projects` resolves (see app.ts loadProjects) so the
19753
+ * Sync peer-scope picker rerenders with the freshly-cached project names.
19754
+ * Without this, loadSyncData's dedup hash would skip the next render when
19755
+ * the underlying sync payload hasn't changed, leaving the scope picker's
19756
+ * clickable project list stuck on whatever was cached at first paint.
19757
+ */
19758
+ function invalidateSyncPeerScopeCache() {
19759
+ lastSyncHash = "";
19760
+ if (state.lastSyncPeers?.length) renderSyncPeers();
19761
+ }
18687
19762
  async function loadPairingData() {
18688
19763
  try {
18689
- state.pairingPayloadRaw = await loadPairing(!isSyncRedactionEnabled()) || null;
19764
+ state.pairingPayloadRaw = await loadPairing() || null;
18690
19765
  renderPairing();
18691
19766
  } catch {
18692
19767
  state.pairingPayloadRaw = null;
@@ -18702,6 +19777,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18702
19777
  initTeamSyncEvents(refreshCallback, loadSyncData);
18703
19778
  initPeopleEvents(loadSyncData);
18704
19779
  initDiagnosticsEvents(refreshCallback);
19780
+ applySyncSubView();
19781
+ ensureSyncSubViewListener();
18705
19782
  }
18706
19783
  //#endregion
18707
19784
  //#region src/app.ts
@@ -18716,7 +19793,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18716
19793
  try {
18717
19794
  const runtime = await loadRuntimeInfo();
18718
19795
  if (!runtime?.version) return;
18719
- setRuntimeLabel(runtime.version, "dc04918");
19796
+ setRuntimeLabel(runtime.version, "c411f68");
18720
19797
  } catch {}
18721
19798
  }
18722
19799
  var lastAnnouncedRefreshState = null;
@@ -18738,14 +19815,6 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18738
19815
  return false;
18739
19816
  }
18740
19817
  }
18741
- function stopReconnectLoop() {
18742
- if (reconnectTimer) {
18743
- clearTimeout(reconnectTimer);
18744
- reconnectTimer = null;
18745
- }
18746
- reconnecting = false;
18747
- setReconnectOverlay(false);
18748
- }
18749
19818
  function canResumeRefresh() {
18750
19819
  return document.visibilityState !== "hidden" && !isSettingsOpen();
18751
19820
  }
@@ -18757,12 +19826,20 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18757
19826
  setReconnectOverlay(true, "The viewer server is restarting or temporarily unavailable. Trying again automatically…");
18758
19827
  const tick = async () => {
18759
19828
  if (await isViewerReady()) {
18760
- stopReconnectLoop();
19829
+ if (reconnectTimer) {
19830
+ clearTimeout(reconnectTimer);
19831
+ reconnectTimer = null;
19832
+ }
19833
+ reconnecting = false;
19834
+ setReconnectOverlay(true, "Viewer responded. Restoring your session…");
18761
19835
  if (canResumeRefresh()) {
18762
19836
  setRefreshStatus("refreshing");
18763
19837
  startPolling();
18764
- doRefresh();
19838
+ try {
19839
+ await doRefresh();
19840
+ } catch {}
18765
19841
  } else setRefreshStatus("paused", document.visibilityState === "hidden" ? "(tab hidden)" : "(settings open)");
19842
+ if (!reconnecting) setReconnectOverlay(false);
18766
19843
  return;
18767
19844
  }
18768
19845
  setReconnectOverlay(true, "Still reconnecting… the viewer will recover automatically as soon as the server responds.");
@@ -18846,14 +19923,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18846
19923
  $(`tabBtn-${id}`)?.addEventListener("click", () => switchTab(id));
18847
19924
  });
18848
19925
  window.addEventListener("hashchange", () => {
18849
- const hash = window.location.hash.replace("#", "");
18850
- if (ALL_TAB_IDS.includes(hash) && hash !== state.activeTab) switchTab(hash);
19926
+ const top = parseTabFromHash();
19927
+ if (top && top !== state.activeTab) switchTab(top);
18851
19928
  });
18852
19929
  switchTab(state.activeTab);
18853
19930
  }
18854
19931
  async function loadProjects() {
18855
19932
  try {
18856
19933
  const projects = await loadProjects$1();
19934
+ state.knownProjects = projects;
19935
+ invalidateSyncPeerScopeCache();
18857
19936
  const projectFilter = $select("projectFilter");
18858
19937
  if (!projectFilter) return;
18859
19938
  projectFilter.textContent = "";
@@ -18947,9 +20026,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18947
20026
  scheduleReconnectLoop();
18948
20027
  return;
18949
20028
  }
18950
- stopReconnectLoop();
20029
+ if (reconnectTimer) {
20030
+ clearTimeout(reconnectTimer);
20031
+ reconnectTimer = null;
20032
+ }
20033
+ reconnecting = false;
20034
+ setReconnectOverlay(true, "Viewer responded. Restoring your session…");
18951
20035
  startPolling();
18952
- doRefresh();
20036
+ try {
20037
+ await doRefresh();
20038
+ } catch {}
20039
+ if (!reconnecting) setReconnectOverlay(false);
18953
20040
  });
18954
20041
  loadRuntimeLabel();
18955
20042
  refresh();