@codemem/server 0.33.0-alpha.2 → 0.33.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
@@ -3509,6 +3509,71 @@
3509
3509
  }, 1200);
3510
3510
  }
3511
3511
  //#endregion
3512
+ //#region src/lib/keyboard.ts
3513
+ var FORM_CONTROL_TAGS = new Set([
3514
+ "BUTTON",
3515
+ "A",
3516
+ "SELECT"
3517
+ ]);
3518
+ var INPUT_TYPES_WITH_NATIVE_ENTER = new Set([
3519
+ "button",
3520
+ "checkbox",
3521
+ "color",
3522
+ "file",
3523
+ "image",
3524
+ "radio",
3525
+ "range",
3526
+ "reset",
3527
+ "submit"
3528
+ ]);
3529
+ function shouldIgnoreTarget(target) {
3530
+ if (!target) return false;
3531
+ if (typeof target.closest !== "function") return false;
3532
+ return target.closest("[data-primary-action-ignore=\"true\"]") !== null;
3533
+ }
3534
+ function isTextareaOrEditable(target) {
3535
+ if (!target) return false;
3536
+ if (target instanceof HTMLTextAreaElement) return true;
3537
+ if ("isContentEditable" in target && target.isContentEditable) return true;
3538
+ return false;
3539
+ }
3540
+ function hasNativeEnterBehavior(target) {
3541
+ if (!target) return false;
3542
+ if (FORM_CONTROL_TAGS.has(target.tagName)) return true;
3543
+ return target instanceof HTMLInputElement && INPUT_TYPES_WITH_NATIVE_ENTER.has(target.type);
3544
+ }
3545
+ function hasPrimaryModifier(event) {
3546
+ return event.metaKey || event.ctrlKey;
3547
+ }
3548
+ /**
3549
+ * Handle a keydown event according to the primary-action conventions
3550
+ * documented at the top of this module.
3551
+ *
3552
+ * This function is a pure helper: it inspects the event, decides whether to
3553
+ * fire `onSubmit` or `onCancel`, and calls `event.preventDefault()` when it
3554
+ * acts. It never mutates DOM state directly. Callers should attach it to the
3555
+ * scope that owns the primary action (modal card, form element, inline
3556
+ * editor row).
3557
+ */
3558
+ function handlePrimaryActionKeyboard(event, options) {
3559
+ if (options.disabled) return;
3560
+ if (event.defaultPrevented) return;
3561
+ if (event.isComposing) return;
3562
+ if (event.key !== "Enter" && event.key !== "Escape") return;
3563
+ const target = event.target instanceof HTMLElement ? event.target : null;
3564
+ if (shouldIgnoreTarget(target)) return;
3565
+ if (event.key === "Escape") {
3566
+ if (!options.onCancel) return;
3567
+ event.preventDefault();
3568
+ options.onCancel();
3569
+ return;
3570
+ }
3571
+ if (hasNativeEnterBehavior(target)) return;
3572
+ if (isTextareaOrEditable(target) && !hasPrimaryModifier(event)) return;
3573
+ event.preventDefault();
3574
+ options.onSubmit();
3575
+ }
3576
+ //#endregion
3512
3577
  //#region src/lib/state.ts
3513
3578
  var ALL_TAB_IDS = [
3514
3579
  "feed",
@@ -4146,10 +4211,18 @@
4146
4211
  const pending = coordinatorAdminState.deviceActionPendingId === deviceId;
4147
4212
  const draft = coordinatorAdminState.deviceRenameDrafts.get(deviceId) ?? String(item.display_name || "");
4148
4213
  const enabled = item.enabled !== false && item.enabled !== 0;
4214
+ const actionDisabled = !deviceId || pending || summary.readiness !== "ready";
4149
4215
  return _$3("div", {
4150
4216
  class: "peer-card peer-card--padded",
4151
4217
  key: deviceId || String(item.fingerprint || "unknown")
4152
- }, _$3("div", { class: "peer-title" }, _$3("strong", null, draft || displayName)), _$3("div", { class: "peer-submeta" }, copy.statusLabel), _$3("div", { class: "peer-meta" }, copy.advancedDetail), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
4218
+ }, _$3("div", { class: "peer-title" }, _$3("strong", null, draft || displayName)), _$3("div", { class: "peer-submeta" }, copy.statusLabel), _$3("div", { class: "peer-meta" }, copy.advancedDetail), _$3("form", {
4219
+ class: "coordinator-admin-form",
4220
+ onSubmit: (event) => {
4221
+ event.preventDefault();
4222
+ if (actionDisabled) return;
4223
+ runDevice(deviceId, teamId, displayName, "rename");
4224
+ }
4225
+ }, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
4153
4226
  class: "peer-scope-input",
4154
4227
  disabled: summary.readiness !== "ready" || pending,
4155
4228
  onInput: (event) => {
@@ -4159,25 +4232,24 @@
4159
4232
  value: draft
4160
4233
  }))), _$3("div", { class: "peer-actions" }, _$3("button", {
4161
4234
  class: "settings-button",
4162
- disabled: !deviceId || pending || summary.readiness !== "ready",
4163
- onClick: () => runDevice(deviceId, teamId, displayName, "rename"),
4164
- type: "button"
4235
+ disabled: actionDisabled,
4236
+ type: "submit"
4165
4237
  }, pending && coordinatorAdminState.deviceActionPendingKind === "rename" ? "Renaming…" : "Rename"), enabled ? _$3("button", {
4166
4238
  class: "settings-button danger",
4167
- disabled: !deviceId || pending || summary.readiness !== "ready",
4239
+ disabled: actionDisabled,
4168
4240
  onClick: () => runDevice(deviceId, teamId, displayName, "disable"),
4169
4241
  type: "button"
4170
4242
  }, pending && coordinatorAdminState.deviceActionPendingKind === "disable" ? "Disabling…" : "Disable") : _$3("button", {
4171
4243
  class: "settings-button",
4172
- disabled: !deviceId || pending || summary.readiness !== "ready",
4244
+ disabled: actionDisabled,
4173
4245
  onClick: () => runDevice(deviceId, teamId, displayName, "enable"),
4174
4246
  type: "button"
4175
4247
  }, pending && coordinatorAdminState.deviceActionPendingKind === "enable" ? "Enabling…" : "Enable"), _$3("button", {
4176
4248
  class: "settings-button danger",
4177
- disabled: !deviceId || pending || summary.readiness !== "ready",
4249
+ disabled: actionDisabled,
4178
4250
  onClick: () => runDevice(deviceId, teamId, displayName, "remove"),
4179
4251
  type: "button"
4180
- }, pending && coordinatorAdminState.deviceActionPendingKind === "remove" ? "Removing…" : "Remove")));
4252
+ }, pending && coordinatorAdminState.deviceActionPendingKind === "remove" ? "Removing…" : "Remove"))));
4181
4253
  })));
4182
4254
  }
4183
4255
  //#endregion
@@ -9731,6 +9803,23 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9731
9803
  label: `${actor.label}${actor.isLocal ? " (You)" : ""}`,
9732
9804
  value: actor.actorId
9733
9805
  }));
9806
+ const mergeReady = Boolean(primary?.actorId && secondary?.actorId);
9807
+ const submitMerge = () => {
9808
+ if (!primary?.actorId || !secondary?.actorId) return;
9809
+ resolveCurrentDialog({
9810
+ action: "merge",
9811
+ primaryActorId: primary.actorId,
9812
+ secondaryActorId: secondary.actorId
9813
+ });
9814
+ };
9815
+ const submitMergeFromRadioKey = (event) => {
9816
+ const target = event.target instanceof HTMLElement ? event.target : null;
9817
+ if (event.defaultPrevented || event.isComposing || event.key !== "Enter") return;
9818
+ if (!target?.closest(".sync-dialog-radio-list")) return;
9819
+ if (!mergeReady) return;
9820
+ event.preventDefault();
9821
+ submitMerge();
9822
+ };
9734
9823
  return step === "choice" ? /* @__PURE__ */ u("div", {
9735
9824
  className: "sync-dialog-stack",
9736
9825
  children: /* @__PURE__ */ u("ul", {
@@ -9739,6 +9828,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9739
9828
  /* @__PURE__ */ u("li", { children: /* @__PURE__ */ u("button", {
9740
9829
  autoFocus: true,
9741
9830
  className: "settings-button",
9831
+ "data-primary-action": "true",
9742
9832
  "data-sync-primary-action": "true",
9743
9833
  onClick: () => setStep("merge"),
9744
9834
  type: "button",
@@ -9760,6 +9850,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9760
9850
  })
9761
9851
  }) : /* @__PURE__ */ u("div", {
9762
9852
  className: "sync-dialog-stack",
9853
+ onKeyDown: (event) => {
9854
+ submitMergeFromRadioKey(event);
9855
+ handlePrimaryActionKeyboard(event, {
9856
+ onSubmit: submitMerge,
9857
+ disabled: !mergeReady
9858
+ });
9859
+ },
9763
9860
  children: [
9764
9861
  /* @__PURE__ */ u("div", {
9765
9862
  className: "small",
@@ -9808,15 +9905,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
9808
9905
  children: "Back"
9809
9906
  }), /* @__PURE__ */ u("button", {
9810
9907
  className: "settings-button",
9811
- disabled: !primary?.actorId || !secondary?.actorId,
9812
- onClick: () => {
9813
- if (!primary?.actorId || !secondary?.actorId) return;
9814
- resolveCurrentDialog({
9815
- action: "merge",
9816
- primaryActorId: primary.actorId,
9817
- secondaryActorId: secondary.actorId
9818
- });
9819
- },
9908
+ "data-primary-action": "true",
9909
+ disabled: !mergeReady,
9910
+ onClick: submitMerge,
9820
9911
  type: "button",
9821
9912
  children: "Combine people"
9822
9913
  })]
@@ -10366,7 +10457,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10366
10457
  loadGroupScopeManagement(groupId, renderShell, checked);
10367
10458
  },
10368
10459
  thumbClassName: "coordinator-admin-switch-thumb"
10369
- })), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New Space id"), _$3(TextInput, {
10460
+ })), _$3("form", {
10461
+ class: "coordinator-admin-form",
10462
+ onSubmit: (event) => {
10463
+ event.preventDefault();
10464
+ if (disabled) return;
10465
+ createScope(groupId, renderShell);
10466
+ }
10467
+ }, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New Space id"), _$3(TextInput, {
10370
10468
  class: "peer-scope-input",
10371
10469
  disabled,
10372
10470
  onInput: (event) => {
@@ -10405,14 +10503,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10405
10503
  }))), _$3("div", { class: "peer-actions" }, _$3("button", {
10406
10504
  class: "settings-button",
10407
10505
  disabled,
10408
- onClick: () => void createScope(groupId, renderShell),
10409
- type: "button"
10506
+ type: "submit"
10410
10507
  }, draft.actionPendingKind === "create" ? "Creating…" : "Create Space"), _$3("button", {
10411
10508
  class: "settings-button",
10412
10509
  disabled,
10413
10510
  onClick: () => void loadGroupScopeManagement(groupId, renderShell, draft.includeInactive),
10414
10511
  type: "button"
10415
- }, draft.loading ? "Refreshing…" : "Refresh")), draft.error ? _$3("div", { class: "peer-submeta coordinator-admin-error" }, draft.error) : null, draft.scopes.length ? _$3("div", { class: "coordinator-admin-scope-card-list" }, draft.scopes.map((scope) => renderScopeCard(groupId, scope, draft, ready, renderShell))) : _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, "No Spaces are defined for this Team yet. Create a Space, then grant specific devices. Projects stay local-only until assigned to a Space."));
10512
+ }, draft.loading ? "Refreshing…" : "Refresh"))), draft.error ? _$3("div", { class: "peer-submeta coordinator-admin-error" }, draft.error) : null, draft.scopes.length ? _$3("div", { class: "coordinator-admin-scope-card-list" }, draft.scopes.map((scope) => renderScopeCard(groupId, scope, draft, ready, renderShell))) : _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, "No Spaces are defined for this Team yet. Create a Space, then grant specific devices. Projects stay local-only until assigned to a Space."));
10416
10513
  }
