@codemem/server 0.20.0-alpha.5 → 0.20.0-alpha.7
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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +546 -69
- package/dist/index.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/memory.d.ts.map +1 -1
- package/dist/routes/observer-status.d.ts +3 -1
- package/dist/routes/observer-status.d.ts.map +1 -1
- package/dist/routes/raw-events.d.ts.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +98 -10
|
@@ -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 {
|
|
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,
|
|
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;
|
|
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;
|
|
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,8EAuiBhD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemem/server",
|
|
3
|
-
"version": "0.20.0-alpha.
|
|
3
|
+
"version": "0.20.0-alpha.7",
|
|
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.
|
|
21
|
+
"@codemem/core": "^0.20.0-alpha.7"
|
|
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/
|
|
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", {
|
|
@@ -287,10 +287,11 @@
|
|
|
287
287
|
}
|
|
288
288
|
return parsed;
|
|
289
289
|
}
|
|
290
|
-
async function loadSyncStatus(includeDiagnostics, project = "") {
|
|
290
|
+
async function loadSyncStatus(includeDiagnostics, project = "", options) {
|
|
291
291
|
const params = new URLSearchParams();
|
|
292
292
|
if (includeDiagnostics) params.set("includeDiagnostics", "1");
|
|
293
293
|
if (project) params.set("project", project);
|
|
294
|
+
if (options?.includeJoinRequests) params.set("includeJoinRequests", "1");
|
|
294
295
|
return fetchJson(`/api/sync/status${params.size ? `?${params.toString()}` : ""}`);
|
|
295
296
|
}
|
|
296
297
|
async function createCoordinatorInvite(payload) {
|
|
@@ -727,8 +728,32 @@
|
|
|
727
728
|
const metadata = item?.metadata_json;
|
|
728
729
|
if (looksLikeSummary(metadata)) return metadata;
|
|
729
730
|
if (looksLikeSummary(metadata?.summary)) return metadata.summary;
|
|
731
|
+
const bodyText = String(item?.body_text || "").trim();
|
|
732
|
+
if (bodyText.includes("## ")) {
|
|
733
|
+
const headingMap = {
|
|
734
|
+
request: "request",
|
|
735
|
+
completed: "completed",
|
|
736
|
+
learned: "learned",
|
|
737
|
+
investigated: "investigated",
|
|
738
|
+
"next steps": "next_steps",
|
|
739
|
+
notes: "notes"
|
|
740
|
+
};
|
|
741
|
+
const parsed = {};
|
|
742
|
+
const sectionRe = /(?:^|\n)##\s+([^\n]+)\n([\s\S]*?)(?=\n##\s+|$)/g;
|
|
743
|
+
for (let match = sectionRe.exec(bodyText); match; match = sectionRe.exec(bodyText)) {
|
|
744
|
+
const key = headingMap[String(match[1] || "").trim().toLowerCase()];
|
|
745
|
+
const content = String(match[2] || "").trim();
|
|
746
|
+
if (key && content) parsed[key] = content;
|
|
747
|
+
}
|
|
748
|
+
if (looksLikeSummary(parsed)) return parsed;
|
|
749
|
+
}
|
|
730
750
|
return null;
|
|
731
751
|
}
|
|
752
|
+
function isSummaryLikeItem(item, metadata) {
|
|
753
|
+
if (String(item?.kind || "").toLowerCase() === "session_summary") return true;
|
|
754
|
+
if (metadata?.is_summary === true) return true;
|
|
755
|
+
return String(metadata?.source || "").trim().toLowerCase() === "observer_summary";
|
|
756
|
+
}
|
|
732
757
|
function observationViewData(item) {
|
|
733
758
|
const metadata = mergeMetadata(item?.metadata_json);
|
|
734
759
|
const summary = String(item?.subtitle || item?.body_text || "").trim();
|
|
@@ -869,6 +894,22 @@
|
|
|
869
894
|
function renderFacts(facts) {
|
|
870
895
|
const trimmed = facts.map((f) => String(f || "").trim()).filter(Boolean);
|
|
871
896
|
if (!trimmed.length) return null;
|
|
897
|
+
if (trimmed.every((f) => /.+?:\s+.+/.test(f))) {
|
|
898
|
+
const container = el("div", "feed-body facts");
|
|
899
|
+
trimmed.forEach((fact) => {
|
|
900
|
+
const splitAt = fact.indexOf(":");
|
|
901
|
+
const labelText = fact.slice(0, splitAt).trim();
|
|
902
|
+
const contentText = fact.slice(splitAt + 1).trim();
|
|
903
|
+
if (!labelText || !contentText) return;
|
|
904
|
+
const row = el("div", "summary-section");
|
|
905
|
+
const label = el("div", "summary-section-label", labelText);
|
|
906
|
+
const value = el("div", "summary-section-content");
|
|
907
|
+
value.innerHTML = renderMarkdownSafe(contentText);
|
|
908
|
+
row.append(label, value);
|
|
909
|
+
container.appendChild(row);
|
|
910
|
+
});
|
|
911
|
+
if (container.childElementCount > 0) return container;
|
|
912
|
+
}
|
|
872
913
|
const container = el("div", "feed-body");
|
|
873
914
|
const list = document.createElement("ul");
|
|
874
915
|
trimmed.forEach((f) => {
|
|
@@ -912,9 +953,10 @@
|
|
|
912
953
|
}
|
|
913
954
|
function renderFeedItem(item) {
|
|
914
955
|
const kindValue = String(item.kind || "session_summary").toLowerCase();
|
|
915
|
-
const isSessionSummary = kindValue === "session_summary";
|
|
916
956
|
const metadata = mergeMetadata(item?.metadata_json);
|
|
917
|
-
const
|
|
957
|
+
const isSessionSummary = isSummaryLikeItem(item, metadata);
|
|
958
|
+
const displayKindValue = isSessionSummary ? "session_summary" : kindValue;
|
|
959
|
+
const card = el("div", `feed-item ${displayKindValue}`.trim());
|
|
918
960
|
const rowKey = itemKey(item);
|
|
919
961
|
card.dataset.key = rowKey;
|
|
920
962
|
if (state.newItemKeys.has(rowKey)) {
|
|
@@ -930,7 +972,7 @@
|
|
|
930
972
|
const displayTitle = isSessionSummary && metadata?.request ? metadata.request : defaultTitle;
|
|
931
973
|
const title = el("div", "feed-title title");
|
|
932
974
|
title.innerHTML = highlightText(displayTitle, state.feedQuery);
|
|
933
|
-
const kind = el("span", `kind-pill ${
|
|
975
|
+
const kind = el("span", `kind-pill ${displayKindValue}`.trim(), displayKindValue.replace(/_/g, " "));
|
|
934
976
|
titleWrap.append(kind, title);
|
|
935
977
|
const rightWrap = el("div", "feed-actions");
|
|
936
978
|
const createdAtRaw = item.created_at || item.created_at_utc;
|
|
@@ -939,7 +981,10 @@
|
|
|
939
981
|
const footerRight = el("div", "feed-footer-right");
|
|
940
982
|
let bodyNode = el("div", "feed-body");
|
|
941
983
|
if (isSessionSummary) {
|
|
942
|
-
const summaryObj = getSummaryObject({
|
|
984
|
+
const summaryObj = getSummaryObject({
|
|
985
|
+
...item,
|
|
986
|
+
metadata_json: metadata
|
|
987
|
+
});
|
|
943
988
|
bodyNode = (summaryObj ? renderSummaryObject(summaryObj) : null) || renderNarrative(String(item.body_text || "")) || bodyNode;
|
|
944
989
|
} else {
|
|
945
990
|
const data = observationViewData({
|
|
@@ -1074,8 +1119,8 @@
|
|
|
1074
1119
|
return card;
|
|
1075
1120
|
}
|
|
1076
1121
|
function filterByType(items) {
|
|
1077
|
-
if (state.feedTypeFilter === "observations") return items.filter((i) =>
|
|
1078
|
-
if (state.feedTypeFilter === "summaries") return items.filter((i) =>
|
|
1122
|
+
if (state.feedTypeFilter === "observations") return items.filter((i) => !isSummaryLikeItem(i, mergeMetadata(i?.metadata_json)));
|
|
1123
|
+
if (state.feedTypeFilter === "summaries") return items.filter((i) => isSummaryLikeItem(i, mergeMetadata(i?.metadata_json)));
|
|
1079
1124
|
return items;
|
|
1080
1125
|
}
|
|
1081
1126
|
function filterByQuery(items) {
|
|
@@ -2724,9 +2769,48 @@
|
|
|
2724
2769
|
//#endregion
|
|
2725
2770
|
//#region src/tabs/sync/index.ts
|
|
2726
2771
|
var lastSyncHash = "";
|
|
2772
|
+
var cachedSyncStatus = null;
|
|
2773
|
+
var HEALTH_SYNC_STATUS_CACHE_TTL_MS = 15e3;
|
|
2774
|
+
function syncStatusCacheKey(project) {
|
|
2775
|
+
return `project:${project || ""}|includeJoinRequests:false`;
|
|
2776
|
+
}
|
|
2777
|
+
function readCachedSyncStatus(project) {
|
|
2778
|
+
const key = syncStatusCacheKey(project);
|
|
2779
|
+
if (!cachedSyncStatus) return null;
|
|
2780
|
+
if (cachedSyncStatus.key !== key) return null;
|
|
2781
|
+
if (Date.now() >= cachedSyncStatus.expiresAtMs) return null;
|
|
2782
|
+
return cachedSyncStatus.payload;
|
|
2783
|
+
}
|
|
2784
|
+
function writeCachedSyncStatus(project, payload) {
|
|
2785
|
+
cachedSyncStatus = {
|
|
2786
|
+
key: syncStatusCacheKey(project),
|
|
2787
|
+
expiresAtMs: Date.now() + HEALTH_SYNC_STATUS_CACHE_TTL_MS,
|
|
2788
|
+
payload
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
function normalizeSyncStatusForCache(payload) {
|
|
2792
|
+
if (!payload || typeof payload !== "object") return payload;
|
|
2793
|
+
return {
|
|
2794
|
+
...payload,
|
|
2795
|
+
join_requests: []
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2727
2798
|
async function loadSyncData() {
|
|
2728
2799
|
try {
|
|
2729
|
-
const
|
|
2800
|
+
const project = state.currentProject || "";
|
|
2801
|
+
const includeJoinRequests = state.activeTab === "sync";
|
|
2802
|
+
const useCache = state.activeTab === "health";
|
|
2803
|
+
let payload;
|
|
2804
|
+
if (useCache) {
|
|
2805
|
+
payload = readCachedSyncStatus(project);
|
|
2806
|
+
if (!payload) {
|
|
2807
|
+
payload = await loadSyncStatus(true, project, { includeJoinRequests: false });
|
|
2808
|
+
writeCachedSyncStatus(project, normalizeSyncStatusForCache(payload));
|
|
2809
|
+
}
|
|
2810
|
+
} else {
|
|
2811
|
+
payload = await loadSyncStatus(true, project, { includeJoinRequests });
|
|
2812
|
+
writeCachedSyncStatus(project, normalizeSyncStatusForCache(payload));
|
|
2813
|
+
}
|
|
2730
2814
|
let actorsPayload = null;
|
|
2731
2815
|
let actorLoadError = false;
|
|
2732
2816
|
try {
|
|
@@ -2743,7 +2827,7 @@
|
|
|
2743
2827
|
state.lastSyncPeers = payload.peers || [];
|
|
2744
2828
|
state.lastSyncSharingReview = payload.sharing_review || [];
|
|
2745
2829
|
state.lastSyncCoordinator = payload.coordinator || null;
|
|
2746
|
-
state.lastSyncJoinRequests = payload.join_requests
|
|
2830
|
+
if (Array.isArray(payload.join_requests)) state.lastSyncJoinRequests = payload.join_requests;
|
|
2747
2831
|
state.lastSyncAttempts = payload.attempts || [];
|
|
2748
2832
|
state.lastSyncLegacyDevices = payload.legacy_devices || [];
|
|
2749
2833
|
renderSyncStatus();
|
|
@@ -2871,6 +2955,10 @@
|
|
|
2871
2955
|
model: DEFAULT_ANTHROPIC_MODEL,
|
|
2872
2956
|
source: "Recommended (Anthropic provider)"
|
|
2873
2957
|
};
|
|
2958
|
+
if (provider === "opencode") return {
|
|
2959
|
+
model: "opencode/gpt-5.1-codex-mini",
|
|
2960
|
+
source: "Recommended (OpenCode Zen provider)"
|
|
2961
|
+
};
|
|
2874
2962
|
if (provider && provider !== "openai") return {
|
|
2875
2963
|
model: "provider default",
|
|
2876
2964
|
source: "Recommended (provider default)"
|