@codemem/server 0.33.0-alpha.2 → 0.33.0-alpha.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAKX,WAAW,EAIX,MAAM,eAAe,CAAC;AAuFvB,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAoBF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;AA+2DD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EAiZ7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EAwqErD"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAKX,WAAW,EAIX,MAAM,eAAe,CAAC;AAuFvB,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAoBF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;AAi3DD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EAiZ7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EA0qErD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemem/server",
3
- "version": "0.33.0-alpha.2",
3
+ "version": "0.33.0-alpha.3",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -19,7 +19,7 @@
19
19
  "drizzle-orm": "^0.45.2",
20
20
  "hono": "^4.12.21",
21
21
  "limiter": "^3.0.0",
22
- "@codemem/core": "^0.33.0-alpha.2"
22
+ "@codemem/core": "^0.33.0-alpha.3"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/better-sqlite3": "^7.6.13",
package/static/app.js CHANGED
@@ -14616,6 +14616,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14616
14616
  ["needs_attention", "Needs review"],
14617
14617
  ["suggested", "Has suggestion"],
14618
14618
  ["local_only", "Stays on this device"],
14619
+ ["received", "Received from peers"],
14619
14620
  ["explicitly_mapped", "Already assigned"],
14620
14621
  ["legacy_review", "Older shared data"],
14621
14622
  ["unmapped", "Missing project identity"]
@@ -14645,6 +14646,18 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14645
14646
  default: return "stays on this device";
14646
14647
  }
14647
14648
  }
14649
+ function isPeerReceivedProject(project) {
14650
+ return project.read_only === true && project.read_only_reason === "peer_received";
14651
+ }
14652
+ function isLocallyAssignableProject(project) {
14653
+ return project.identity_source !== "unmapped" && !isPeerReceivedProject(project);
14654
+ }
14655
+ function projectDomainLabel(project) {
14656
+ return isPeerReceivedProject(project) ? "Received from peers" : scopeSummary(project.resolved_scope_id);
14657
+ }
14658
+ function projectResolutionLabel(project) {
14659
+ return isPeerReceivedProject(project) ? "source-owned project" : formatResolution(project.resolution_reason);
14660
+ }
14648
14661
  function formatLatest(value) {
14649
14662
  if (!value) return "No recent sessions";
14650
14663
  const date = new Date(value);
@@ -14823,7 +14836,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14823
14836
  }
14824
14837
  }
