dsh-engram 0.3.3 → 0.3.4

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/lib/client.js CHANGED
@@ -4,6 +4,7 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ "use strict";
7
8
  var __defProp = Object.defineProperty;
8
9
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
10
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -217,6 +218,44 @@ function useEngramTheme() {
217
218
  return { dark, vars };
218
219
  }
219
220
 
221
+ // client/src/esrModel.ts
222
+ function taskGaps(t) {
223
+ const gaps = [];
224
+ if (!t.artifact) gaps.push("artifact");
225
+ if (!t.evaluation) gaps.push("evaluation");
226
+ if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
227
+ return gaps;
228
+ }
229
+ function shortId(id) {
230
+ return id.length > 12 ? `${id.slice(0, 6)}\u2026${id.slice(-4)}` : id;
231
+ }
232
+ function blockedBy(t, all) {
233
+ if (t.state === "stable") return 0;
234
+ const open = new Set(all.filter((x) => x.state !== "stable").map((x) => x.id));
235
+ return (t.deps ?? []).filter((d) => d.kind !== "relates-to" && open.has(d.id)).length;
236
+ }
237
+ function shortAgent(a) {
238
+ if (!a) return "";
239
+ const bare = a.split(/[@#/:\\]+/).pop();
240
+ return bare.replace(/^session[-_]/i, "").replace(/^agent[-_]/i, "").slice(0, 14);
241
+ }
242
+ function fmtDateShort(ts) {
243
+ return ts ? new Date(ts).toLocaleDateString("zh-CN", { month: "short", day: "numeric" }) : "\u2013";
244
+ }
245
+ function buildTasksMarkdown(tasks) {
246
+ const esc = (s4) => String(s4 ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ");
247
+ const rows = tasks.slice().sort((a, b) => a.state.localeCompare(b.state) || (a.createdAt ?? 0) - (b.createdAt ?? 0)).map((t) => {
248
+ const ev = `${t.artifact ? "artifact\u2713" : "artifact\u2717"} \xB7 ${t.evaluation ? "eval\u2713" : "eval\u2717"} \xB7 ${(t.memoryRefs?.length ?? 0) > 0 ? "ref\u2713" : "ref\u2717"}`;
249
+ return `| ${t.state} | ${esc(t.name)} | ${esc(t.workspace.replace(/^.*[\\/]/, ""))} | ${esc(taskGaps(t).join(", ") || "\u2014")} | ${ev} | ${fmtDateShort(t.createdAt ?? 0)} |`;
250
+ });
251
+ return `# ESR \u4EFB\u52A1\u5BFC\u51FA \xB7 ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
252
+
253
+ | \u72B6\u6001 | \u4EFB\u52A1 | \u5DE5\u4F5C\u533A | \u8BC1\u636E\u7F3A\u53E3 | \u8BC1\u636E | \u521B\u5EFA |
254
+ |---|---|---|---|---|---|
255
+ ${rows.join("\n") || "(\u65E0\u4EFB\u52A1)"}`;
256
+ }
257
+ var POLL_MS = 2e4;
258
+
220
259
  // client/src/EngramTaskDock.tsx
221
260
  var import_jsx_runtime = require("react/jsx-runtime");
222
261
  var EMPTY = { tasks: [], links: [], nodes: [], denied: false, error: null, loading: true };
@@ -233,13 +272,6 @@ function fmtD(ts) {
233
272
  const p = (n) => String(n).padStart(2, "0");
234
273
  return `${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
235
274
  }
236
- var taskGaps = (t) => {
237
- const gaps = [];
238
- if (!t.artifact) gaps.push("artifact");
239
- if (!t.evaluation) gaps.push("evaluation");
240
- if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
241
- return gaps;
242
- };
243
275
  var STATUS = {
244
276
  gap: { bg: "var(--dsw-alias-state-warn-secondary, rgba(245,158,11,.14))", fg: "var(--dsw-alias-state-warn-label, #b45309)" },
245
277
  ready: { bg: "rgba(59,130,246,.13)", fg: "var(--dsw-alias-label-primary-bluish, #1d4ed8)" },
@@ -398,7 +430,7 @@ function EngramTaskDock({ sessionId, useSessions, useWorkspaces, useProjection,
398
430
  (0, import_react2.useEffect)(() => {
399
431
  if (!effWs || data.denied) return;
400
432
  if (pollRef.current !== null) window.clearInterval(pollRef.current);
401
- pollRef.current = window.setInterval(() => void load(), 15e3);
433
+ pollRef.current = window.setInterval(() => void load(), POLL_MS);
402
434
  return () => {
403
435
  if (pollRef.current !== null) window.clearInterval(pollRef.current);
404
436
  pollRef.current = null;
@@ -1340,7 +1372,7 @@ function EngramGraph({ workspace, entities, tasks, links, nameOf }) {
1340
1372
  setView({ x: pan.current.vx + dx, y: pan.current.vy + dy, k: view.k });
1341
1373
  }
1342
1374
  };
1343
- const endPointer = (e) => {
1375
+ const endPointer = () => {
1344
1376
  if (dragging.current) {
1345
1377
  const p = posRef.current.get(dragging.current.id);
1346
1378
  if (p) {
@@ -1652,7 +1684,7 @@ function EngramPreview({ api, workspace, defaultWorkspace, workspaces }) {
1652
1684
  );
1653
1685
  (0, import_react4.useEffect)(() => {
1654
1686
  void refresh();
1655
- const id = setInterval(() => void refresh(), 2e4);
1687
+ const id = setInterval(() => void refresh(), POLL_MS);
1656
1688
  return () => clearInterval(id);
1657
1689
  }, [refresh]);
1658
1690
  const copy = (which) => {
@@ -1963,13 +1995,12 @@ function EngramTelemetry({ api, workspace }) {
1963
1995
  );
1964
1996
  (0, import_react5.useEffect)(() => {
1965
1997
  void refresh();
1966
- const id = setInterval(() => void refresh(), 2e4);
1998
+ const id = setInterval(() => void refresh(), POLL_MS);
1967
1999
  return () => clearInterval(id);
1968
2000
  }, [refresh]);
1969
2001
  const toolRows = (0, import_react5.useMemo)(() => {
1970
2002
  if (!stats) return [];
1971
2003
  const entries = Object.entries(stats.totals.counts ?? {}).sort((a, b) => b[1] - a[1]);
1972
- const max = entries.length > 0 ? entries[0][1] : 0;
1973
2004
  return entries.slice(0, 8).map(([name, count]) => ({
1974
2005
  name,
1975
2006
  count,
@@ -2193,7 +2224,7 @@ function gapsOf(t) {
2193
2224
  if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
2194
2225
  return gaps;
2195
2226
  }
2196
- function EngramDetail({ target, api, memories, tasks, nodes, links, onClose, onNavigateMemory, onChanged }) {
2227
+ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMemory, onChanged }) {
2197
2228
  const { dark, vars } = useEngramTheme();
2198
2229
  const [gArt, setGArt] = (0, import_react6.useState)("");
2199
2230
  const [gEval, setGEval] = (0, import_react6.useState)("");
@@ -2687,13 +2718,6 @@ function StatCard({ num, label }) {
2687
2718
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: s2.cardLabel, children: label })
2688
2719
  ] });
2689
2720
  }
2690
- function taskGaps2(t) {
2691
- const gaps = [];
2692
- if (!t.artifact) gaps.push("artifact");
2693
- if (!t.evaluation) gaps.push("evaluation");
2694
- if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
2695
- return gaps;
2696
- }
2697
2721
  function groupByWorkspace(items) {
2698
2722
  const groups = /* @__PURE__ */ new Map();
2699
2723
  for (const m of items) {
@@ -2742,7 +2766,7 @@ function EngramSection({ api, t }) {
2742
2766
  const ov = await api.overview();
2743
2767
  setOverview(ov);
2744
2768
  const wsList = workspace ? [workspace] : Object.keys(ov.workspaces);
2745
- const [mem, taskGroups2, linkGroups2, nodeGroups2, st] = await Promise.all([
2769
+ const [mem, taskGroups2, linkGroups2, nodeGroups2] = await Promise.all([
2746
2770
  api.memories({
2747
2771
  workspace: workspace || void 0,
2748
2772
  q: q || void 0,
@@ -2765,6 +2789,8 @@ function EngramSection({ api, t }) {
2765
2789
  }, [api, workspace, q, kind, status]);
2766
2790
  (0, import_react7.useEffect)(() => {
2767
2791
  void refresh();
2792
+ const id = setInterval(() => void refresh(), POLL_MS);
2793
+ return () => clearInterval(id);
2768
2794
  }, [refresh]);
2769
2795
  const workspaces = (0, import_react7.useMemo)(() => overview ? Object.keys(overview.workspaces) : [], [overview]);
2770
2796
  const kindsPresent = (0, import_react7.useMemo)(() => overview ? Object.keys(overview.kinds) : [], [overview]);
@@ -3002,11 +3028,11 @@ function EngramSection({ api, t }) {
3002
3028
  ] }, t2.id)),
3003
3029
  gcReport.removedLinks.slice(0, 3).map((l) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.mono, children: [
3004
3030
  "- link ",
3005
- l.source.slice(0, 8),
3031
+ (l.source ?? "?").slice(0, 8),
3006
3032
  " --",
3007
- l.relation,
3033
+ l.relation ?? "",
3008
3034
  "--> ",
3009
- l.target.slice(0, 8)
3035
+ (l.target ?? "?").slice(0, 8)
3010
3036
  ] }, l.id))
3011
3037
  ] })
3012
3038
  ] }),
@@ -3088,7 +3114,7 @@ function EngramSection({ api, t }) {
3088
3114
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: { ...s2.td, minWidth: 0 }, children: [
3089
3115
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { title: r.m.text, style: expandedRows.has(r.m.id) ? s2.expanded : s2.clamp3, children: r.m.text }),
3090
3116
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", marginTop: 2, flexWrap: "wrap" }, children: [
3091
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...s2.mono, ...s2.ellipsis, flex: "1 1 160px" }, title: `${fmtDate2(r.m.createdAt)} \xB7 ${r.m.id} \xB7 ${r.m.entity ?? ""} \xB7 signal ${r.m.signal.toFixed(2)} \xB7 hits ${r.m.hits} \xB7 TTL ${daysLeft2(r.m.expiresAt)}`, children: [
3117
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...s2.mono, flex: "1 1 160px" }, title: `${fmtDate2(r.m.createdAt)} \xB7 ${r.m.id} \xB7 ${r.m.entity ?? ""} \xB7 signal ${r.m.signal.toFixed(2)} \xB7 hits ${r.m.hits} \xB7 TTL ${daysLeft2(r.m.expiresAt)}`, children: [
3092
3118
  fmtDate2(r.m.createdAt),
3093
3119
  " \xB7 ",
3094
3120
  r.m.id.slice(0, 8),
@@ -3184,7 +3210,7 @@ ${r.m.text.slice(0, 60)}`)) void act(() => api.remove(r.m.id, r.m.workspace));
3184
3210
  " \u4E2A\u4EFB\u52A1"
3185
3211
  ] }),
