@codemem/server 0.20.0-alpha.5 → 0.20.0-alpha.6

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.
@@ -4,12 +4,14 @@
4
4
  * Ports Python's viewer_routes/observer_status.py.
5
5
  * Returns observer runtime info, credential availability, and queue status.
6
6
  */
7
- import type { MemoryStore, RawEventSweeper } from "@codemem/core";
7
+ import type { ObserverClient } from "@codemem/core";
8
+ import { type MemoryStore, type RawEventSweeper } from "@codemem/core";
8
9
  import { Hono } from "hono";
9
10
  type StoreFactory = () => MemoryStore;
10
11
  export interface ObserverStatusDeps {
11
12
  getStore: StoreFactory;
12
13
  getSweeper: () => RawEventSweeper | null;
14
+ getObserver?: () => ObserverClient | null;
13
15
  }
14
16
  export declare function observerStatusRoutes(deps?: ObserverStatusDeps): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
15
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"observer-status.d.ts","sourceRoot":"","sources":["../../src/routes/observer-status.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,MAAM,eAAe,GAAG,IAAI,CAAC;CACzC;AAiBD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,kBAAkB,8EA2C7D"}
1
+ {"version":3,"file":"observer-status.d.ts","sourceRoot":"","sources":["../../src/routes/observer-status.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,WAAW,EAA6B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,MAAM,eAAe,GAAG,IAAI,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;CAC1C;AA6BD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,kBAAkB,8EAiD7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"raw-events.d.ts","sourceRoot":"","sources":["../../src/routes/raw-events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIlE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AAqFtC,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,8EA0UvF"}
1
+ {"version":3,"file":"raw-events.d.ts","sourceRoot":"","sources":["../../src/routes/raw-events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIlE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AA2FtC,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,8EA0UvF"}
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.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;AAyGtC,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,8EAyRhD"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AAqBhE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AAmXtC,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,8EAiiBhD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemem/server",
3
- "version": "0.20.0-alpha.5",
3
+ "version": "0.20.0-alpha.6",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -18,7 +18,7 @@
18
18
  "@hono/node-server": "^1.14.3",
19
19
  "drizzle-orm": "^0.45.1",
20
20
  "hono": "^4.7.10",
21
- "@codemem/core": "^0.20.0-alpha.5"
21
+ "@codemem/core": "^0.20.0-alpha.6"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/better-sqlite3": "^7.6.13",
package/static/app.js CHANGED
@@ -245,7 +245,7 @@
245
245
  return params.toString();
246
246
  }
247
247
  async function loadMemoriesPage(project, options) {
248
- return fetchJson(`/api/memories?${buildProjectParams(project, options?.limit, options?.offset, options?.scope)}`);
248
+ return fetchJson(`/api/observations?${buildProjectParams(project, options?.limit, options?.offset, options?.scope)}`);
249
249
  }
250
250
  async function updateMemoryVisibility(memoryId, visibility) {
251
251
  const resp = await fetch("/api/memories/visibility", {
@@ -727,8 +727,32 @@
727
727
  const metadata = item?.metadata_json;
728
728
  if (looksLikeSummary(metadata)) return metadata;
729
729
  if (looksLikeSummary(metadata?.summary)) return metadata.summary;
730
+ const bodyText = String(item?.body_text || "").trim();
731
+ if (bodyText.includes("## ")) {
732
+ const headingMap = {
733
+ request: "request",
734
+ completed: "completed",
735
+ learned: "learned",
736
+ investigated: "investigated",
737
+ "next steps": "next_steps",
738
+ notes: "notes"
739
+ };
740
+ const parsed = {};
741
+ const sectionRe = /(?:^|\n)##\s+([^\n]+)\n([\s\S]*?)(?=\n##\s+|$)/g;
742
+ for (let match = sectionRe.exec(bodyText); match; match = sectionRe.exec(bodyText)) {
743
+ const key = headingMap[String(match[1] || "").trim().toLowerCase()];
744
+ const content = String(match[2] || "").trim();
745
+ if (key && content) parsed[key] = content;
746
+ }
747
+ if (looksLikeSummary(parsed)) return parsed;
748
+ }
730
749
  return null;
731
750
  }
751
+ function isSummaryLikeItem(item, metadata) {
752
+ if (String(item?.kind || "").toLowerCase() === "session_summary") return true;
753
+ if (metadata?.is_summary === true) return true;
754
+ return String(metadata?.source || "").trim().toLowerCase() === "observer_summary";
755
+ }
732
756
  function observationViewData(item) {
733
757
  const metadata = mergeMetadata(item?.metadata_json);
734
758
  const summary = String(item?.subtitle || item?.body_text || "").trim();
@@ -869,6 +893,22 @@
869
893
  function renderFacts(facts) {
870
894
  const trimmed = facts.map((f) => String(f || "").trim()).filter(Boolean);
871
895
  if (!trimmed.length) return null;
896
+ if (trimmed.every((f) => /.+?:\s+.+/.test(f))) {
897
+ const container = el("div", "feed-body facts");
898
+ trimmed.forEach((fact) => {
899
+ const splitAt = fact.indexOf(":");
900
+ const labelText = fact.slice(0, splitAt).trim();
901
+ const contentText = fact.slice(splitAt + 1).trim();
902
+ if (!labelText || !contentText) return;
903
+ const row = el("div", "summary-section");
904
+ const label = el("div", "summary-section-label", labelText);
905
+ const value = el("div", "summary-section-content");
906
+ value.innerHTML = renderMarkdownSafe(contentText);
907
+ row.append(label, value);
908
+ container.appendChild(row);
909
+ });
910
+ if (container.childElementCount > 0) return container;
911
+ }
872
912
  const container = el("div", "feed-body");
873
913
  const list = document.createElement("ul");
874
914
  trimmed.forEach((f) => {
@@ -912,9 +952,10 @@
912
952
  }
913
953
  function renderFeedItem(item) {
914
954
  const kindValue = String(item.kind || "session_summary").toLowerCase();
915
- const isSessionSummary = kindValue === "session_summary";
916
955
  const metadata = mergeMetadata(item?.metadata_json);
917
- const card = el("div", `feed-item ${kindValue}`.trim());
956
+ const isSessionSummary = isSummaryLikeItem(item, metadata);
957
+ const displayKindValue = isSessionSummary ? "session_summary" : kindValue;
958
+ const card = el("div", `feed-item ${displayKindValue}`.trim());
918
959
  const rowKey = itemKey(item);
919
960
  card.dataset.key = rowKey;
920
961
  if (state.newItemKeys.has(rowKey)) {
@@ -930,7 +971,7 @@
930
971
  const displayTitle = isSessionSummary && metadata?.request ? metadata.request : defaultTitle;
931
972
  const title = el("div", "feed-title title");
932
973
  title.innerHTML = highlightText(displayTitle, state.feedQuery);
933
- const kind = el("span", `kind-pill ${kindValue}`.trim(), kindValue.replace(/_/g, " "));
974
+ const kind = el("span", `kind-pill ${displayKindValue}`.trim(), displayKindValue.replace(/_/g, " "));
934
975
  titleWrap.append(kind, title);
935
976
  const rightWrap = el("div", "feed-actions");
936
977
  const createdAtRaw = item.created_at || item.created_at_utc;
@@ -939,7 +980,10 @@
939
980
  const footerRight = el("div", "feed-footer-right");
940
981
  let bodyNode = el("div", "feed-body");
941
982
  if (isSessionSummary) {
942
- const summaryObj = getSummaryObject({ metadata_json: metadata });
983
+ const summaryObj = getSummaryObject({
984
+ ...item,
985
+ metadata_json: metadata
986
+ });
943
987
  bodyNode = (summaryObj ? renderSummaryObject(summaryObj) : null) || renderNarrative(String(item.body_text || "")) || bodyNode;
944
988
  } else {
945
989
  const data = observationViewData({
@@ -1074,8 +1118,8 @@
1074
1118
  return card;
1075
1119
  }
1076
1120
  function filterByType(items) {
1077
- if (state.feedTypeFilter === "observations") return items.filter((i) => String(i.kind || "").toLowerCase() !== "session_summary");
1078
- if (state.feedTypeFilter === "summaries") return items.filter((i) => String(i.kind || "").toLowerCase() === "session_summary");
1121
+ if (state.feedTypeFilter === "observations") return items.filter((i) => !isSummaryLikeItem(i, mergeMetadata(i?.metadata_json)));
1122
+ if (state.feedTypeFilter === "summaries") return items.filter((i) => isSummaryLikeItem(i, mergeMetadata(i?.metadata_json)));
1079
1123
  return items;
1080
1124
  }
1081
1125
  function filterByQuery(items) {
@@ -2871,6 +2915,10 @@
2871
2915
  model: DEFAULT_ANTHROPIC_MODEL,
2872
2916
  source: "Recommended (Anthropic provider)"
2873
2917
  };
2918
+ if (provider === "opencode") return {
2919
+ model: "opencode/gpt-5.1-codex-mini",
2920
+ source: "Recommended (OpenCode Zen provider)"
2921
+ };
2874
2922
  if (provider && provider !== "openai") return {
2875
2923
  model: "provider default",
2876
2924
  source: "Recommended (provider default)"