@codemem/server 0.22.3 → 0.23.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.
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/routes/memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIjD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AAgJtC,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,8EAwQlD"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/routes/memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAWjD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AA6ItC,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,8EAwQlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AA2BhE,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;AAEF,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;AA8pBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EA+O7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EAyzBrD"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAEX,WAAW,EAEX,MAAM,eAAe,CAAC;AA+BvB,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;AAEF,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;AA6vBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EA4R7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EA+4BrD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemem/server",
3
- "version": "0.22.3",
3
+ "version": "0.23.0",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -15,33 +15,36 @@
15
15
  "static/"
16
16
  ],
17
17
  "dependencies": {
18
- "@hono/node-server": "^1.14.3",
19
- "drizzle-orm": "^0.45.1",
20
- "hono": "^4.7.10",
18
+ "@hono/node-server": "^1.19.12",
19
+ "drizzle-orm": "^0.45.2",
20
+ "hono": "^4.12.11",
21
21
  "limiter": "^3.0.0",
22
- "@codemem/core": "^0.22.3"
22
+ "@codemem/core": "^0.23.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/better-sqlite3": "^7.6.13",
26
26
  "@types/node": "^22.15.21",
27
27
  "better-sqlite3": "^12.8.0",
28
28
  "sqlite-vec": "0.1.7-alpha.2",
29
- "typescript": "^5.8.2",
30
- "vite": "8.0.1",
31
- "vitest": "4.0.17"
29
+ "typescript": "^5.9.3",
30
+ "vite": "^8.0.5",
31
+ "vitest": "^4.1.2"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
35
35
  "url": "git+https://github.com/kunickiaj/codemem.git",
36
36
  "directory": "packages/viewer-server"
37
37
  },
38
+ "engines": {
39
+ "node": ">=24"
40
+ },
38
41
  "license": "MIT",
39
42
  "publishConfig": {
40
43
  "access": "public"
41
44
  },
42
45
  "scripts": {
43
46
  "clean": "rm -rf dist tsconfig.tsbuildinfo",
44
- "build": "pnpm exec vite build --ssr src/index.ts --outDir dist && pnpm exec tsc --build --force",
47
+ "build": "pnpm exec vite build --ssr src/index.ts --outDir dist && pnpm exec tsc --build",
45
48
  "typecheck": "pnpm exec tsc --noEmit"
46
49
  }
47
50
  }
package/static/app.js CHANGED
@@ -481,6 +481,16 @@
481
481
  if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
482
482
  return payload;
483
483
  }
484
+ async function deactivateActor(actorId) {
485
+ const resp = await fetch("/api/sync/actors/deactivate", {
486
+ method: "POST",
487
+ headers: { "Content-Type": "application/json" },
488
+ body: JSON.stringify({ actor_id: actorId })
489
+ });
490
+ const { text, payload } = await readJsonPayload(resp);
491
+ if (!resp.ok) throw new Error(payloadError(payload) || text || "request failed");
492
+ return payload;
493
+ }
484
494
  async function claimLegacyDeviceIdentity(originDeviceId) {
485
495
  const resp = await fetch("/api/sync/legacy-devices/claim", {
486
496
  method: "POST",
@@ -1313,6 +1323,10 @@
1313
1323
  if (metadata?.is_summary === true) return true;
1314
1324
  return String(metadata?.source || "").trim().toLowerCase() === "observer_summary";
1315
1325
  }
1326
+ function canonicalKind(item, metadata) {
1327
+ const kindValue = String(item?.kind || "").trim().toLowerCase();
1328
+ return isSummaryLikeItem(item, metadata) ? "session_summary" : kindValue || "change";
1329
+ }
1316
1330
  function observationViewData(item) {
1317
1331
  const metadata = mergeMetadata(item?.metadata_json);
1318
1332
  const summary = String(item?.subtitle || item?.body_text || "").trim();
@@ -1494,10 +1508,9 @@
1494
1508
  }, display);
1495
1509
  }