14825
14838
  async function saveProjectClusterMapping(projects, scopeId) {
14826
- const assignable = projects.filter((project) => project.identity_source !== "unmapped");
14839
+ const assignable = projects.filter(isLocallyAssignableProject);
14827
14840
  if (assignable.length === 0) return;
14828
14841
  try {
14829
14842
  await saveSharingDomainProjectMappings({ mappings: assignable.map((project) => ({
@@ -14911,6 +14924,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
14911
14924
  function renderProjectActions(project) {
14912
14925
  const actions = document.createElement("div");
14913
14926
  actions.className = "project-inventory-actions";
14927
+ if (isPeerReceivedProject(project)) {
14928
+ const note = document.createElement("div");
14929
+ note.className = "settings-note";
14930
+ 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.";
14931
+ actions.appendChild(note);
14932
+ return actions;
14933
+ }
14914
14934
  if (project.identity_source === "unmapped") {
14915
14935
  const note = document.createElement("div");
14916
14936
  note.className = "settings-note";
@@ -15055,13 +15075,19 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15055
15075
  header.appendChild(title);
15056
15076
  const domain = document.createElement("div");
15057
15077
  domain.className = "project-inventory-domain";
15058
- domain.textContent = scopeSummary(project.resolved_scope_id);
15078
+ domain.textContent = projectDomainLabel(project);
15059
15079
  header.appendChild(domain);
15060
15080
  row.appendChild(header);
15061
15081
  const meta = document.createElement("div");
15062
15082
  meta.className = "project-inventory-meta";
15063
- meta.textContent = `${formatResolution(project.resolution_reason)} · ${project.identity_source} · ${formatLatest(project.latest_session_at)}`;
15083
+ meta.textContent = `${projectResolutionLabel(project)} · ${project.identity_source} · ${formatLatest(project.latest_session_at)}`;
15064
15084
  row.appendChild(meta);
15085
+ if (isPeerReceivedProject(project)) {
15086
+ const receivedNote = document.createElement("div");
15087
+ receivedNote.className = "settings-note";
15088
+ 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.";
15089
+ row.appendChild(receivedNote);
15090
+ }
15065
15091
  const signal = document.createElement("div");
15066
15092
  signal.className = "project-inventory-signal mono";
15067
15093
  signal.textContent = strongestSignal(project);
@@ -15072,7 +15098,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15072
15098
  suggestion.textContent = project.suggestion_reason ? `Suggestion: ${project.suggestion_reason}` : `Suggestion: assign this project to ${scopeSummary(project.suggested_scope_id)}.`;
15073
15099
  row.appendChild(suggestion);
15074
15100
  }
15075
- const warnings = project.guardrail_warnings.filter((warning) => warning.severity === "warning");
15101
+ const warnings = (project.guardrail_warnings ?? []).filter((warning) => warning.severity === "warning");
15076
15102
  if (warnings.length > 0) {
15077
15103
  const warningBox = document.createElement("div");
15078
15104
  warningBox.className = "settings-note project-attention-note";
@@ -15108,7 +15134,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15108
15134
  ["CWD", project.cwd],
15109
15135
  ["Git remote", project.git_remote],
15110
15136
  ["Git branch", project.git_branch],
15111
- ["Current Space", scopeSummary(project.resolved_scope_id)],
15137
+ ["Current Space", projectDomainLabel(project)],
15112
15138
  ["Suggested Space", project.suggested_scope_id ? scopeSummary(project.suggested_scope_id) : null],
15113
15139
  ["Advanced: current Space ID", project.resolved_scope_id],
15114
15140
  ["Advanced: suggested Space ID", project.suggested_scope_id],
@@ -15129,8 +15155,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15129
15155
  return row;
15130
15156
  }
15131
15157
  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";
15158
+ const uniqueLabels = [...new Set(projects.map((project) => projectDomainLabel(project)))];
15159
+ return uniqueLabels.length === 1 ? uniqueLabels[0] : "Mixed Spaces";
15134
15160
  }
15135
15161
  function renderProjectCluster(projects) {
15136
15162
  if (projects.length === 1) return renderProjectRow(projects[0]);
@@ -15156,36 +15182,45 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15156
15182
  row.appendChild(meta);
15157
15183
  const actions = document.createElement("div");
15158
15184
  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) {
15185
+ const assignableProjects = projects.filter(isLocallyAssignableProject);
15186
+ if (assignableProjects.length === 0) {
15183
15187
  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.";
15188
+ note.className = "settings-note";
15189
+ 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
15190
  actions.appendChild(note);
15191
+ row.appendChild(actions);
15192
+ } else {
15193
+ const hasGuardrailWarnings = assignableProjects.some((project) => (project.guardrail_warnings ?? []).length > 0);
15194
+ const suggestedScopes = new Set(assignableProjects.map((project) => project.suggested_scope_id).filter((scopeId) => Boolean(scopeId)));
15195
+ const resolvedScopes = new Set(assignableProjects.map((project) => project.resolved_scope_id));
15196
+ const select = document.createElement("select");
15197
+ select.className = "project-domain-select";
15198
+ select.setAttribute("aria-label", `Space for ${projectClusterLabel(projects[0])} group`);
15199
+ const placeholder = document.createElement("option");
15200
+ placeholder.value = "";
15201
+ placeholder.textContent = "Choose Space…";
15202
+ select.appendChild(placeholder);
15203
+ appendAssignableScopeOptions(select);
15204
+ select.value = "";
15205
+ const save = document.createElement("button");
15206
+ save.className = "settings-button";
15207
+ save.type = "button";
15208
+ save.textContent = `Save Space for ${assignableProjects.length} identit${assignableProjects.length === 1 ? "y" : "ies"}`;
15209
+ save.disabled = true;
15210
+ save.addEventListener("click", () => void saveProjectClusterMapping(assignableProjects, select.value));
15211
+ select.addEventListener("change", () => {
15212
+ save.disabled = !select.value || hasGuardrailWarnings;
15213
+ });
15214
+ select.addEventListener("blur", refreshSkippedProjectDataAfterSelectBlur);
15215
+ actions.append(select, save);
15216
+ if (suggestedScopes.size > 1 || resolvedScopes.size > 1 || hasGuardrailWarnings) {
15217
+ const note = document.createElement("div");
15218
+ note.className = "settings-note project-attention-note";
15219
+ 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.";
15220
+ actions.appendChild(note);
15221
+ }
15222
+ row.appendChild(actions);
15187
15223
  }
15188
- row.appendChild(actions);
15189
15224
  const details = document.createElement("details");
15190
15225
  details.className = "project-inventory-details";
15191
15226
  details.open = openProjectClusters.has(clusterKey);
@@ -18841,6 +18876,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18841
18876
  }
18842
18877
  //#endregion
18843
18878
  //#region src/tabs/sync/diagnostics/render/sync-attempts.ts
18879
+ function shouldShowSyncAttemptRedactionHint(attempt, redact) {
18880
+ return redact && attempt.error_redacted === true;
18881
+ }
18844
18882
  function renderSyncAttempts() {
18845
18883
  const syncAttempts = document.getElementById("syncAttempts");
18846
18884
  if (!syncAttempts) return;
@@ -18862,7 +18900,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
18862
18900
  if (isError && attempt.error) {
18863
18901
  const errText = String(attempt.error);
18864
18902
  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.");
18903
+ if (shouldShowSyncAttemptRedactionHint(attempt, redact)) detailParts.push("Turn off Redact in Advanced diagnostics to reveal the full error.");
18866
18904
  }
18867
18905
  if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
18868
18906
  if (!redact && attempt.address) detailParts.push(attempt.address);
@@ -19493,6 +19531,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19493
19531
  function openTeamsAccessManagement() {
19494
19532
  window.location.hash = "coordinator-admin";
19495
19533
  }
19534
+ function canManageSpacesInTeams(status = state.lastCoordinatorAdminStatus) {
19535
+ return status?.readiness === "ready" && status.has_admin_secret === true;
19536
+ }
19496
19537
  function SyncPeerCard({ peer, onAssignActor, onRemove, onRename, onSync }) {
19497
19538
  const peerId = String(peer.peer_device_id || "");
19498
19539
  const displayName = peer.name || (peerId ? peerId.slice(0, 8) : "unknown");
@@ -19601,11 +19642,12 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19601
19642
  }
19602
19643
  async function sync() {
19603
19644
  if (pendingScopeReview) {
19645
+ const canReviewInTeams = canManageSpacesInTeams();
19604
19646
  if (!await openSyncConfirmDialog({
19605
19647
  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.",
19648
+ 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
19649
  confirmLabel: "Sync anyway",
19608
- cancelLabel: "Review in Teams first"
19650
+ cancelLabel: canReviewInTeams ? "Review in Teams first" : "Cancel"
19609
19651
  })) return;
19610
19652
  }
19611
19653
  setSyncBusy(true);
@@ -19658,6 +19700,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19658
19700
  const drawerId = `device-drawer-${peerId || "unknown"}`;
19659
19701
  const presenceState = presenceForPeer(peer);
19660
19702
  const syncMetaText = lastSyncAt ? `Sync: ${formatTimestamp(lastSyncAt)}` : "Sync: never";
19703
+ const canManageSpaces = canManageSpacesInTeams();
19661
19704
  const toggleLabel = `${isExpanded ? "Collapse" : "Expand"} device ${displayName}`;
19662
19705
  const handleOpenChange = (open) => {
19663
19706
  if (open) setExpandedPeer(peerId);
@@ -19788,7 +19831,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19788
19831
  children: [
19789
19832
  scopeReviewRequested ? /* @__PURE__ */ u("div", {
19790
19833
  className: "peer-meta",
19791
- children: "Review this device's Space access and advanced rules in Teams if the defaults are too broad."
19834
+ 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
19835
  }) : pendingScopeReview ? /* @__PURE__ */ u("div", {
19793
19836
  className: "peer-meta",
19794
19837
  children: "Advanced rule review is still pending for this device."
@@ -19917,7 +19960,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19917
19960
  projectNarrowing.note
19918
19961
  ]
19919
19962
  }),
19920
- /* @__PURE__ */ u("div", {
19963
+ canManageSpaces ? /* @__PURE__ */ u("div", {
19921
19964
  className: "peer-actions",
19922
19965
  children: /* @__PURE__ */ u("button", {
19923
19966
  type: "button",
@@ -19925,6 +19968,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
19925
19968
  onClick: openTeamsAccessManagement,
19926
19969
  children: "Manage Spaces in Teams"
19927
19970
  })
19971
+ }) : /* @__PURE__ */ u("div", {
19972
+ className: "peer-meta",
19973
+ children: "Space access is managed in Teams by a coordinator or manager."
19928
19974
  }),
19929
19975
  /* @__PURE__ */ u(SyncInlineFeedback, { feedback })
19930
19976
  ]
@@ -20057,7 +20103,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
20057
20103
  tone: "warning"
20058
20104
  };
20059
20105
  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.`,
20106
+ 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
20107
  tone: "warning"
20062
20108
  };
20063
20109
  else feedback = {
@@ -22006,7 +22052,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
22006
22052
  try {
22007
22053
  const runtime = await loadRuntimeInfo();
22008
22054
  if (!runtime?.version) return;
22009
- setRuntimeLabel(runtime.version, "c8fe0f7");
22055
+ setRuntimeLabel(runtime.version, "242955b");
22010
22056
  } catch {}
22011
22057
  }
22012
22058
  var lastAnnouncedRefreshState = null;