10417
10514
  //#endregion
10418
10515
  //#region src/tabs/coordinator-admin/components/groups-panel.ts
@@ -10650,43 +10747,52 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10650
10747
  return _$3(RadixTabsContent, {
10651
10748
  className: "coordinator-admin-panel",
10652
10749
  value: "groups"
10653
- }, _$3("h3", null, "Teams"), _$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 Team below to manage it.` : "No Team selected yet. Create one or select an existing Team 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 Team (${selectedGroup}) is configured locally but does not exist in the coordinator yet. Create it below or switch to another Team once one exists.`) : null, renderTeamSetupGuide(renderShell), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New Team id"), _$3(TextInput, {
10654
- class: "peer-scope-input",
10655
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
10656
- onInput: (event) => {
10657
- coordinatorAdminState.createGroupId = String(event.currentTarget.value || "");
10658
- },
10659
- placeholder: "team-alpha",
10660
- type: "text",
10661
- value: coordinatorAdminState.createGroupId
10662
- })), _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
10663
- class: "peer-scope-input",
10664
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
10665
- onInput: (event) => {
10666
- coordinatorAdminState.createGroupDisplayName = String(event.currentTarget.value || "");
10667
- },
10668
- placeholder: "Team Alpha",
10669
- type: "text",
10670
- value: coordinatorAdminState.createGroupDisplayName
10671
- }))), _$3("div", { class: "section-actions coordinator-admin-groups-toolbar" }, _$3("div", { class: "coordinator-admin-primary-actions" }, _$3("button", {
10672
- class: "settings-button",
10673
- disabled: summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create",
10674
- onClick: () => createGroup(),
10675
- type: "button"
10676
- }, coordinatorAdminState.groupActionPendingKind === "create" ? "Creating…" : "Create Team")), _$3("div", { class: "coordinator-admin-secondary-actions" }, _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
10677
- class: "section-meta",
10678
- id: "coordinatorAdminShowArchivedLabel"
10679
- }, "Show archived"), _$3(RadixSwitch, {
10680
- "aria-labelledby": "coordinatorAdminShowArchivedLabel",
10681
- checked: coordinatorAdminState.showArchivedGroups,
10682
- className: "coordinator-admin-switch",
10683
- disabled: summary.readiness !== "ready",
10684
- onCheckedChange: (checked) => {
10685
- coordinatorAdminState.showArchivedGroups = checked;
10686
- renderShell();
10687
- },
10688
- thumbClassName: "coordinator-admin-switch-thumb"
10689
- })))), !visibleGroups.length ? _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, summary.readiness === "ready" ? coordinatorAdminState.showArchivedGroups ? "No Teams are available yet." : "No active Teams yet. Create one to get started." : "Team browsing will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, visibleGroups.map((group) => {
10750
+ }, _$3("h3", null, "Teams"), _$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 Team below to manage it.` : "No Team selected yet. Create one or select an existing Team 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 Team (${selectedGroup}) is configured locally but does not exist in the coordinator yet. Create it below or switch to another Team once one exists.`) : null, renderTeamSetupGuide(renderShell), (() => {
10751
+ const createGroupDisabled = summary.readiness !== "ready" || coordinatorAdminState.groupActionPendingKind === "create";
10752
+ return _$3("form", {
10753
+ class: "coordinator-admin-form",
10754
+ onSubmit: (event) => {
10755
+ event.preventDefault();
10756
+ if (createGroupDisabled) return;
10757
+ createGroup();
10758
+ }
10759
+ }, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "New Team id"), _$3(TextInput, {
10760
+ class: "peer-scope-input",
10761
+ disabled: createGroupDisabled,
10762
+ onInput: (event) => {
10763
+ coordinatorAdminState.createGroupId = String(event.currentTarget.value || "");
10764
+ },
10765
+ placeholder: "team-alpha",
10766
+ type: "text",
10767
+ value: coordinatorAdminState.createGroupId
10768
+ })), _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Display name"), _$3(TextInput, {
10769
+ class: "peer-scope-input",
10770
+ disabled: createGroupDisabled,
10771
+ onInput: (event) => {
10772
+ coordinatorAdminState.createGroupDisplayName = String(event.currentTarget.value || "");
10773
+ },
10774
+ placeholder: "Team Alpha",
10775
+ type: "text",
10776
+ value: coordinatorAdminState.createGroupDisplayName
10777
+ }))), _$3("div", { class: "section-actions coordinator-admin-groups-toolbar" }, _$3("div", { class: "coordinator-admin-primary-actions" }, _$3("button", {
10778
+ class: "settings-button",
10779
+ disabled: createGroupDisabled,
10780
+ type: "submit"
10781
+ }, coordinatorAdminState.groupActionPendingKind === "create" ? "Creating…" : "Create Team")), _$3("div", { class: "coordinator-admin-secondary-actions" }, _$3("label", { class: "coordinator-admin-inline-filter" }, _$3("span", {
10782
+ class: "section-meta",
10783
+ id: "coordinatorAdminShowArchivedLabel"
10784
+ }, "Show archived"), _$3(RadixSwitch, {
10785
+ "aria-labelledby": "coordinatorAdminShowArchivedLabel",
10786
+ checked: coordinatorAdminState.showArchivedGroups,
10787
+ className: "coordinator-admin-switch",
10788
+ disabled: summary.readiness !== "ready",
10789
+ onCheckedChange: (checked) => {
10790
+ coordinatorAdminState.showArchivedGroups = checked;
10791
+ renderShell();
10792
+ },
10793
+ thumbClassName: "coordinator-admin-switch-thumb"
10794
+ })))));
10795
+ })(), !visibleGroups.length ? _$3("div", { class: "peer-meta coordinator-admin-empty-state" }, summary.readiness === "ready" ? coordinatorAdminState.showArchivedGroups ? "No Teams are available yet." : "No active Teams yet. Create one to get started." : "Team browsing will appear here once setup is complete.") : _$3("div", { class: "peer-list" }, visibleGroups.map((group) => {
10690
10796
  const selected = group.group_id === selectedGroup;
10691
10797
  const pending = coordinatorAdminState.groupActionPendingId === group.group_id;
10692
10798
  const archived = Boolean(group.archived_at);
@@ -10800,10 +10906,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10800
10906
  const effectiveGroup = coordinatorAdminState.inviteGroup.trim() || activeGroup;
10801
10907
  const output = String(state.lastTeamInvite?.encoded || "").trim();
10802
10908
  const warnings = Array.isArray(state.lastTeamInvite?.warnings) ? state.lastTeamInvite?.warnings : [];
10909
+ const inviteDisabled = summary.readiness !== "ready" || coordinatorAdminState.invitePending;
10803
10910
  return _$3(RadixTabsContent, {
10804
10911
  className: "coordinator-admin-panel",
10805
10912
  value: "invites"
10806
- }, _$3("h3", null, "Create teammate invite"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Generate an invite for the selected Team. Default Space access is controlled by that Team's auto-grant setting." : "Finish setup first. Invite creation stays disabled until the local coordinator admin configuration is ready."), _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Team"), _$3(TextInput, {
10913
+ }, _$3("h3", null, "Create teammate invite"), _$3("p", { class: "peer-submeta" }, summary.readiness === "ready" ? "Generate an invite for the selected Team. Default Space access is controlled by that Team's auto-grant setting." : "Finish setup first. Invite creation stays disabled until the local coordinator admin configuration is ready."), _$3("form", {
10914
+ class: "coordinator-admin-form",
10915
+ onSubmit: (event) => {
10916
+ event.preventDefault();
10917
+ if (inviteDisabled) return;
10918
+ createInvite();
10919
+ }
10920
+ }, _$3("div", { class: "coordinator-admin-form-grid" }, _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Team"), _$3(TextInput, {
10807
10921
  class: "peer-scope-input",
10808
10922
  disabled: summary.readiness !== "ready",
10809
10923
  onInput: (event) => {
@@ -10844,12 +10958,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10844
10958
  value: coordinatorAdminState.inviteTtlHours
10845
10959
  }))), _$3("div", { class: "section-actions" }, _$3("button", {
10846
10960
  class: "settings-button",
10847
- disabled: summary.readiness !== "ready" || coordinatorAdminState.invitePending,
10848
- onClick: () => {
10849
- createInvite();
10850
- },
10851
- type: "button"
10852
- }, coordinatorAdminState.invitePending ? "Creating…" : "Create invite"), effectiveGroup ? _$3("span", { class: "peer-submeta" }, `Using Team ${effectiveGroup}`) : null), output ? _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Generated invite"), _$3(TextArea, {
10961
+ disabled: inviteDisabled,
10962
+ type: "submit"
10963
+ }, coordinatorAdminState.invitePending ? "Creating…" : "Create invite"), effectiveGroup ? _$3("span", { class: "peer-submeta" }, `Using Team ${effectiveGroup}`) : null)), output ? _$3("label", { class: "coordinator-admin-field" }, _$3("span", null, "Generated invite"), _$3(TextArea, {
10853
10964
  class: "feed-search coordinator-admin-output",
10854
10965
  readOnly: true,
10855
10966
  value: output
@@ -13567,6 +13678,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13567
13678
  const tagContent = tags.length ? ` · ${tags.map((t) => formatTagLabel(t)).join(", ")}` : "";
13568
13679
  const fileContent = files.length ? ` · ${formatFileList(files)}` : "";
13569
13680
  const memoryId = Number(item.id || 0);
13681
+ const memoryIdLabel = memoryId > 0 ? `ID ${memoryId}` : "";
13570
13682
  const [isNew, setIsNew] = d$2(state.newItemKeys.has(rowKey));
13571
13683
  const summaryObj = isSessionSummary ? getSummaryObject({
13572
13684
  ...item,
@@ -13743,7 +13855,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13743
13855
  }), _$3(ProvenanceChip, {
13744
13856
  label: visibility || "private",
13745
13857
  variant: visibility || "private"
13746
- })), _$3("div", { className: "feed-meta" }, metaText || "No tags, files, or provenance details attached."), bodyContent, _$3("div", { className: "feed-footer" }, _$3("div", { className: "feed-footer-left" }, tags.length ? _$3("div", { className: "feed-tags" }, tags.map((tag, index) => _$3(TagChip, {
13858
+ }), memoryIdLabel ? _$3(Tooltip, {
13859
+ label: `Memory database id ${memoryId}`,
13860
+ side: "top"
13861
+ }, _$3(ProvenanceChip, {
13862
+ label: memoryIdLabel,
13863
+ variant: "memory-id"
13864
+ })) : null), _$3("div", { className: "feed-meta" }, metaText || "No tags, files, or provenance details attached."), bodyContent, _$3("div", { className: "feed-footer" }, _$3("div", { className: "feed-footer-left" }, tags.length ? _$3("div", { className: "feed-tags" }, tags.map((tag, index) => _$3(TagChip, {
13747
13865
  key: `${String(tag)}-${index}`,
13748
13866
  tag
13749
13867
  }))) : null, item.owned_by_self && memoryId > 0 ? _$3("div", { className: "feed-visibility-controls" }, _$3("select", {
@@ -14616,6 +14734,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14616
14734
  ["needs_attention", "Needs review"],
14617
14735
  ["suggested", "Has suggestion"],
14618
14736
  ["local_only", "Stays on this device"],
14737
+ ["received", "Received from peers"],
14619
14738
  ["explicitly_mapped", "Already assigned"],
14620
14739
  ["legacy_review", "Older shared data"],
14621
14740
  ["unmapped", "Missing project identity"]
@@ -14627,6 +14746,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14627
14746
  var openProjectDetails = /* @__PURE__ */ new Set();
14628
14747
  var openProjectClusters = /* @__PURE__ */ new Set();
14629
14748
  var draftDomainSelections = /* @__PURE__ */ new Map();
14749
+ var draftClusterDomainSelections = /* @__PURE__ */ new Map();
14630
14750
  var pendingConfirmations = /* @__PURE__ */ new Map();
14631
14751
  var pendingForgetConfirmations = /* @__PURE__ */ new Map();
14632
14752
  var skippedProjectRefreshForActiveSelect = false;
@@ -14645,6 +14765,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14645
14765
  default: return "stays on this device";
14646
14766
  }
14647
14767
  }
14768
+ function isPeerReceivedProject(project) {
14769
+ return project.read_only === true && project.read_only_reason === "peer_received";
14770
+ }
14771
+ function isLocallyAssignableProject(project) {
14772
+ return project.identity_source !== "unmapped" && !isPeerReceivedProject(project);
14773
+ }
14774
+ function projectDomainLabel(project) {
14775
+ return isPeerReceivedProject(project) ? "Received from peers" : scopeSummary(project.resolved_scope_id);
14776
+ }
14777
+ function projectResolutionLabel(project) {
14778
+ return isPeerReceivedProject(project) ? "source-owned project" : formatResolution(project.resolution_reason);
14779
+ }
14648
14780
  function formatLatest(value) {
14649
14781
  if (!value) return "No recent sessions";
14650
14782
  const date = new Date(value);
@@ -14823,7 +14955,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14823
14955
  }
14824
14956
  }
14825
14957
  async function saveProjectClusterMapping(projects, scopeId) {
14826
- const assignable = projects.filter((project) => project.identity_source !== "unmapped");
14958
+ const assignable = projects.filter(isLocallyAssignableProject);
14827
14959
  if (assignable.length === 0) return;
14828
14960
  try {
14829
14961
  await saveSharingDomainProjectMappings({ mappings: assignable.map((project) => ({
@@ -14833,6 +14965,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14833
14965
  workspace_identity: project.workspace_identity
14834
14966
  })) });
14835
14967
  showGlobalNotice(`Updated ${assignable.length} project identit${assignable.length === 1 ? "y" : "ies"}. Device access grants are unchanged.`);
14968
+ draftClusterDomainSelections.delete(projectClusterKey(assignable[0]));
14836
14969
  refreshProjects?.();
14837
14970
  } catch (error) {
14838
14971
  showGlobalNotice(error instanceof SharingDomainGuardrailConfirmationError ? "One or more identities in this group need review before bulk assignment. Expand the group and save those identities directly." : error instanceof Error ? error.message : "Unable to update project Spaces.", "warning");
@@ -14911,6 +15044,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14911
15044
  function renderProjectActions(project) {
14912
15045
  const actions = document.createElement("div");
14913
15046
  actions.className = "project-inventory-actions";
15047
+ if (isPeerReceivedProject(project)) {
15048
+ const note = document.createElement("div");
15049
+ note.className = "settings-note";
15050
+ note.textContent = "This project was received from a peer. Change its project or Space on the source device; this node keeps the received identity read-only.";
15051
+ actions.appendChild(note);
15052
+ return actions;
15053
+ }
14914
15054
  if (project.identity_source === "unmapped") {
14915
15055
  const note = document.createElement("div");
14916
15056
  note.className = "settings-note";
@@ -15055,13 +15195,19 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15055
15195
  header.appendChild(title);
15056
15196
  const domain = document.createElement("div");
15057
15197
  domain.className = "project-inventory-domain";
15058
- domain.textContent = scopeSummary(project.resolved_scope_id);
15198
+ domain.textContent = projectDomainLabel(project);
15059
15199
  header.appendChild(domain);
15060
15200
  row.appendChild(header);
15061
15201
  const meta = document.createElement("div");
15062
15202
  meta.className = "project-inventory-meta";
15063
- meta.textContent = `${formatResolution(project.resolution_reason)} · ${project.identity_source} · ${formatLatest(project.latest_session_at)}`;
15203
+ meta.textContent = `${projectResolutionLabel(project)} · ${project.identity_source} · ${formatLatest(project.latest_session_at)}`;
15064
15204
  row.appendChild(meta);
15205
+ if (isPeerReceivedProject(project)) {
15206
+ const receivedNote = document.createElement("div");
15207
+ receivedNote.className = "settings-note";
15208
+ receivedNote.textContent = "Received memories keep the source device's project and Space assignment. Local reassignment controls are disabled here to avoid split-brain sync state.";
15209
+ row.appendChild(receivedNote);
15210
+ }
15065
15211
  const signal = document.createElement("div");
15066
15212
  signal.className = "project-inventory-signal mono";
15067
15213
  signal.textContent = strongestSignal(project);
@@ -15072,7 +15218,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15072
15218
  suggestion.textContent = project.suggestion_reason ? `Suggestion: ${project.suggestion_reason}` : `Suggestion: assign this project to ${scopeSummary(project.suggested_scope_id)}.`;
15073
15219
  row.appendChild(suggestion);
15074
15220
  }
15075
- const warnings = project.guardrail_warnings.filter((warning) => warning.severity === "warning");
15221
+ const warnings = (project.guardrail_warnings ?? []).filter((warning) => warning.severity === "warning");
15076
15222
  if (warnings.length > 0) {
15077
15223
  const warningBox = document.createElement("div");
15078
15224
  warningBox.className = "settings-note project-attention-note";
@@ -15108,7 +15254,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15108
15254
  ["CWD", project.cwd],
15109
15255
  ["Git remote", project.git_remote],
15110
15256
  ["Git branch", project.git_branch],
15111
- ["Current Space", scopeSummary(project.resolved_scope_id)],
15257
+ ["Current Space", projectDomainLabel(project)],
15112
15258
  ["Suggested Space", project.suggested_scope_id ? scopeSummary(project.suggested_scope_id) : null],
15113
15259
  ["Advanced: current Space ID", project.resolved_scope_id],
15114
15260
  ["Advanced: suggested Space ID", project.suggested_scope_id],
@@ -15129,8 +15275,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15129
15275
  return row;
15130
15276
  }
15131
15277
  function clusterDomainLabel(projects) {
15132
- const uniqueScopes = [...new Set(projects.map((project) => project.resolved_scope_id))];
15133
- return uniqueScopes.length === 1 ? scopeSummary(uniqueScopes[0]) : "Mixed Spaces";
15278
+ const uniqueLabels = [...new Set(projects.map((project) => projectDomainLabel(project)))];
15279
+ return uniqueLabels.length === 1 ? uniqueLabels[0] : "Mixed Spaces";
15134
15280
  }
15135
15281
  function renderProjectCluster(projects) {
15136
15282
  if (projects.length === 1) return renderProjectRow(projects[0]);
@@ -15156,36 +15302,47 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15156
15302
  row.appendChild(meta);
15157
15303
  const actions = document.createElement("div");
15158
15304
  actions.className = "project-inventory-actions";
15159
- const hasGuardrailWarnings = projects.some((project) => project.guardrail_warnings.length > 0);
15160
- const suggestedScopes = new Set(projects.map((project) => project.suggested_scope_id).filter((scopeId) => Boolean(scopeId)));
15161
- const resolvedScopes = new Set(projects.map((project) => project.resolved_scope_id));
15162
- const select = document.createElement("select");
15163
- select.className = "project-domain-select";
15164
- select.setAttribute("aria-label", `Space for ${projectClusterLabel(projects[0])} group`);
15165
- const placeholder = document.createElement("option");
15166
- placeholder.value = "";
15167
- placeholder.textContent = "Choose Space…";
15168
- select.appendChild(placeholder);
15169
- appendAssignableScopeOptions(select);
15170
- select.value = "";
15171
- const save = document.createElement("button");
15172
- save.className = "settings-button";
15173
- save.type = "button";
15174
- save.textContent = `Save Space for ${projects.length} identities`;
15175
- save.disabled = true;
15176
- save.addEventListener("click", () => void saveProjectClusterMapping(projects, select.value));
15177
- select.addEventListener("change", () => {
15178
- save.disabled = !select.value || hasGuardrailWarnings;
15179
- });
15180
- select.addEventListener("blur", refreshSkippedProjectDataAfterSelectBlur);
15181
- actions.append(select, save);
15182
- if (suggestedScopes.size > 1 || resolvedScopes.size > 1 || hasGuardrailWarnings) {
15305
+ const assignableProjects = projects.filter(isLocallyAssignableProject);
15306
+ if (assignableProjects.length === 0) {
15183
15307
  const note = document.createElement("div");
15184
- note.className = "settings-note project-attention-note";
15185
- note.textContent = hasGuardrailWarnings ? "One or more identities in this group need individual review before bulk assignment." : "This group has mixed suggestions or current Spaces. Choose a Space explicitly before bulk assignment.";
15308
+ note.className = "settings-note";
15309
+ note.textContent = projects.every(isPeerReceivedProject) ? "These project identities were received from peers. Change project or Space assignments on their source devices." : "These project identities cannot be bulk assigned until they have stable local identities. Expand each identity for details.";
15186
15310
  actions.appendChild(note);
15311
+ row.appendChild(actions);
15312
+ } else {
15313
+ const hasGuardrailWarnings = assignableProjects.some((project) => (project.guardrail_warnings ?? []).length > 0);
15314
+ const suggestedScopes = new Set(assignableProjects.map((project) => project.suggested_scope_id).filter((scopeId) => Boolean(scopeId)));
15315
+ const resolvedScopes = new Set(assignableProjects.map((project) => project.resolved_scope_id));
15316
+ const select = document.createElement("select");
15317
+ select.className = "project-domain-select";
15318
+ select.setAttribute("aria-label", `Space for ${projectClusterLabel(projects[0])} group`);
15319
+ const placeholder = document.createElement("option");
15320
+ placeholder.value = "";
15321
+ placeholder.textContent = "Choose Space…";
15322
+ select.appendChild(placeholder);
15323
+ appendAssignableScopeOptions(select);
15324
+ select.value = firstSafeSelection(draftClusterDomainSelections.get(clusterKey));
15325
+ const save = document.createElement("button");
15326
+ save.className = "settings-button";
15327
+ save.type = "button";
15328
+ save.textContent = `Save Space for ${assignableProjects.length} identit${assignableProjects.length === 1 ? "y" : "ies"}`;
15329
+ save.disabled = !select.value || hasGuardrailWarnings;
15330
+ save.addEventListener("click", () => void saveProjectClusterMapping(assignableProjects, select.value));
15331
+ select.addEventListener("change", () => {
15332
+ if (select.value) draftClusterDomainSelections.set(clusterKey, select.value);
15333
+ else draftClusterDomainSelections.delete(clusterKey);
15334
+ save.disabled = !select.value || hasGuardrailWarnings;
15335
+ });
15336
+ select.addEventListener("blur", refreshSkippedProjectDataAfterSelectBlur);
15337
+ actions.append(select, save);
15338
+ if (suggestedScopes.size > 1 || resolvedScopes.size > 1 || hasGuardrailWarnings) {
15339
+ const note = document.createElement("div");
15340
+ note.className = "settings-note project-attention-note";
15341
+ note.textContent = hasGuardrailWarnings ? "One or more identities in this group need individual review before bulk assignment." : "This group has mixed suggestions or current Spaces. Choose a Space explicitly before bulk assignment.";
15342
+ actions.appendChild(note);
15343
+ }
15344
+ row.appendChild(actions);
15187
15345
  }
15188
- row.appendChild(actions);
15189
15346
  const details = document.createElement("details");
15190
15347
  details.className = "project-inventory-details";
15191
15348
  details.open = openProjectClusters.has(clusterKey);
@@ -15217,10 +15374,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15217
15374
  empty.textContent = message;
15218
15375
  list.appendChild(empty);
15219
15376
  }
15377
+ function hideProjectInventorySkeleton() {
15378
+ document.getElementById("projectsInventorySkeleton")?.remove();
15379
+ }
15220
15380
  function renderProjectInventory(result) {
15221
15381
  const meta = el("projectsInventoryMeta");
15222
15382
  const list = el("projectsInventoryList");
15223
15383
  if (!meta || !list) return;
15384
+ hideProjectInventorySkeleton();
15224
15385
  list.textContent = "";
15225
15386
  if (result.projects.length === 0) renderEmpty("No projects match those filters.");
15226
15387
  else for (const cluster of projectClusters(result.projects)) list.appendChild(renderProjectCluster(cluster));
@@ -15257,6 +15418,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15257
15418
  renderProjectInventory(result);
15258
15419
  refreshProjectCoordinatorGroupNamesInBackground(result);
15259
15420
  } catch (error) {
15421
+ hideProjectInventorySkeleton();
15260
15422
  meta.textContent = "Project inventory failed to load.";
15261
15423
  renderEmpty(error instanceof Error ? error.message : "Unable to load project inventory.");
15262
15424
  }
@@ -16884,487 +17046,167 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
16884
17046
  ] });
16885
17047
  }
16886
17048
  //#endregion
16887
- //#region src/tabs/settings/components/SharingDomainsPanel.tsx
16888
- function domainLabel(scope) {
16889
- const team = scope.group_id ? `Team ${scope.group_id}` : scope.authority_type;
16890
- const qualifier = scope.authority_type === "local" ? "local" : scope.authority_type;
16891
- return `${scope.label || scope.scope_id} · ${team || qualifier}`;
16892
- }
16893
- function projectSubtitle(project) {
16894
- if (project.git_remote) return `Matched by git remote · ${project.git_remote}`;
16895
- if (project.cwd) return `Matched by path · ${project.cwd}`;
16896
- return `Matched by ${project.identity_source} · ${project.workspace_identity}`;
16897
- }
16898
- function resolutionLabel(reason) {
16899
- switch (reason) {
16900
- case "exact_mapping": return "explicit project mapping";
16901
- case "pattern_mapping": return "pattern mapping";
16902
- case "explicit_override": return "explicit override";
16903
- default: return "local-only fallback";
16904
- }
16905
- }
16906
- function scopeName(scopes, scopeId) {
16907
- return scopes.find((scope) => scope.scope_id === scopeId)?.label || scopeId;
16908
- }
16909
- function resetDrafts(settings) {
16910
- return Object.fromEntries(settings.projects.map((project) => [project.workspace_identity, project.suggested_scope_id ?? project.resolved_scope_id]));
16911
- }
16912
- function canAssignProject(project) {
16913
- return project.identity_source !== "unmapped";
16914
- }
16915
- function warningKey(warning, index) {
16916
- return [
16917
- warning.code,
16918
- warning.workspace_identity,
16919
- warning.project_pattern,
16920
- index
16921
- ].join(":");
16922
- }
16923
- function visibleProjectWarnings(project) {
16924
- return (project.guardrail_warnings ?? []).filter((warning) => warning.severity === "warning" || warning.code === "unknown_project_local_only");
16925
- }
16926
- function isUsingSuggestion(project, currentValue) {
16927
- return Boolean(project.suggested_scope_id && currentValue === project.suggested_scope_id && project.suggested_scope_id !== project.resolved_scope_id);
16928
- }
16929
- function settingsMappingWarnings(settings) {
16930
- return settings.mappings.flatMap((mapping) => mapping.guardrail_warnings ?? []);
16931
- }
16932
- function GuardrailMessages({ label = "Space assignment guardrail", warnings }) {
16933
- if (warnings.length === 0) return null;
16934
- return /* @__PURE__ */ u("div", {
16935
- "aria-label": label,
16936
- className: "settings-note",
16937
- role: "status",
16938
- children: /* @__PURE__ */ u("ul", { children: warnings.map((warning, index) => /* @__PURE__ */ u("li", { children: warning.message }, warningKey(warning, index))) })
16939
- });
16940
- }
16941
- function SharingDomainsPanel() {
16942
- const [settings, setSettings] = d$2(null);
16943
- const [drafts, setDrafts] = d$2({});
16944
- const [loading, setLoading] = d$2(false);
16945
- const [savingKey, setSavingKey] = d$2(null);
16946
- const [error, setError] = d$2(null);
16947
- const [confirmation, setConfirmation] = d$2(null);
16948
- const reload = async () => {
16949
- setLoading(true);
16950
- setError(null);
16951
- try {
16952
- const next = await loadSharingDomainSettings();
16953
- setSettings(next);
16954
- setDrafts(resetDrafts(next));
16955
- } catch (err) {
16956
- setError(err instanceof Error ? err.message : "Unable to load Spaces");
16957
- } finally {
16958
- setLoading(false);
16959
- }
16960
- };
16961
- y$2(() => {
16962
- reload();
16963
- }, []);
16964
- const scopeOptions = T$1(() => (settings?.scopes ?? []).filter((scope) => scope.scope_id !== "legacy-shared-review").map((scope) => ({
16965
- value: scope.scope_id,
16966
- label: domainLabel(scope)
16967
- })), [settings?.scopes]);
16968
- const saveProject = async (project) => {
16969
- await saveProjectWithGuardrails(project);
16970
- };
16971
- const saveProjectWithGuardrails = async (project, confirmedGuardrailTokens = []) => {
16972
- if (!canAssignProject(project)) {
16973
- setError("Unmapped projects need a stable path, git remote, or workspace id before assignment.");
16974
- return;
16975
- }
16976
- const scopeId = drafts[project.workspace_identity] ?? project.resolved_scope_id;
16977
- setSavingKey(project.workspace_identity);
16978
- setError(null);
16979
- try {
16980
- await saveSharingDomainProjectMapping({
16981
- ...project.mapping_id && project.resolution_reason === "exact_mapping" ? { id: project.mapping_id } : {},
16982
- ...confirmedGuardrailTokens.length > 0 ? { confirmed_guardrail_tokens: confirmedGuardrailTokens } : {},
16983
- workspace_identity: project.workspace_identity,
16984
- project_pattern: project.display_project,
16985
- scope_id: scopeId
16986
- });
16987
- setConfirmation(null);
16988
- showGlobalNotice("Project Space assignment updated. Device access grants are unchanged.");
16989
- await reload();
16990
- } catch (err) {
16991
- if (err instanceof SharingDomainGuardrailConfirmationError) {
16992
- setConfirmation({
16993
- workspaceIdentity: project.workspace_identity,
16994
- requiredGuardrailTokens: err.requiredGuardrailTokens,
16995
- warnings: err.guardrailWarnings
16996
- });
16997
- return;
16998
- }
16999
- setError(err instanceof Error ? err.message : "Unable to save Space assignment");
17000
- } finally {
17001
- setSavingKey(null);
17002
- }
17003
- };
17004
- const resetProject = async (project) => {
17005
- if (!project.mapping_id) return;
17006
- setSavingKey(project.workspace_identity);
17007
- setError(null);
17008
- try {
17009
- await deleteSharingDomainProjectMapping(project.mapping_id);
17010
- setConfirmation(null);
17011
- showGlobalNotice("Project Space assignment removed. The next fallback now applies.");
17012
- await reload();
17013
- } catch (err) {
17014
- setError(err instanceof Error ? err.message : "Unable to reset Space assignment");
17015
- } finally {
17016
- setSavingKey(null);
17017
- }
17018
- };
17019
- const openProjects = () => {
17020
- window.location.hash = "projects";
17021
- };
17022
- return /* @__PURE__ */ u("div", {
17049
+ //#region src/tabs/settings/components/SyncPanel.tsx
17050
+ function SyncPanel({ values, hiddenUnlessAdvanced, onTextInput, onSwitchInput, protectedConfigHelp }) {
17051
+ return /* @__PURE__ */ u(k$3, { children: [/* @__PURE__ */ u(SettingsSectionIntro, {
17052
+ detail: "Choose whether this device syncs at all, how often it checks peers, and which coordinator group it should join.",
17053
+ title: "Device sync"
17054
+ }), /* @__PURE__ */ u("div", {
17023
17055
  className: "settings-group",
17024
17056
  children: [
17025
17057
  /* @__PURE__ */ u("h3", {
17026
17058
  className: "settings-group-title",
17027
- children: "Advanced Space assignments"
17059
+ children: "Device Sync"
17060
+ }),
17061
+ /* @__PURE__ */ u(SettingsSwitchRow, {
17062
+ checked: values.syncEnabled,
17063
+ className: "field",
17064
+ id: "syncEnabled",
17065
+ label: "Enable sync",
17066
+ onCheckedChange: onSwitchInput("syncEnabled")
17028
17067
  }),
17029
17068
  /* @__PURE__ */ u("div", {
17030
- className: "small",
17031
- children: "Use Projects for day-to-day project/Space review. This fallback panel exposes the same assignment controls for troubleshooting and recovery."
17069
+ className: "field",
17070
+ children: [
17071
+ /* @__PURE__ */ u("label", {
17072
+ htmlFor: "syncInterval",
17073
+ children: "Sync interval (seconds)"
17074
+ }),
17075
+ /* @__PURE__ */ u(TextInput, {
17076
+ id: "syncInterval",
17077
+ min: "10",
17078
+ onInput: onTextInput("syncInterval"),
17079
+ type: "number",
17080
+ value: values.syncInterval
17081
+ }),
17082
+ /* @__PURE__ */ u("div", {
17083
+ className: "small",
17084
+ children: "How often this device checks for sync work when sync is enabled."
17085
+ })
17086
+ ]
17032
17087
  }),
17033
17088
  /* @__PURE__ */ u("div", {
17034
- className: "small",
17035
- children: "Saving an assignment changes local Space resolution for future writes; it does not grant any device or Team member access by itself."
17089
+ className: "field settings-advanced",
17090
+ hidden: hiddenUnlessAdvanced(),
17091
+ children: [/* @__PURE__ */ u("label", {
17092
+ htmlFor: "syncHost",
17093
+ children: "Sync host"
17094
+ }), /* @__PURE__ */ u(TextInput, {
17095
+ id: "syncHost",
17096
+ onInput: onTextInput("syncHost"),
17097
+ placeholder: "127.0.0.1",
17098
+ value: values.syncHost
17099
+ })]
17036
17100
  }),
17037
17101
  /* @__PURE__ */ u("div", {
17038
- className: "section-actions",
17039
- children: /* @__PURE__ */ u("button", {
17040
- className: "settings-button",
17041
- onClick: openProjects,
17042
- type: "button",
17043
- children: "Open Projects review"
17044
- })
17102
+ className: "field settings-advanced",
17103
+ hidden: hiddenUnlessAdvanced(),
17104
+ children: [/* @__PURE__ */ u("label", {
17105
+ htmlFor: "syncPort",
17106
+ children: "Sync port"
17107
+ }), /* @__PURE__ */ u(TextInput, {
17108
+ id: "syncPort",
17109
+ min: "1",
17110
+ onInput: onTextInput("syncPort"),
17111
+ type: "number",
17112
+ value: values.syncPort
17113
+ })]
17045
17114
  }),
17046
- settings ? /* @__PURE__ */ u(GuardrailMessages, {
17047
- label: "Space assignment warnings",
17048
- warnings: settingsMappingWarnings(settings)
17049
- }) : null,
17050
- loading && !settings ? /* @__PURE__ */ u("div", {
17051
- className: "small",
17052
- children: "Loading Spaces…"
17053
- }) : null,
17054
- error ? /* @__PURE__ */ u("div", {
17055
- className: "settings-note",
17056
- role: "alert",
17057
- children: error
17058
- }) : null,
17059
- settings && settings.projects.length === 0 ? /* @__PURE__ */ u("div", {
17060
- className: "small",
17061
- children: "No projects with memories are available yet."
17062
- }) : null,
17063
- settings?.projects.map((project, index) => {
17064
- const fieldId = `sharingDomainProject-${index}`;
17065
- const currentValue = drafts[project.workspace_identity] ?? project.resolved_scope_id;
17066
- const saving = savingKey === project.workspace_identity;
17067
- const unchanged = currentValue === project.resolved_scope_id;
17068
- const assignable = canAssignProject(project);
17069
- const currentScopeName = scopeName(settings.scopes, project.resolved_scope_id);
17070
- const usingSuggestion = isUsingSuggestion(project, currentValue);
17071
- const suggestedScopeName = project.suggested_scope_id ? scopeName(settings.scopes, project.suggested_scope_id) : null;
17072
- const pendingConfirmation = confirmation?.workspaceIdentity === project.workspace_identity ? confirmation : null;
17073
- const canRemoveProjectMapping = assignable && project.mapping_id != null && project.resolution_reason === "exact_mapping";
17074
- return /* @__PURE__ */ u("div", {
17075
- className: "field",
17076
- children: [
17077
- /* @__PURE__ */ u("label", {
17078
- htmlFor: fieldId,
17079
- children: project.display_project
17080
- }),
17081
- /* @__PURE__ */ u("div", {
17082
- className: "small",
17083
- children: projectSubtitle(project)
17084
- }),
17085
- /* @__PURE__ */ u(RadixSelect, {
17086
- ariaLabel: `Space for ${project.display_project}`,
17087
- contentClassName: "settings-select-content",
17088
- disabled: !assignable || saving || scopeOptions.length === 0,
17089
- id: fieldId,
17090
- itemClassName: "settings-select-item",
17091
- onValueChange: (value) => {
17092
- setDrafts((prev) => ({
17093
- ...prev,
17094
- [project.workspace_identity]: value
17095
- }));
17096
- if (confirmation?.workspaceIdentity === project.workspace_identity) setConfirmation(null);
17097
- },
17098
- options: scopeOptions,
17099
- placeholder: "Choose Space",
17100
- triggerClassName: "settings-select-trigger",
17101
- value: currentValue,
17102
- viewportClassName: "settings-select-viewport"
17103
- }),
17104
- /* @__PURE__ */ u("div", {
17105
- className: "small",
17106
- children: [
17107
- "Current Space: ",
17108
- currentScopeName,
17109
- " · ",
17110
- resolutionLabel(project.resolution_reason)
17111
- ]
17112
- }),
17113
- project.suggested_scope_id && project.suggestion_reason ? /* @__PURE__ */ u("div", {
17114
- className: "settings-note",
17115
- role: "status",
17116
- children: [
17117
- /* @__PURE__ */ u("strong", { children: ["Suggested mapping: ", suggestedScopeName] }),
17118
- /* @__PURE__ */ u("div", { children: project.suggestion_reason }),
17119
- /* @__PURE__ */ u("div", { children: "Folders, paths, and git remotes are hints only. Saving this mapping requires your confirmation and does not grant any peer access." })
17120
- ]
17121
- }) : null,
17122
- /* @__PURE__ */ u(GuardrailMessages, { warnings: visibleProjectWarnings(project) }),
17123
- !assignable ? /* @__PURE__ */ u("div", {
17124
- className: "settings-note",
17125
- children: "This project is missing a stable identity, so Space assignment is disabled. Add a path, git remote, or workspace id first; until then it remains Local only."
17126
- }) : null,
17127
- pendingConfirmation ? /* @__PURE__ */ u("div", {
17128
- className: "settings-note",
17129
- role: "alert",
17130
- children: [
17131
- /* @__PURE__ */ u("strong", { children: "Review before saving this Space assignment." }),
17132
- /* @__PURE__ */ u("ul", { children: pendingConfirmation.warnings.map((warning, warningIndex) => /* @__PURE__ */ u("li", { children: warning.message }, warningKey(warning, warningIndex))) }),
17133
- /* @__PURE__ */ u("div", {
17134
- className: "section-actions",
17135
- children: [/* @__PURE__ */ u("button", {
17136
- className: "settings-button",
17137
- disabled: saving,
17138
- onClick: () => void saveProjectWithGuardrails(project, pendingConfirmation.requiredGuardrailTokens),
17139
- type: "button",
17140
- children: "Confirm and save"
17141
- }), /* @__PURE__ */ u("button", {
17142
- className: "settings-button",
17143
- disabled: saving,
17144
- onClick: () => setConfirmation(null),
17145
- type: "button",
17146
- children: "Cancel"
17147
- })]
17148
- })
17149
- ]
17150
- }) : null,
17151
- /* @__PURE__ */ u("div", {
17152
- className: "section-actions",
17153
- children: [/* @__PURE__ */ u("button", {
17154
- className: "settings-button",
17155
- disabled: !assignable || saving || unchanged,
17156
- onClick: () => void saveProject(project),
17157
- type: "button",
17158
- children: saving ? "Saving…" : usingSuggestion ? "Confirm suggested mapping" : "Save Space"
17159
- }), /* @__PURE__ */ u("button", {
17160
- className: "settings-button",
17161
- disabled: saving || !canRemoveProjectMapping,
17162
- onClick: () => void resetProject(project),
17163
- type: "button",
17164
- children: "Remove project mapping"
17165
- })]
17166
- })
17167
- ]
17168
- }, project.workspace_identity);
17169
- })
17170
- ]
17171
- });
17172
- }
17173
- //#endregion
17174
- //#region src/tabs/settings/components/SyncPanel.tsx
17175
- function SyncPanel({ values, hiddenUnlessAdvanced, onTextInput, onSwitchInput, protectedConfigHelp }) {
17176
- return /* @__PURE__ */ u(k$3, { children: [
17177
- /* @__PURE__ */ u(SettingsSectionIntro, {
17178
- detail: "Choose whether this device syncs at all, how often it checks peers, and which coordinator group it should join.",
17179
- title: "Device sync"
17180
- }),
17181
- /* @__PURE__ */ u("div", {
17182
- className: "settings-group",
17183
- children: [
17184
- /* @__PURE__ */ u("h3", {
17185
- className: "settings-group-title",
17186
- children: "Device Sync"
17187
- }),
17188
- /* @__PURE__ */ u(SettingsSwitchRow, {
17189
- checked: values.syncEnabled,
17190
- className: "field",
17191
- id: "syncEnabled",
17192
- label: "Enable sync",
17193
- onCheckedChange: onSwitchInput("syncEnabled")
17194
- }),
17195
- /* @__PURE__ */ u("div", {
17196
- className: "field",
17197
- children: [
17198
- /* @__PURE__ */ u("label", {
17199
- htmlFor: "syncInterval",
17200
- children: "Sync interval (seconds)"
17201
- }),
17202
- /* @__PURE__ */ u(TextInput, {
17203
- id: "syncInterval",
17204
- min: "10",
17205
- onInput: onTextInput("syncInterval"),
17206
- type: "number",
17207
- value: values.syncInterval
17208
- }),
17209
- /* @__PURE__ */ u("div", {
17210
- className: "small",
17211
- children: "How often this device checks for sync work when sync is enabled."
17212
- })
17213
- ]
17214
- }),
17215
- /* @__PURE__ */ u("div", {
17216
- className: "field settings-advanced",
17217
- hidden: hiddenUnlessAdvanced(),
17218
- children: [/* @__PURE__ */ u("label", {
17219
- htmlFor: "syncHost",
17220
- children: "Sync host"
17221
- }), /* @__PURE__ */ u(TextInput, {
17222
- id: "syncHost",
17223
- onInput: onTextInput("syncHost"),
17224
- placeholder: "127.0.0.1",
17225
- value: values.syncHost
17226
- })]
17227
- }),
17228
- /* @__PURE__ */ u("div", {
17229
- className: "field settings-advanced",
17230
- hidden: hiddenUnlessAdvanced(),
17231
- children: [/* @__PURE__ */ u("label", {
17232
- htmlFor: "syncPort",
17233
- children: "Sync port"
17234
- }), /* @__PURE__ */ u(TextInput, {
17235
- id: "syncPort",
17236
- min: "1",
17237
- onInput: onTextInput("syncPort"),
17238
- type: "number",
17239
- value: values.syncPort
17240
- })]
17241
- }),
17242
- /* @__PURE__ */ u(SettingsSwitchRow, {
17243
- checked: values.syncMdns,
17244
- className: "field settings-advanced",
17245
- hidden: hiddenUnlessAdvanced(),
17246
- id: "syncMdns",
17247
- label: "Enable mDNS discovery",
17248
- onCheckedChange: onSwitchInput("syncMdns")
17249
- }),
17250
- /* @__PURE__ */ u("div", {
17251
- className: "field",
17252
- children: [
17253
- /* @__PURE__ */ u("label", {
17254
- htmlFor: "syncCoordinatorUrl",
17255
- children: "Coordinator URL"
17256
- }),
17257
- /* @__PURE__ */ u(TextInput, {
17258
- disabled: true,
17259
- id: "syncCoordinatorUrl",
17260
- placeholder: "https://coord.example.com",
17261
- value: values.syncCoordinatorUrl
17262
- }),
17263
- /* @__PURE__ */ u("div", {
17264
- className: "small",
17265
- children: protectedConfigHelp("sync_coordinator_url")
17266
- })
17267
- ]
17268
- }),
17269
- /* @__PURE__ */ u("div", {
17270
- className: "field",
17271
- children: [
17272
- /* @__PURE__ */ u("label", {
17273
- htmlFor: "syncCoordinatorGroup",
17274
- children: "Coordinator group"
17275
- }),
17276
- /* @__PURE__ */ u(TextInput, {
17277
- id: "syncCoordinatorGroup",
17278
- onInput: onTextInput("syncCoordinatorGroup"),
17279
- placeholder: "team-alpha",
17280
- value: values.syncCoordinatorGroup
17281
- }),
17282
- /* @__PURE__ */ u("div", {
17283
- className: "small",
17284
- children: "Discovery namespace for peers using the same coordinator."
17285
- })
17286
- ]
17287
- }),
17288
- /* @__PURE__ */ u("div", {
17289
- className: "field settings-advanced",
17290
- hidden: hiddenUnlessAdvanced(),
17291
- children: /* @__PURE__ */ u(SettingsHint, {
17292
- hidden: hiddenUnlessAdvanced(),
17293
- children: "These network overrides are for unusual local-network setups. Leave them alone unless you know this device needs non-default sync discovery or coordinator timing."
17294
- })
17295
- }),
17296
- /* @__PURE__ */ u("div", {
17297
- className: "field settings-advanced",
17298
- hidden: hiddenUnlessAdvanced(),
17299
- children: [/* @__PURE__ */ u("label", {
17300
- htmlFor: "syncCoordinatorTimeout",
17301
- children: "Coordinator timeout (seconds)"
17302
- }), /* @__PURE__ */ u(TextInput, {
17303
- id: "syncCoordinatorTimeout",
17304
- min: "1",
17305
- onInput: onTextInput("syncCoordinatorTimeout"),
17306
- type: "number",
17307
- value: values.syncCoordinatorTimeout
17308
- })]
17309
- }),
17310
- /* @__PURE__ */ u("div", {
17311
- className: "field settings-advanced",
17312
- hidden: hiddenUnlessAdvanced(),
17313
- children: [/* @__PURE__ */ u("label", {
17314
- htmlFor: "syncCoordinatorPresenceTtl",
17315
- children: "Presence TTL (seconds)"
17316
- }), /* @__PURE__ */ u(TextInput, {
17317
- id: "syncCoordinatorPresenceTtl",
17318
- min: "1",
17319
- onInput: onTextInput("syncCoordinatorPresenceTtl"),
17320
- type: "number",
17321
- value: values.syncCoordinatorPresenceTtl
17322
- })]
17323
- })
17324
- ]
17325
- }),
17326
- /* @__PURE__ */ u(AnchorPeerSetupCard, {}),
17327
- /* @__PURE__ */ u(SharingDomainsPanel, {})
17328
- ] });
17329
- }
17330
- function AnchorPeerSetupCard() {
17331
- return /* @__PURE__ */ u("section", {
17332
- "aria-labelledby": "anchor-peer-setup-title",
17333
- className: "settings-group",
17334
- children: [
17335
- /* @__PURE__ */ u("h3", {
17336
- className: "settings-group-title",
17337
- id: "anchor-peer-setup-title",
17338
- children: "Always-on peers"
17115
+ /* @__PURE__ */ u(SettingsSwitchRow, {
17116
+ checked: values.syncMdns,
17117
+ className: "field settings-advanced",
17118
+ hidden: hiddenUnlessAdvanced(),
17119
+ id: "syncMdns",
17120
+ label: "Enable mDNS discovery",
17121
+ onCheckedChange: onSwitchInput("syncMdns")
17339
17122
  }),
17340
- /* @__PURE__ */ u("p", {
17341
- className: "small",
17342
- children: "An anchor peer is just a normal paired device that stays online. It is useful as a stable sync backstop, but it is not a coordinator, relay, or special protocol role."
17123
+ /* @__PURE__ */ u("div", {
17124
+ className: "field",
17125
+ children: [
17126
+ /* @__PURE__ */ u("label", {
17127
+ htmlFor: "syncCoordinatorUrl",
17128
+ children: "Coordinator URL"
17129
+ }),
17130
+ /* @__PURE__ */ u(TextInput, {
17131
+ disabled: true,
17132
+ id: "syncCoordinatorUrl",
17133
+ placeholder: "https://coord.example.com",
17134
+ value: values.syncCoordinatorUrl
17135
+ }),
17136
+ /* @__PURE__ */ u("div", {
17137
+ className: "small",
17138
+ children: protectedConfigHelp("sync_coordinator_url")
17139
+ })
17140
+ ]
17343
17141
  }),
17344
- /* @__PURE__ */ u("ul", {
17345
- className: "small",
17142
+ /* @__PURE__ */ u("div", {
17143
+ className: "field",
17346
17144
  children: [
17347
- /* @__PURE__ */ u("li", { children: "Coordinator discovery helps peers find each other; it does not grant data access." }),
17348
- /* @__PURE__ */ u("li", { children: "Explicit Sharing-domain grants decide what an always-on peer can receive." }),
17349
- /* @__PURE__ */ u("li", { children: "Project include/exclude filters only narrow already-granted domains." }),
17350
- /* @__PURE__ */ u("li", { children: "Use durable storage and backups for peers you expect to recover after restart." })
17145
+ /* @__PURE__ */ u("label", {
17146
+ htmlFor: "syncCoordinatorGroup",
17147
+ children: "Coordinator group"
17148
+ }),
17149
+ /* @__PURE__ */ u(TextInput, {
17150
+ id: "syncCoordinatorGroup",
17151
+ onInput: onTextInput("syncCoordinatorGroup"),
17152
+ placeholder: "team-alpha",
17153
+ value: values.syncCoordinatorGroup
17154
+ }),
17155
+ /* @__PURE__ */ u("div", {
17156
+ className: "small",
17157
+ children: "Discovery namespace for peers using the same coordinator."
17158
+ })
17351
17159
  ]
17352
17160
  }),
17353
- /* @__PURE__ */ u("a", {
17354
- className: "settings-link",
17355
- href: "https://github.com/kunickiaj/codemem/blob/main/docs/anchor-peer-deployment.md",
17356
- rel: "noreferrer",
17357
- target: "_blank",
17358
- children: "Read the anchor-peer deployment guide"
17161
+ /* @__PURE__ */ u("div", {
17162
+ className: "field settings-advanced",
17163
+ hidden: hiddenUnlessAdvanced(),
17164
+ children: /* @__PURE__ */ u(SettingsHint, {
17165
+ hidden: hiddenUnlessAdvanced(),
17166
+ children: "These network overrides are for unusual local-network setups. Leave them alone unless you know this device needs non-default sync discovery or coordinator timing."
17167
+ })
17168
+ }),
17169
+ /* @__PURE__ */ u("div", {
17170
+ className: "field settings-advanced",
17171
+ hidden: hiddenUnlessAdvanced(),
17172
+ children: [/* @__PURE__ */ u("label", {
17173
+ htmlFor: "syncCoordinatorTimeout",
17174
+ children: "Coordinator timeout (seconds)"
17175
+ }), /* @__PURE__ */ u(TextInput, {
17176
+ id: "syncCoordinatorTimeout",
17177
+ min: "1",
17178
+ onInput: onTextInput("syncCoordinatorTimeout"),
17179
+ type: "number",
17180
+ value: values.syncCoordinatorTimeout
17181
+ })]
17182
+ }),
17183
+ /* @__PURE__ */ u("div", {
17184
+ className: "field settings-advanced",
17185
+ hidden: hiddenUnlessAdvanced(),
17186
+ children: [/* @__PURE__ */ u("label", {
17187
+ htmlFor: "syncCoordinatorPresenceTtl",
17188
+ children: "Presence TTL (seconds)"
17189
+ }), /* @__PURE__ */ u(TextInput, {
17190
+ id: "syncCoordinatorPresenceTtl",
17191
+ min: "1",
17192
+ onInput: onTextInput("syncCoordinatorPresenceTtl"),
17193
+ type: "number",
17194
+ value: values.syncCoordinatorPresenceTtl
17195
+ })]
17359
17196
  })
17360
17197
  ]
17361
- });
17198
+ })] });
17362
17199
  }
17363
17200
  //#endregion
17364
17201
  //#region src/tabs/settings/components/SettingsModalContent.tsx
17365
17202
  function SettingsModalContent({ panelProps, activeTab, showAdvanced, renderState, settingsDirty, onClose, onSave, onActiveTabChange, onAdvancedToggle, observerStatusBannerSlot }) {
17203
+ const saveDisabled = !settingsDirty || renderState.isSaving;
17366
17204
  return /* @__PURE__ */ u("div", {
17367
17205
  className: "modal-card",
17206
+ onKeyDown: (event) => handlePrimaryActionKeyboard(event, {
17207
+ onSubmit: onSave,
17208
+ disabled: saveDisabled
17209
+ }),
17368
17210
  children: [
17369
17211
  /* @__PURE__ */ u("div", {
17370
17212
  className: "modal-header",
@@ -17469,7 +17311,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
17469
17311
  children: renderState.statusText
17470
17312
  }), /* @__PURE__ */ u("button", {
17471
17313
  className: "settings-save",
17472
- disabled: !settingsDirty || renderState.isSaving,
17314
+ "data-primary-action": "true",
17315
+ disabled: saveDisabled,
17473
17316
  id: "settingsSave",
17474
17317
  onClick: onSave,
17475
17318
  type: "button",
@@ -18841,6 +18684,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18841
18684
  }
18842
18685
  //#endregion
18843
18686
  //#region src/tabs/sync/diagnostics/render/sync-attempts.ts
18687
+ function shouldShowSyncAttemptRedactionHint(attempt, redact) {
18688
+ return redact && attempt.error_redacted === true;
18689
+ }
18844
18690
  function renderSyncAttempts() {
18845
18691
  const syncAttempts = document.getElementById("syncAttempts");
18846
18692
  if (!syncAttempts) return;
@@ -18862,7 +18708,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18862
18708
  if (isError && attempt.error) {
18863
18709
  const errText = String(attempt.error);
18864
18710
  detailParts.push(redact ? redactIpOctets(errText) : errText);
18865
- if (redact && /enable diagnostics for details/i.test(errText)) detailParts.push("Turn off Redact in Advanced diagnostics to reveal the full error.");
18711
+ if (shouldShowSyncAttemptRedactionHint(attempt, redact)) detailParts.push("Turn off Redact in Advanced diagnostics to reveal the full error.");
18866
18712
  }
18867
18713
  if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
18868
18714
  if (!redact && attempt.address) detailParts.push(attempt.address);
@@ -19266,11 +19112,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19266
19112
  disabled: renameBusy || mergeBusy,
19267
19113
  type: "text",
19268
19114
  value: name,
19269
- onInput: (event) => setName(event.currentTarget.value)
19115
+ onInput: (event) => setName(event.currentTarget.value),
19116
+ onKeyDown: (event) => handlePrimaryActionKeyboard(event, {
19117
+ onSubmit: () => void rename(),
19118
+ disabled: renameBusy || mergeBusy || !name.trim()
19119
+ })
19270
19120
  }),
19271
19121
  /* @__PURE__ */ u("button", {
19272
19122
  type: "button",
19273
19123
  className: "settings-button",
19124
+ "data-primary-action": "true",
19274
19125
  disabled: renameBusy || mergeBusy,
19275
19126
  onClick: () => void rename(),
19276
19127
  children: renameLabel
@@ -19493,6 +19344,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19493
19344
  function openTeamsAccessManagement() {
19494
19345
  window.location.hash = "coordinator-admin";
19495
19346
  }
19347
+ function canManageSpacesInTeams(status = state.lastCoordinatorAdminStatus) {
19348
+ return status?.readiness === "ready" && status.has_admin_secret === true;
19349
+ }
19496
19350
  function SyncPeerCard({ peer, onAssignActor, onRemove, onRename, onSync }) {
19497
19351
  const peerId = String(peer.peer_device_id || "");
19498
19352
  const displayName = peer.name || (peerId ? peerId.slice(0, 8) : "unknown");
@@ -19601,11 +19455,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19601
19455
  }
19602
19456
  async function sync() {
19603
19457
  if (pendingScopeReview) {
19458
+ const canReviewInTeams = canManageSpacesInTeams();
19604
19459
  if (!await openSyncConfirmDialog({
19605
19460
  title: `Sync ${displayName} before advanced rule review?`,
19606
- description: "This manual sync will use the current Space access and advanced filters until you review them in Teams.",
19461
+ description: canReviewInTeams ? "This manual sync will use the current Space access and advanced filters until you review them in Teams." : "This manual sync will use the current Space access and advanced filters until a coordinator or manager reviews them in Teams.",
19607
19462
  confirmLabel: "Sync anyway",
19608
- cancelLabel: "Review in Teams first"
19463
+ cancelLabel: canReviewInTeams ? "Review in Teams first" : "Cancel"
19609
19464
  })) return;
19610
19465
  }
19611
19466
  setSyncBusy(true);
@@ -19658,6 +19513,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19658
19513
  const drawerId = `device-drawer-${peerId || "unknown"}`;
19659
19514
  const presenceState = presenceForPeer(peer);
19660
19515
  const syncMetaText = lastSyncAt ? `Sync: ${formatTimestamp(lastSyncAt)}` : "Sync: never";
19516
+ const canManageSpaces = canManageSpacesInTeams();
19661
19517
  const toggleLabel = `${isExpanded ? "Collapse" : "Expand"} device ${displayName}`;
19662
19518
  const handleOpenChange = (open) => {
19663
19519
  if (open) setExpandedPeer(peerId);
@@ -19788,7 +19644,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19788
19644
  children: [
19789
19645
  scopeReviewRequested ? /* @__PURE__ */ u("div", {
19790
19646
  className: "peer-meta",
19791
- children: "Review this device's Space access and advanced rules in Teams if the defaults are too broad."
19647
+ children: canManageSpaces ? "Review this device's Space access and advanced rules in Teams if the defaults are too broad." : "A coordinator or manager can review this device's Space access and advanced rules in Teams if the defaults are too broad."
19792
19648
  }) : pendingScopeReview ? /* @__PURE__ */ u("div", {
19793
19649
  className: "peer-meta",
19794
19650
  children: "Advanced rule review is still pending for this device."
@@ -19917,7 +19773,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19917
19773
  projectNarrowing.note
19918
19774
  ]
19919
19775
  }),
19920
- /* @__PURE__ */ u("div", {
19776
+ canManageSpaces ? /* @__PURE__ */ u("div", {
19921
19777
  className: "peer-actions",
19922
19778
  children: /* @__PURE__ */ u("button", {
19923
19779
  type: "button",
@@ -19925,6 +19781,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19925
19781
  onClick: openTeamsAccessManagement,
19926
19782
  children: "Manage Spaces in Teams"
19927
19783
  })
19784
+ }) : /* @__PURE__ */ u("div", {
19785
+ className: "peer-meta",
19786
+ children: "Space access is managed in Teams by a coordinator or manager."
19928
19787
  }),
19929
19788
  /* @__PURE__ */ u(SyncInlineFeedback, { feedback })
19930
19789
  ]
@@ -20057,7 +19916,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
20057
19916
  tone: "warning"
20058
19917
  };
20059
19918
  else if (peerId && isPeerScopeReviewPending(peerId)) feedback = {
20060
- message: `Triggered sync for ${peer?.name || (peerId ? peerId.slice(0, 8) : "unknown")}. Review Space access and advanced rules in Teams if this device needs tighter sharing.`,
19919
+ message: `Triggered sync for ${peer?.name || (peerId ? peerId.slice(0, 8) : "unknown")}. ${canManageSpacesInTeams() ? "Review Space access and advanced rules in Teams if this device needs tighter sharing." : "A coordinator or manager can review Space access and advanced rules in Teams if this device needs tighter sharing."}`,
20061
19920
  tone: "warning"
20062
19921
  };
20063
19922
  else feedback = {
@@ -20155,6 +20014,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
20155
20014
  const syncActorCreateButton = document.getElementById("syncActorCreateButton");
20156
20015
  const syncActorCreateInput = document.getElementById("syncActorCreateInput");
20157
20016
  const syncLegacyClaimButton = document.getElementById("syncLegacyClaimButton");
20017
+ syncActorCreateInput?.addEventListener("keydown", (event) => {
20018
+ handlePrimaryActionKeyboard(event, {
20019
+ onSubmit: () => syncActorCreateButton?.click(),
20020
+ disabled: !syncActorCreateButton || syncActorCreateButton.disabled
20021
+ });
20022
+ });
20158
20023
  syncActorCreateButton?.addEventListener("click", async () => {
20159
20024
  if (!syncActorCreateButton || !syncActorCreateInput) return;
20160
20025
  const displayName = String(syncActorCreateInput.value || "").trim();
@@ -20382,6 +20247,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
20382
20247
  }
20383
20248
  }
20384
20249
  });
20250
+ syncJoinInvite?.addEventListener("keydown", (event) => {
20251
+ handlePrimaryActionKeyboard(event, {
20252
+ onSubmit: () => syncJoinButton?.click(),
20253
+ disabled: !syncJoinButton || syncJoinButton.disabled
20254
+ });
20255
+ });
20385
20256
  syncJoinButton?.addEventListener("click", async () => {
20386
20257
  if (!syncJoinButton || !syncJoinInvite) return;
20387
20258
  const inviteValue = syncJoinInvite.value.trim();
@@ -21334,6 +21205,72 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
21334
21205
  default: return "Other Space";
21335
21206
  }
21336
21207
  }
21208
+ function formatSampleDate(value) {
21209
+ if (!value) return "date unavailable";
21210
+ const date = new Date(value);
21211
+ if (Number.isNaN(date.getTime())) return value;
21212
+ return new Intl.DateTimeFormat("en-US", {
21213
+ day: "numeric",
21214
+ month: "short",
21215
+ timeZone: "UTC",
21216
+ year: "numeric"
21217
+ }).format(date);
21218
+ }
21219
+ function sampleOrigin(sample) {
21220
+ if (sample.gitRemote) return sample.gitRemote;
21221
+ if (sample.cwd) return sample.cwd;
21222
+ if (sample.project) return sample.project;
21223
+ return "source identity unavailable";
21224
+ }
21225
+ function LegacyMemorySamples({ group }) {
21226
+ const samples = group.memorySamples ?? [];
21227
+ const shownCount = samples.length;
21228
+ return /* @__PURE__ */ u("details", {
21229
+ className: "legacy-review-samples",
21230
+ children: [
21231
+ /* @__PURE__ */ u("summary", { children: ["Inspect affected memories", shownCount ? ` (${shownCount} sample${shownCount === 1 ? "" : "s"})` : ""] }),
21232
+ /* @__PURE__ */ u("div", {
21233
+ className: "legacy-review-cleanup-note",
21234
+ children: "Showing representative memories from this project group before reassignment. Local memories can be reassigned; peer-owned memories stay in review on this device."
21235
+ }),
21236
+ samples.length > 0 ? /* @__PURE__ */ u("ul", {
21237
+ className: "legacy-review-sample-list",
21238
+ children: samples.map((sample) => /* @__PURE__ */ u("li", {
21239
+ className: "legacy-review-sample",
21240
+ children: [
21241
+ /* @__PURE__ */ u("div", {
21242
+ className: "legacy-review-sample-title",
21243
+ children: sample.title
21244
+ }),
21245
+ /* @__PURE__ */ u("div", {
21246
+ className: "legacy-review-group-meta",
21247
+ children: [
21248
+ sample.kind || "memory",
21249
+ " · ",
21250
+ formatSampleDate(sample.updatedAt ?? sample.createdAt),
21251
+ " ",
21252
+ "·",
21253
+ " ",
21254
+ sample.ownership === "local" ? "local, reassignable" : "peer-owned, stays in review"
21255
+ ]
21256
+ }),
21257
+ sample.bodyPreview ? /* @__PURE__ */ u("div", {
21258
+ className: "legacy-review-sample-body",
21259
+ children: sample.bodyPreview
21260
+ }) : null,
21261
+ /* @__PURE__ */ u("div", {
21262
+ className: "legacy-review-group-meta mono",
21263
+ children: sampleOrigin(sample)
21264
+ })
21265
+ ]
21266
+ }, sample.id))
21267
+ }) : /* @__PURE__ */ u("div", {
21268
+ className: "legacy-review-cleanup-note",
21269
+ children: "No samples are available for this group. Refresh Sync and try again before reassigning."
21270
+ })
21271
+ ]
21272
+ });
21273
+ }
21337
21274
  function formatLegacyReviewError(error, scopeId, targetScopes) {
21338
21275
  let result = (error instanceof Error ? error.message : "Unable to reassign legacy review memories.").replace(/sharing domain/gi, "Space");
21339
21276
  if (scopeId) result = result.replace(new RegExp(`\\b${escapeRegExp(scopeId)}\\b`, "g"), targetScopeLabel(scopeId, targetScopes));
@@ -21688,6 +21625,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
21688
21625
  "."
21689
21626
  ]
21690
21627
  }) : null,
21628
+ /* @__PURE__ */ u(LegacyMemorySamples, { group }),
21691
21629
  targetScopes.length > 0 && onReassign && canReassignLegacyGroup(group) ? /* @__PURE__ */ u("label", {
21692
21630
  className: "legacy-review-target",
21693
21631
  children: [/* @__PURE__ */ u("span", { children: "Destination Space" }), /* @__PURE__ */ u("select", {
@@ -21781,6 +21719,22 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
21781
21719
  identitySource: String(raw.identity_source || "unknown"),
21782
21720
  lastUpdatedAt: typeof raw.last_updated_at === "string" ? raw.last_updated_at : null,
21783
21721
  memoryCount: Number(raw.memory_count || 0),
21722
+ memorySamples: Array.isArray(raw.memory_samples) ? raw.memory_samples.map((sample) => {
21723
+ const sampleRaw = sample;
21724
+ const ownership = sampleRaw.ownership === "peer" ? "peer" : "local";
21725
+ return {
21726
+ bodyPreview: typeof sampleRaw.body_preview === "string" ? sampleRaw.body_preview : null,
21727
+ createdAt: typeof sampleRaw.created_at === "string" ? sampleRaw.created_at : null,
21728
+ cwd: typeof sampleRaw.cwd === "string" ? sampleRaw.cwd : null,
21729
+ gitRemote: typeof sampleRaw.git_remote === "string" ? sampleRaw.git_remote : null,
21730
+ id: Number(sampleRaw.id || 0),
21731
+ kind: typeof sampleRaw.kind === "string" ? sampleRaw.kind : null,
21732
+ ownership,
21733
+ project: typeof sampleRaw.project === "string" ? sampleRaw.project : null,
21734
+ title: String(sampleRaw.title || `Memory ${Number(sampleRaw.id || 0)}`),
21735
+ updatedAt: typeof sampleRaw.updated_at === "string" ? sampleRaw.updated_at : null
21736
+ };
21737
+ }) : [],
21784
21738
  peerOwnedMemoryCount: Number(raw.peer_owned_memory_count || 0),
21785
21739
  reassignableMemoryCount: Number(raw.reassignable_memory_count || 0),
21786
21740
  suggestedScopeId: typeof raw.suggested_scope_id === "string" ? raw.suggested_scope_id : null,
@@ -22006,7 +21960,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
22006
21960
  try {
22007
21961
  const runtime = await loadRuntimeInfo();
22008
21962
  if (!runtime?.version) return;
22009
- setRuntimeLabel(runtime.version, "c8fe0f7");
21963
+ setRuntimeLabel(runtime.version, "c329fa8");
22010
21964
  } catch {}
22011
21965
  }
22012
21966
  var lastAnnouncedRefreshState = null;
@@ -22067,6 +22021,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
22067
22021
  setLegacyUpgradeNotice(false);
22068
22022
  return;
22069
22023
  }
22024
+ if (event.key === "Enter") {
22025
+ const primary = $("legacyUpgradeReviewGroups");
22026
+ handlePrimaryActionKeyboard(event, {
22027
+ onSubmit: () => primary?.click(),
22028
+ disabled: !primary || primary.disabled
22029
+ });
22030
+ return;
22031
+ }
22070
22032
  if (event.key !== "Tab") return;
22071
22033
  const focusable = legacyUpgradeFocusableElements();
22072
22034
  if (focusable.length === 0) return;