1496
1510
  function FeedItemCard({ item }) {
1497
- const kindValue = String(item.kind || "session_summary").toLowerCase();
1498
1511
  const metadata = mergeMetadata(item?.metadata_json);
1499
1512
  const isSessionSummary = isSummaryLikeItem(item, metadata);
1500
- const displayKindValue = isSessionSummary ? "session_summary" : kindValue;
1513
+ const displayKindValue = canonicalKind(item, metadata);
1501
1514
  const rowKey = itemKey(item);
1502
1515
  const defaultTitle = item.title || "(untitled)";
1503
1516
  const displayTitle = isSessionSummary && metadata?.request ? metadata.request : defaultTitle;
@@ -4052,15 +4065,19 @@
4052
4065
  class: "diag-line",
4053
4066
  children: [/* @__PURE__ */ u("div", {
4054
4067
  class: "left",
4055
- children: [/* @__PURE__ */ u("div", { children: attempt.status }), /* @__PURE__ */ u("div", {
4068
+ children: [/* @__PURE__ */ u("div", { children: [
4069
+ attempt.peerLabel,
4070
+ " — ",
4071
+ attempt.status
4072
+ ] }), attempt.detail ? /* @__PURE__ */ u("div", {
4056
4073
  class: "small",
4057
- children: attempt.address
4058
- })]
4074
+ children: attempt.detail
4075
+ }) : null]
4059
4076
  }), /* @__PURE__ */ u("div", {
4060
4077
  class: "right",
4061
4078
  children: attempt.startedAt
4062
4079
  })]
4063
- }, `${attempt.startedAt}-${attempt.address}-${index}`)) });
4080
+ }, `${attempt.startedAt}-${attempt.peerLabel}-${index}`)) });
4064
4081
  }
4065
4082
  function PairingText({ text }) {
4066
4083
  return /* @__PURE__ */ u(k$2, { children: text });
@@ -4532,9 +4549,18 @@
4532
4549
  }
4533
4550
  renderAttemptsList(syncAttempts, attempts.slice(0, 5).map((attempt) => {
4534
4551
  const time = attempt.started_at || attempt.started_at_utc || "";
4552
+ const peerId = String(attempt.peer_device_id || "").trim();
4553
+ const matchedPeer = Array.isArray(state.lastSyncPeers) ? state.lastSyncPeers.find((p) => String(p?.peer_device_id || "") === peerId) : null;
4554
+ const peerLabel = String(matchedPeer?.name || "").trim() || (peerId ? peerId.slice(0, 8) : "unknown");
4555
+ const isError = attempt.status === "error";
4556
+ const detailParts = [];
4557
+ if (isError && attempt.error) detailParts.push(String(attempt.error));
4558
+ if (!isError && (attempt.ops_in || attempt.ops_out)) detailParts.push(`${attempt.ops_in ?? 0} in · ${attempt.ops_out ?? 0} out`);
4559
+ if (!isSyncRedactionEnabled() && attempt.address) detailParts.push(attempt.address);
4535
4560
  return {
4536
4561
  status: attempt.status || "unknown",
4537
- address: isSyncRedactionEnabled() ? redactAddress(attempt.address) : attempt.address || "n/a",
4562
+ peerLabel,
4563
+ detail: detailParts.join(" · "),
4538
4564
  startedAt: time ? formatTimestamp(time) : ""
4539
4565
  };
4540
4566
  }));
@@ -10337,18 +10363,33 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10337
10363
  displayName: String(request.display_name || request.device_id || "Pending device"),
10338
10364
  requestId: String(request.request_id || "")
10339
10365
  }));
10366
+ const visibleDiscoveredRows = discoveredRows.filter((row) => row.mode !== "paired" && row.mode !== "none" && row.mode !== "scope-pending");
10340
10367
  const discoveredActionableCount = discoveredRows.filter((row) => row.mode === "accept" || row.mode === "scope-pending").length;
10341
10368
  const actionableCount = attentionItems.length + pendingJoinRequests.length + discoveredActionableCount;