3186
3212
  items.map((task) => {
3187
- const gaps = taskGaps2(task);
3213
+ const gaps = taskGaps(task);
3188
3214
  const isStable = task.state === "stable";
3189
3215
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.subPanel, children: [
3190
3216
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { fontWeight: 600, fontSize: 13 }, children: [
@@ -3297,7 +3323,6 @@ ${r.m.text.slice(0, 60)}`)) void act(() => api.remove(r.m.id, r.m.workspace));
3297
3323
  {
3298
3324
  target: detail,
3299
3325
  api,
3300
- memories,
3301
3326
  tasks,
3302
3327
  nodes,
3303
3328
  links,
@@ -3345,7 +3370,7 @@ var ADVANCED_GROUPS = [
3345
3370
  title: "\u751F\u547D\u5468\u671F\u4E0E GC\uFF08\u9AD8\u7EA7\uFF09",
3346
3371
  description: "\u5BB9\u91CF\u4E0A\u9650\u4E0E\u5B9A\u671F\u56DE\u6536\uFF08\u81EA\u52A8 GC = \u66FF\u4EE3 DSH \u81EA\u52A8 compact\uFF09",
3347
3372
  fields: [
3348
- { key: "maxMemoriesPerWorkspace", label: "\u5DE5\u4F5C\u533A\u8BB0\u5FC6\u4E0A\u9650", kind: "num", min: 0, max: 1e4 },
3373
+ { key: "maxMemoriesPerWorkspace", label: "\u5DE5\u4F5C\u533A\u8BB0\u5FC6\u4E0A\u9650", hint: "\u5355\u5DE5\u4F5C\u533A\u5BB9\u91CF\u4E0A\u9650\uFF08GC \u5F52\u6863\u8D85\u9650\u6761\u76EE\uFF09", kind: "num", min: 0, max: 1e4 },
3349
3374
  { key: "gcEnabled", label: "\u8BB0\u5FC6 GC", hint: "\u5B9A\u65F6\u56DE\u6536\uFF08\u8FC7\u671F/\u8D85\u5BB9\u91CF/stable \u8D85\u7A97/\u60AC\u7A7A\u94FE\u63A5\uFF09", kind: "bool" },
3350
3375
  { key: "gcNarrative", label: "Context GC \u53D9\u4E8B\u515C\u5E95", hint: "\u81EA\u52A8 compact \u65F6\u65E0\u951A\u8F6E\u6B21\u7528 LLM \u6458\u8981\uFF1B\u5173\u6389=\u7EAF\u673A\u68B0\uFF08\u96F6 LLM\uFF09", kind: "bool" },
3351
3376
  { key: "gcStableRetentionDays", label: "stable \u4EFB\u52A1\u4FDD\u7559\uFF08\u5929\uFF09", hint: "\u8D85\u7A97\u540E\u7531 GC \u5F52\u6863\u3001\u79BB\u5F00 [ESR] \u8868\u9762", kind: "num", min: 0, max: 3650 },
@@ -3836,20 +3861,12 @@ var import_client = require("react-dom/client");
3836
3861
  // client/src/EngramBoard.tsx
3837
3862
  var import_react9 = require("react");
3838
3863
  var import_jsx_runtime9 = require("react/jsx-runtime");
3839
- function taskGaps3(t) {
3840
- const gaps = [];
3841
- if (!t.artifact) gaps.push("artifact");
3842
- if (!t.evaluation) gaps.push("evaluation");
3843
- if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
3844
- return gaps;
3845
- }
3846
3864
  var COLUMNS = [
3847
3865
  { key: "draft", title: "\u8349\u7A3F", sub: "\u672A\u88AB\u6FC0\u6D3B", color: "#94a3b8", match: (t) => t.state === "draft" },
3848
- { key: "gapped", title: "\u8FDB\u884C\u4E2D", sub: "\u8BC1\u636E\u6709\u7F3A\u53E3", color: "#f59e0b", match: (t) => t.state === "active" && taskGaps3(t).length > 0 },
3849
- { key: "ready", title: "\u5C31\u7EEA", sub: "\u8BC1\u636E\u9F50\uFF0C\u53EF\u95ED\u73AF", color: "#10b981", match: (t) => t.state === "active" && taskGaps3(t).length === 0 },
3866
+ { key: "gapped", title: "\u8FDB\u884C\u4E2D", sub: "\u8BC1\u636E\u6709\u7F3A\u53E3", color: "#f59e0b", match: (t) => t.state === "active" && taskGaps(t).length > 0 },
3867
+ { key: "ready", title: "\u5C31\u7EEA", sub: "\u8BC1\u636E\u9F50\uFF0C\u53EF\u95ED\u73AF", color: "#10b981", match: (t) => t.state === "active" && taskGaps(t).length === 0 },
3850
3868
  { key: "stable", title: "\u5DF2\u95ED\u73AF", sub: "\u51ED\u636E\u9F50\u5907", color: "#6366f1", match: (t) => t.state === "stable" }
3851
3869
  ];
3852
- var fmtDate3 = (ts) => ts ? new Date(ts).toLocaleDateString("zh-CN", { month: "short", day: "numeric" }) : "\u2013";
3853
3870
  function buildCloseEvidence(bulkArtifact, bulkEval, bulkRefs, task) {
3854
3871
  const refs = bulkRefs.split(/[,\s]+/).map((x) => x.trim()).filter(Boolean);
3855
3872
  return {
@@ -3858,31 +3875,6 @@ function buildCloseEvidence(bulkArtifact, bulkEval, bulkRefs, task) {
3858
3875
  memoryRefs: refs.length > 0 ? refs : task.memoryRefs
3859
3876
  };
3860
3877
  }
3861
- function buildTasksMarkdown(tasks) {
3862
- const esc = (s4) => String(s4 ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ");
3863
- const rows = tasks.slice().sort((a, b) => a.state.localeCompare(b.state) || (a.createdAt ?? 0) - (b.createdAt ?? 0)).map((t) => {
3864
- const ev = `${t.artifact ? "artifact\u2713" : "artifact\u2717"} \xB7 ${t.evaluation ? "eval\u2713" : "eval\u2717"} \xB7 ${(t.memoryRefs?.length ?? 0) > 0 ? "ref\u2713" : "ref\u2717"}`;
3865
- return `| ${t.state} | ${esc(t.name)} | ${esc(t.workspace.replace(/^.*[\\/]/, ""))} | ${esc(taskGaps3(t).join(", ") || "\u2014")} | ${ev} | ${fmtDate3(t.createdAt ?? 0)} |`;
3866
- });
3867
- return `# ESR \u4EFB\u52A1\u5BFC\u51FA \xB7 ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
3868
-
3869
- | \u72B6\u6001 | \u4EFB\u52A1 | \u5DE5\u4F5C\u533A | \u8BC1\u636E\u7F3A\u53E3 | \u8BC1\u636E | \u521B\u5EFA |
3870
- |---|---|---|---|---|---|
3871
- ${rows.join("\n") || "(\u65E0\u4EFB\u52A1)"}`;
3872
- }
3873
- function shortId(id) {
3874
- return id.length > 12 ? `${id.slice(0, 6)}\u2026${id.slice(-4)}` : id;
3875
- }
3876
- function blockedBy(t, all) {
3877
- if (t.state === "stable") return 0;
3878
- const open = new Set(all.filter((x) => x.state !== "stable").map((x) => x.id));
3879
- return (t.deps ?? []).filter((d) => d.kind !== "relates-to" && open.has(d.id)).length;
3880
- }
3881
- function shortAgent(a) {
3882
- if (!a) return "";
3883
- const bare = a.split(/[@#/:\\]+/).pop();
3884
- return bare.replace(/^session[-_]/i, "").replace(/^agent[-_]/i, "").slice(0, 14);
3885
- }
3886
3878
  var TREND_LABEL = {
3887
3879
  new: "\u65B0",
3888
3880
  strengthening: "\u589E\u5F3A",
@@ -3918,7 +3910,6 @@ function EngramBoard({ api, onRequestClose }) {
3918
3910
  const [bulkRefs, setBulkRefs] = (0, import_react9.useState)("");
3919
3911
  const [bulkBusy, setBulkBusy] = (0, import_react9.useState)(false);
3920
3912
  const [bulkMsg, setBulkMsg] = (0, import_react9.useState)(null);
3921
- const loadedWs = (0, import_react9.useRef)(/* @__PURE__ */ new Set());
3922
3913
  const [obsItems, setObsItems] = (0, import_react9.useState)(null);
3923
3914
  const [obsOpen, setObsOpen] = (0, import_react9.useState)(false);
3924
3915
  const [model, setModel] = (0, import_react9.useState)(null);
@@ -3931,10 +3922,8 @@ function EngramBoard({ api, onRequestClose }) {
3931
3922
  const wsList = Object.keys(ov.workspaces);
3932
3923
  const entries = await Promise.all(
3933
3924
  wsList.map(async (w) => {
3934
- const shouldLoad = !loadedWs.current.has(w);
3935
- if (shouldLoad) loadedWs.current.add(w);
3936
- const res = shouldLoad ? await Promise.all([api.tasks(w, true), api.nodes(w), api.links(w)]) : null;
3937
- return [w, res ? { tasks: res[0].items, nodes: res[1].items, links: res[2].items } : null];
3925
+ const res = await Promise.all([api.tasks(w, true), api.nodes(w), api.links(w)]);
3926
+ return [w, { tasks: res[0].items, nodes: res[1].items, links: res[2].items }];
3938
3927
  })
3939
3928
  );
3940
3929
  setTasksByWs((prev) => {
@@ -3967,25 +3956,9 @@ function EngramBoard({ api, onRequestClose }) {
3967
3956
  }, [api]);
3968
3957
  (0, import_react9.useEffect)(() => {
3969
3958
  void refresh();
3970
- const id = setInterval(() => void refresh(), 2e4);
3959
+ const id = setInterval(() => void refresh(), POLL_MS);
3971
3960
  return () => clearInterval(id);
3972
3961
  }, [refresh]);
3973
- (0, import_react9.useEffect)(() => {
3974
- if (!ws || denied) return;
3975
- const id = setInterval(() => {
3976
- const fetchWs = async () => {
3977
- try {
3978
- const [res, nodeRes, linkRes] = await Promise.all([api.tasks(ws, true), api.nodes(ws), api.links(ws)]);
3979
- setTasksByWs((prev) => ({ ...prev, [ws]: res.items }));
3980
- setNodesByWs((prev) => ({ ...prev, [ws]: nodeRes.items }));
3981
- setLinksByWs((prev) => ({ ...prev, [ws]: linkRes.items }));
3982
- } catch {
3983
- }
3984
- };
3985
- void fetchWs();
3986
- }, 2e4);
3987
- return () => clearInterval(id);
3988
- }, [ws, denied, api]);
3989
3962
  const workspaces = (0, import_react9.useMemo)(
3990
3963
  () => overview ? Object.entries(overview.workspaces).sort((a, b) => b[1].tasks - a[1].tasks) : [],
3991
3964
  [overview]
@@ -4018,7 +3991,7 @@ function EngramBoard({ api, onRequestClose }) {
4018
3991
  }
4019
3992
  if (t.state === "draft") continue;
4020
3993
  active += 1;
4021
- const gates = taskGaps3(t);
3994
+ const gates = taskGaps(t);
4022
3995
  gateTotal += 3;
4023
3996
  gateFilled += 3 - gates.length;
4024
3997
  if (gates.length === 0) ready += 1;
@@ -4047,7 +4020,6 @@ function EngramBoard({ api, onRequestClose }) {
4047
4020
  setBusy(true);
4048
4021
  try {
4049
4022
  await api.createTask(targetWs, name, newDesc);
4050
- loadedWs.current.add(targetWs);
4051
4023
  setNewName("");
4052
4024
  setNewDesc("");
4053
4025
  setCreating(false);
@@ -4336,7 +4308,7 @@ function EngramBoard({ api, onRequestClose }) {
4336
4308
  "@",
4337
4309
  shortAgent(t.assignee)
4338
4310
  ] }),
4339
- (col.key === "gapped" || col.key === "ready") && taskGaps3(t).map((g) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: hb.gap, children: [
4311
+ (col.key === "gapped" || col.key === "ready") && taskGaps(t).map((g) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: hb.gap, children: [
4340
4312
  g,
4341
4313
  " \u2717"
4342
4314
  ] }, g)),
@@ -4348,7 +4320,7 @@ function EngramBoard({ api, onRequestClose }) {
4348
4320
  "\xB7ref",
4349
4321
  (t.memoryRefs?.length ?? 0) > 0 ? "\u2713" : "\u2717"
4350
4322
  ] }),
4351
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.meta, children: fmtDate3(t.createdAt) })
4323
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.meta, children: fmtDateShort(t.createdAt) })
4352
4324
  ] })
4353
4325
  ] })
4354
4326
  ] }),
@@ -0,0 +1,49 @@
1
+ // <autogenerated by client/build-model.mjs — do not edit directly>
2
+ // Compiles client/src/esrModel.ts for the node test runner.
3
+
4
+ // client/src/esrModel.ts
5
+ function taskGaps(t) {
6
+ const gaps = [];
7
+ if (!t.artifact) gaps.push("artifact");
8
+ if (!t.evaluation) gaps.push("evaluation");
9
+ if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
10
+ return gaps;
11
+ }
12
+ function shortId(id) {
13
+ return id.length > 12 ? `${id.slice(0, 6)}\u2026${id.slice(-4)}` : id;
14
+ }
15
+ function blockedBy(t, all) {
16
+ if (t.state === "stable") return 0;
17
+ const open = new Set(all.filter((x) => x.state !== "stable").map((x) => x.id));
18
+ return (t.deps ?? []).filter((d) => d.kind !== "relates-to" && open.has(d.id)).length;
19
+ }
20
+ function shortAgent(a) {
21
+ if (!a) return "";
22
+ const bare = a.split(/[@#/:\\]+/).pop();
23
+ return bare.replace(/^session[-_]/i, "").replace(/^agent[-_]/i, "").slice(0, 14);
24
+ }
25
+ function fmtDateShort(ts) {
26
+ return ts ? new Date(ts).toLocaleDateString("zh-CN", { month: "short", day: "numeric" }) : "\u2013";
27
+ }
28
+ function buildTasksMarkdown(tasks) {
29
+ const esc = (s) => String(s ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ");
30
+ const rows = tasks.slice().sort((a, b) => a.state.localeCompare(b.state) || (a.createdAt ?? 0) - (b.createdAt ?? 0)).map((t) => {
31
+ const ev = `${t.artifact ? "artifact\u2713" : "artifact\u2717"} \xB7 ${t.evaluation ? "eval\u2713" : "eval\u2717"} \xB7 ${(t.memoryRefs?.length ?? 0) > 0 ? "ref\u2713" : "ref\u2717"}`;
32
+ return `| ${t.state} | ${esc(t.name)} | ${esc(t.workspace.replace(/^.*[\\/]/, ""))} | ${esc(taskGaps(t).join(", ") || "\u2014")} | ${ev} | ${fmtDateShort(t.createdAt ?? 0)} |`;
33
+ });
34
+ return `# ESR \u4EFB\u52A1\u5BFC\u51FA \xB7 ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
35
+
36
+ | \u72B6\u6001 | \u4EFB\u52A1 | \u5DE5\u4F5C\u533A | \u8BC1\u636E\u7F3A\u53E3 | \u8BC1\u636E | \u521B\u5EFA |
37
+ |---|---|---|---|---|---|
38
+ ${rows.join("\n") || "(\u65E0\u4EFB\u52A1)"}`;
39
+ }
40
+ var POLL_MS = 2e4;
41
+ export {
42
+ POLL_MS,
43
+ blockedBy,
44
+ buildTasksMarkdown,
45
+ fmtDateShort,
46
+ shortAgent,
47
+ shortId,
48
+ taskGaps
49
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-engram",
3
3
  "description": "Minimalist long-term memory for DeepSeek Harness, distilling symbolic-index + pi-esr ideas: zero-LLM auto-capture, a symbolic [ENGRAM] index with progressive disclosure, and an ESR-lite evidence-closure protocol (esr_task / esr_node / esr_close / esr_link). Real agent-behaviour telemetry (usage rollup + /stats) and a deterministic offline recall benchmark (npm run eval). Hot path is model-free; storage on ctx.storageDomain; web memory viewer, observability panel and config card through DSH's native settings slots.",
4
- "version": "0.3.3",
4
+ "version": "0.3.4",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -33,10 +33,10 @@
33
33
  "scripts": {
34
34
  "setup": "node scripts/setup-links.mjs",
35
35
  "prepublishOnly": "node scripts/prepublish-check.mjs",
36
- "build:client": "node client/build.mjs",
36
+ "build:client": "node client/build.mjs && node client/build-model.mjs",
37
37
  "test": "node --test \"test/**/*.test.mjs\"",
38
38
  "eval": "node eval/recall-bench.mjs",
39
- "typecheck": "echo ok"
39
+ "typecheck": "node client/typecheck.mjs"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public"