10369
+ const attentionParts = [];
10370
+ if (attentionItems.length > 0) {
10371
+ const repairItems = attentionItems.filter((item) => item.kind === "device-needs-repair");
10372
+ const nameItems = attentionItems.filter((item) => item.kind === "name-device");
10373
+ const reviewItems = attentionItems.filter((item) => item.kind === "review-team-device");
10374
+ const duplicateItems = attentionItems.filter((item) => item.kind === "possible-duplicate-person");
10375
+ if (repairItems.length > 0) attentionParts.push(`${repairItems.length} device${repairItems.length === 1 ? "" : "s"} to repair`);
10376
+ if (nameItems.length > 0) attentionParts.push(`${nameItems.length} device${nameItems.length === 1 ? "" : "s"} to name`);
10377
+ if (reviewItems.length > 0) attentionParts.push(`${reviewItems.length} device${reviewItems.length === 1 ? "" : "s"} to review`);
10378
+ if (duplicateItems.length > 0) attentionParts.push(`${duplicateItems.length} possible duplicate${duplicateItems.length === 1 ? "" : "s"}`);
10379
+ }
10380
+ if (pendingJoinRequests.length > 0) attentionParts.push(`${pendingJoinRequests.length} join request${pendingJoinRequests.length === 1 ? "" : "s"} to review`);
10381
+ if (discoveredActionableCount > 0) attentionParts.push(`${discoveredActionableCount} discovered device${discoveredActionableCount === 1 ? "" : "s"}`);
10382
+ const attentionDetail = attentionParts.join(", ");
10342
10383
  const teamLabel = (coordinator.groups || []).join(", ") || "none";
10343
10384
  const statusSummary = {
10344
10385
  badgeClassName: `pill ${presenceStatus === "posted" ? "pill-success" : presenceStatus === "not_enrolled" ? "pill-warning" : "pill-error"}`,
10345
- headline: presenceStatus === "posted" ? actionableCount > 0 ? `${actionableCount} item${actionableCount === 1 ? "" : "s"} need attention` : "Everything is healthy" : presenceStatus === "not_enrolled" ? "This device is not enrolled in the team yet" : "Sync needs attention",
10386
+ headline: presenceStatus === "posted" ? actionableCount > 0 ? attentionDetail : "Everything is healthy" : presenceStatus === "not_enrolled" ? "This device is not enrolled in the team yet" : "Sync needs attention",
10346
10387
  metricsText: metricParts.join(" · "),
10347
10388
  presenceLabel
10348
10389
  };
10349
10390
  meta.textContent = presenceStatus === "posted" ? actionableCount > 0 ? `Team: ${teamLabel}. Start with the next step below, then scan the current team status.` : `Team: ${teamLabel}. Team status and device details are below.` : presenceStatus === "not_enrolled" ? `Team: ${teamLabel}. Enroll this device first, then return here to review the rest of the team.` : `Team: ${teamLabel}. Fix the current sync issue first, then use the rest of this card to verify the team state.`;
10350
- if (discoveredPanel) discoveredPanel.hidden = discoveredRows.length === 0 && !state.syncDiscoveredFeedback;
10351
- if (discoveredMeta) discoveredMeta.textContent = discoveredRows.length ? "Review anything here that still needs trust, repair, or approval." : "";
10391
+ if (discoveredPanel) discoveredPanel.hidden = visibleDiscoveredRows.length === 0 && !state.syncDiscoveredFeedback;
10392
+ if (discoveredMeta) discoveredMeta.textContent = visibleDiscoveredRows.length ? "Review anything here that still needs trust, repair, or approval." : "";
10352
10393
  if (joinRequests) joinRequests.hidden = pendingJoinRequests.length === 0 && !state.syncJoinRequestsFeedback;
10353
10394
  teardownTeamSyncRender(actions, [
10354
10395
  list,
@@ -10376,7 +10417,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10376
10417
  presenceStatus
10377
10418
  }),
10378
10419
  discoveredListMount: discoveredList,
10379
- discoveredRows,
10420
+ discoveredRows: visibleDiscoveredRows,
10380
10421
  joinRequestsMount: joinRequests,
10381
10422
  listMount: list,
10382
10423
  onApproveJoinRequest: async (request) => {
@@ -10642,7 +10683,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10642
10683
  if (hiddenLocalDuplicateCount <= 0) return "Represents you across your devices.";
10643
10684
  return `Represents you across your devices. ${hiddenLocalDuplicateCount} unresolved duplicate ${hiddenLocalDuplicateCount === 1 ? "entry is" : "entries are"} hidden until reviewed in Needs attention.`;
10644
10685
  }
10645
- function SyncActorRow({ actor, hiddenLocalDuplicateCount, onRename, onMerge }) {
10686
+ function SyncActorRow({ actor, hiddenLocalDuplicateCount, onRename, onMerge, onDeactivate }) {
10646
10687
  const actorId = String(actor.actor_id || "");
10647
10688
  const label = actorLabel(actor);
10648
10689
  const count = assignedActorCount(actorId);
@@ -10775,12 +10816,26 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10775
10816
  /* @__PURE__ */ u("div", {
10776
10817
  className: "peer-meta actor-merge-note",
10777
10818
  children: mergeNote
10819
+ }),
10820
+ /* @__PURE__ */ u("button", {
10821
+ className: "settings-button",
10822
+ disabled: renameBusy || mergeBusy,
10823
+ onClick: async () => {
10824
+ if (await openSyncConfirmDialog({
10825
+ title: `Remove ${label}?`,
10826
+ description: "This deactivates the person and unassigns their devices. Existing memories keep their current attribution.",
10827
+ confirmLabel: "Remove person",
10828
+ cancelLabel: "Keep",
10829
+ tone: "danger"
10830
+ })) await onDeactivate(actorId);
10831
+ },
10832
+ children: "Remove person"
10778
10833
  })
10779
10834
  ] })
10780
10835
  })]
10781
10836
  });
10782
10837
  }
10783
- function SyncActorsList({ actors, hiddenLocalDuplicateCount, onRename, onMerge }) {
10838
+ function SyncActorsList({ actors, hiddenLocalDuplicateCount, onRename, onMerge, onDeactivate }) {
10784
10839
  if (!actors.length) return /* @__PURE__ */ u("div", {
10785
10840
  className: "sync-empty-state",
10786
10841
  children: [/* @__PURE__ */ u("strong", { children: "No people yet." }), /* @__PURE__ */ u("span", { children: "Create a named person here, then assign each device below to keep sync ownership readable." })]
@@ -10791,7 +10846,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
10791
10846
  actor,
10792
10847
  hiddenLocalDuplicateCount,
10793
10848
  onRename,
10794
- onMerge
10849
+ onMerge,
10850
+ onDeactivate
10795
10851
  }, actorId);
10796
10852
  }) });
10797
10853
  }
@@ -11286,6 +11342,16 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
11286
11342
  showGlobalNotice(friendlyError(error, "Failed to combine people."), "warning");
11287
11343
  throw error;
11288
11344
  }
11345
+ },
11346
+ onDeactivate: async (actorId) => {
11347
+ try {
11348
+ await deactivateActor(actorId);
11349
+ showGlobalNotice("Person removed. Assigned devices have been unassigned.");
11350
+ await _loadSyncData();
11351
+ } catch (error) {
11352
+ showGlobalNotice(friendlyError(error, "Failed to remove person."), "warning");
11353
+ throw error;
11354
+ }
11289
11355
  }
11290
11356
  });
11291
11357
  }
@@ -13294,7 +13360,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
13294
13360
  try {
13295
13361
  const runtime = await loadRuntimeInfo();
13296
13362
  if (!runtime?.version) return;
13297
- setRuntimeLabel(runtime.version, "e26a1af");
13363
+ setRuntimeLabel(runtime.version, "8d28296");
13298
13364
  } catch {}
13299
13365
  }
13300
13366
  var lastAnnouncedRefreshState = null;