dsh-engram 0.3.3 → 0.3.5
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/README.md +156 -22
- package/README.zh.md +108 -13
- package/cordis.patch.yml +6 -0
- package/docs/CONTEXT-GC-GUIDE.zh.md +192 -0
- package/docs/PROPOSAL-agentmemory.zh.md +108 -0
- package/docs/PROPOSAL-beads.zh.md +81 -0
- package/docs/PROPOSAL-contextgc.zh.md +188 -0
- package/docs/PROPOSAL-esrtrigger.zh.md +199 -0
- package/docs/PROPOSAL-hindsight.zh.md +156 -0
- package/lib/api.js +19 -0
- package/lib/capture.js +132 -4
- package/lib/client.js +93 -90
- package/lib/compaction.js +2 -18
- package/lib/context-gc.js +234 -2
- package/lib/esrModel.mjs +49 -0
- package/lib/goal-capture.js +89 -0
- package/lib/index-block.js +4 -0
- package/lib/index.js +196 -4
- package/lib/redact.js +48 -0
- package/lib/session-cjk.js +159 -0
- package/lib/settings.js +7 -0
- package/lib/status.js +57 -0
- package/lib/store.js +124 -6
- package/lib/todo-sink.js +146 -0
- package/lib/tools.js +58 -34
- package/lib/trigger.js +10 -8
- package/lib/usage.js +1 -0
- package/lib/web-provision.js +430 -0
- package/package.json +14 -3
- package/scripts/dsh-engram.mjs +268 -0
- package/scripts/engram-web-compaction.mjs +7 -0
- package/scripts/prepublish-check.mjs +106 -0
- package/scripts/setup-links.mjs +241 -0
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(),
|
|
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 = (
|
|
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(),
|
|
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(),
|
|
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,
|
|
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
|
|
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,
|
|
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 =
|
|
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,11 +3370,21 @@ 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 },
|
|
3352
|
-
{ key: "verifyArtifact", label: "\u6821\u9A8C artifact \u5B58\u5728", hint: "esr_close \u7684 artifact \u987B\u5728\u5DE5\u4F5C\u533A\u78C1\u76D8\u4E0A\u771F\u5B9E\u5B58\u5728\uFF08URL \u8C41\u514D\uFF09\uFF1Bforce:true/\u5173\u6389\u53EF\u8DF3\u8FC7", kind: "bool" }
|
|
3377
|
+
{ key: "verifyArtifact", label: "\u6821\u9A8C artifact \u5B58\u5728", hint: "esr_close \u7684 artifact \u987B\u5728\u5DE5\u4F5C\u533A\u78C1\u76D8\u4E0A\u771F\u5B9E\u5B58\u5728\uFF08URL \u8C41\u514D\uFF09\uFF1Bforce:true/\u5173\u6389\u53EF\u8DF3\u8FC7", kind: "bool" },
|
|
3378
|
+
{ key: "autoSinkTodosOnEnd", label: "\u4F1A\u8BDD\u7ED3\u675F\u81EA\u52A8\u6C89\u6DC0 todo", hint: "\u4F1A\u8BDD\u7ED3\u675F\u65F6\u4ECD pending \u7684 todo \u81EA\u52A8\u8F6C\u6210 ESR draft\uFF08\u6309\u540D\u53BB\u91CD\u3001\u53D7\u4EFB\u52A1\u4E0A\u9650\u7EA6\u675F\uFF09\uFF1B\u5173\u6389=\u968F\u4F1A\u8BDD\u5F03\u53BB", kind: "bool" },
|
|
3379
|
+
{ key: "autoWebCompaction", label: "web \u9762\u81EA\u52A8\u542F\u7528 Context GC", hint: "\u542F\u52A8\u65F6\u628A\u5168\u90E8 stock \u5E03\u5C40\u7684 agent \u9884\u8BBE\uFF08shipped + \u81EA\u5B9A\u4E49\u6839\uFF09\u7684 compaction \u7EC4\u81EA\u52A8\u6362\u6210 dsh-engram/compaction\uFF1B\u5173\u6389=\u4E0D\u518D\u81EA\u52A8\u63A5\u7BA1\uFF08\u5DF2\u63A5\u7BA1\u7684\u9700 web-compaction:revert \u8FD8\u539F\uFF09", kind: "bool" }
|
|
3380
|
+
]
|
|
3381
|
+
},
|
|
3382
|
+
{
|
|
3383
|
+
id: "semantics-adv",
|
|
3384
|
+
title: "\u8BB0\u5FC6\u8BED\u4E49\uFF08\u9AD8\u7EA7\uFF09",
|
|
3385
|
+
description: "supersedes / contradict \u7684\u542F\u53D1\u5F0F",
|
|
3386
|
+
fields: [
|
|
3387
|
+
{ key: "autoSupersede", label: "\u81EA\u52A8 supersedes", hint: "\u5B9E\u4F53\u951A\u5B9A + \u66FF\u6362\u5F0F\u66F4\u65B0\uFF08\u6539\u7528/\u4E0D\u518D/no longer\u2026\uFF09\u81EA\u52A8\u628A\u65E7\u8BB0\u5FC6\u6807\u4E3A superseded\uFF1B\u65E7\u884C\u4FDD\u7559\u3001\u53EC\u56DE\u964D\u7EA7\u3002\u9ED8\u8BA4\u5173\uFF0C\u663E\u5F0F supersedes \u6C38\u8FDC\u4F18\u5148", kind: "bool" }
|
|
3353
3388
|
]
|
|
3354
3389
|
},
|
|
3355
3390
|
{
|
|
@@ -3836,20 +3871,12 @@ var import_client = require("react-dom/client");
|
|
|
3836
3871
|
// client/src/EngramBoard.tsx
|
|
3837
3872
|
var import_react9 = require("react");
|
|
3838
3873
|
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
3874
|
var COLUMNS = [
|
|
3847
3875
|
{ 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" &&
|
|
3849
|
-
{ key: "ready", title: "\u5C31\u7EEA", sub: "\u8BC1\u636E\u9F50\uFF0C\u53EF\u95ED\u73AF", color: "#10b981", match: (t) => t.state === "active" &&
|
|
3876
|
+
{ key: "gapped", title: "\u8FDB\u884C\u4E2D", sub: "\u8BC1\u636E\u6709\u7F3A\u53E3", color: "#f59e0b", match: (t) => t.state === "active" && taskGaps(t).length > 0 },
|
|
3877
|
+
{ 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
3878
|
{ key: "stable", title: "\u5DF2\u95ED\u73AF", sub: "\u51ED\u636E\u9F50\u5907", color: "#6366f1", match: (t) => t.state === "stable" }
|
|
3851
3879
|
];
|
|
3852
|
-
var fmtDate3 = (ts) => ts ? new Date(ts).toLocaleDateString("zh-CN", { month: "short", day: "numeric" }) : "\u2013";
|
|
3853
3880
|
function buildCloseEvidence(bulkArtifact, bulkEval, bulkRefs, task) {
|
|
3854
3881
|
const refs = bulkRefs.split(/[,\s]+/).map((x) => x.trim()).filter(Boolean);
|
|
3855
3882
|
return {
|
|
@@ -3858,31 +3885,6 @@ function buildCloseEvidence(bulkArtifact, bulkEval, bulkRefs, task) {
|
|
|
3858
3885
|
memoryRefs: refs.length > 0 ? refs : task.memoryRefs
|
|
3859
3886
|
};
|
|
3860
3887
|
}
|
|
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
3888
|
var TREND_LABEL = {
|
|
3887
3889
|
new: "\u65B0",
|
|
3888
3890
|
strengthening: "\u589E\u5F3A",
|
|
@@ -3890,6 +3892,26 @@ var TREND_LABEL = {
|
|
|
3890
3892
|
weakening: "\u51CF\u5F31",
|
|
3891
3893
|
stale: "\u9648\u65E7"
|
|
3892
3894
|
};
|
|
3895
|
+
function ContextGcChip({ compaction }) {
|
|
3896
|
+
const host = compaction?.host ?? "unknown";
|
|
3897
|
+
const hostLabel = host === "context-gc" ? "Context GC\xB7\u4E3B\u673A" : host === "default" ? "\u9ED8\u8BA4\u6458\u8981" : host === "unavailable" ? "GC \u4E0D\u53EF\u7528" : "GC \u72B6\u6001\u2026";
|
|
3898
|
+
const wired = (compaction?.web?.presets ?? []).filter((p) => p.action === "swapped" || p.action === "already").length;
|
|
3899
|
+
const webLabel = wired > 0 ? `\xB7${wired} \u9884\u8BBE` : "";
|
|
3900
|
+
const color = host === "context-gc" ? "var(--dsw-alias-success-strong, #059669)" : host === "default" || host === "unavailable" ? "var(--dsw-alias-label-secondary, var(--dsh-color-muted, #6b7280))" : "var(--dsw-alias-label-tertiary, #9ca3af)";
|
|
3901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3902
|
+
"span",
|
|
3903
|
+
{
|
|
3904
|
+
title: `host \u5E73\u9762\uFF1A${host}
|
|
3905
|
+
web \u5E73\u9762\uFF1A${compaction?.web?.action ?? "?"}\uFF08${wired} \u4E2A\u9884\u8BBE\u5DF2\u63A5\u7BA1\uFF09
|
|
3906
|
+
\u5173\u6389\u81EA\u52A8\u88C5\u914D\u89C1\u8BBE\u7F6E\u5361\u300Cweb \u9762\u81EA\u52A8\u542F\u7528 Context GC\u300D\uFF1B\u8FD8\u539F\u7528 npx dsh-engram revert`,
|
|
3907
|
+
style: { fontSize: 11, fontWeight: 600, color, border: `1px solid ${color}55`, borderRadius: 999, padding: "2px 8px", whiteSpace: "nowrap" },
|
|
3908
|
+
children: [
|
|
3909
|
+
hostLabel,
|
|
3910
|
+
webLabel
|
|
3911
|
+
]
|
|
3912
|
+
}
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3893
3915
|
function EngramBoard({ api, onRequestClose }) {
|
|
3894
3916
|
const { vars } = useEngramTheme();
|
|
3895
3917
|
const [overview, setOverview] = (0, import_react9.useState)(null);
|
|
@@ -3918,7 +3940,6 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
3918
3940
|
const [bulkRefs, setBulkRefs] = (0, import_react9.useState)("");
|
|
3919
3941
|
const [bulkBusy, setBulkBusy] = (0, import_react9.useState)(false);
|
|
3920
3942
|
const [bulkMsg, setBulkMsg] = (0, import_react9.useState)(null);
|
|
3921
|
-
const loadedWs = (0, import_react9.useRef)(/* @__PURE__ */ new Set());
|
|
3922
3943
|
const [obsItems, setObsItems] = (0, import_react9.useState)(null);
|
|
3923
3944
|
const [obsOpen, setObsOpen] = (0, import_react9.useState)(false);
|
|
3924
3945
|
const [model, setModel] = (0, import_react9.useState)(null);
|
|
@@ -3931,10 +3952,8 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
3931
3952
|
const wsList = Object.keys(ov.workspaces);
|
|
3932
3953
|
const entries = await Promise.all(
|
|
3933
3954
|
wsList.map(async (w) => {
|
|
3934
|
-
const
|
|
3935
|
-
|
|
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];
|
|
3955
|
+
const res = await Promise.all([api.tasks(w, true), api.nodes(w), api.links(w)]);
|
|
3956
|
+
return [w, { tasks: res[0].items, nodes: res[1].items, links: res[2].items }];
|
|
3938
3957
|
})
|
|
3939
3958
|
);
|
|
3940
3959
|
setTasksByWs((prev) => {
|
|
@@ -3967,25 +3986,9 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
3967
3986
|
}, [api]);
|
|
3968
3987
|
(0, import_react9.useEffect)(() => {
|
|
3969
3988
|
void refresh();
|
|
3970
|
-
const id = setInterval(() => void refresh(),
|
|
3989
|
+
const id = setInterval(() => void refresh(), POLL_MS);
|
|
3971
3990
|
return () => clearInterval(id);
|
|
3972
3991
|
}, [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
3992
|
const workspaces = (0, import_react9.useMemo)(
|
|
3990
3993
|
() => overview ? Object.entries(overview.workspaces).sort((a, b) => b[1].tasks - a[1].tasks) : [],
|
|
3991
3994
|
[overview]
|
|
@@ -4018,7 +4021,7 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
4018
4021
|
}
|
|
4019
4022
|
if (t.state === "draft") continue;
|
|
4020
4023
|
active += 1;
|
|
4021
|
-
const gates =
|
|
4024
|
+
const gates = taskGaps(t);
|
|
4022
4025
|
gateTotal += 3;
|
|
4023
4026
|
gateFilled += 3 - gates.length;
|
|
4024
4027
|
if (gates.length === 0) ready += 1;
|
|
@@ -4047,7 +4050,6 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
4047
4050
|
setBusy(true);
|
|
4048
4051
|
try {
|
|
4049
4052
|
await api.createTask(targetWs, name, newDesc);
|
|
4050
|
-
loadedWs.current.add(targetWs);
|
|
4051
4053
|
setNewName("");
|
|
4052
4054
|
setNewDesc("");
|
|
4053
4055
|
setCreating(false);
|
|
@@ -4136,6 +4138,7 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
4136
4138
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.title, children: "ESR \u4EFB\u52A1\u770B\u677F" }),
|
|
4137
4139
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.sub, children: "draft \u2192 active(\u8BC1\u636E) \u2192 stable \xB7 \u8DE8\u5DE5\u4F5C\u533A \xB7 \u4E0E esr_task/esr_close \u540C\u4E00\u8BC1\u636E\u95E8" }),
|
|
4138
4140
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.legendChip, children: "\u4EC5 ESR \xB7 \u4F1A\u8BDD\u5185 todo \u89C1\u8F93\u5165\u6846\u4E0A\u65B9\u4EFB\u52A1\u6761" }),
|
|
4141
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ContextGcChip, { compaction: overview?.compaction }),
|
|
4139
4142
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: hb.seg, children: [
|
|
4140
4143
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", style: viewMode === "board" ? hb.segActive : hb.segBtn, onClick: () => setViewMode("board"), title: "\u56DB\u5217\u4EFB\u52A1\u770B\u677F", children: "\u770B\u677F" }),
|
|
4141
4144
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", style: viewMode === "graph" ? hb.segActive : hb.segBtn, onClick: () => setViewMode("graph"), title: "\u5B9E\u4F53\u5173\u7CFB\u56FE\u8C31\uFF08esr_node / esr_link\uFF09", children: "\u56FE\u8C31" })
|
|
@@ -4336,7 +4339,7 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
4336
4339
|
"@",
|
|
4337
4340
|
shortAgent(t.assignee)
|
|
4338
4341
|
] }),
|
|
4339
|
-
(col.key === "gapped" || col.key === "ready") &&
|
|
4342
|
+
(col.key === "gapped" || col.key === "ready") && taskGaps(t).map((g) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: hb.gap, children: [
|
|
4340
4343
|
g,
|
|
4341
4344
|
" \u2717"
|
|
4342
4345
|
] }, g)),
|
|
@@ -4348,7 +4351,7 @@ function EngramBoard({ api, onRequestClose }) {
|
|
|
4348
4351
|
"\xB7ref",
|
|
4349
4352
|
(t.memoryRefs?.length ?? 0) > 0 ? "\u2713" : "\u2717"
|
|
4350
4353
|
] }),
|
|
4351
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.meta, children:
|
|
4354
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: hb.meta, children: fmtDateShort(t.createdAt) })
|
|
4352
4355
|
] })
|
|
4353
4356
|
] })
|
|
4354
4357
|
] }),
|
package/lib/compaction.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* entry never writes).
|
|
32
32
|
*/
|
|
33
33
|
import { openEngramDomain } from "./store.js";
|
|
34
|
-
import {
|
|
34
|
+
import { mountCompactionEngine, collectPointerContext } from "./context-gc.js";
|
|
35
35
|
import { workspaceKey as wk } from "./util.js";
|
|
36
36
|
|
|
37
37
|
export const name = "dsh-engram-compaction";
|
|
@@ -56,9 +56,6 @@ export function apply(ctx, config = {}) {
|
|
|
56
56
|
const deps =
|
|
57
57
|
mode === "context-gc"
|
|
58
58
|
? {
|
|
59
|
-
narrativeEnabled: config.gcNarrative !== false,
|
|
60
|
-
narrativeMaxTokens: config.gcNarrativeMaxTokens ?? 1024,
|
|
61
|
-
narrativeMaxChars: config.gcNarrativeMaxChars ?? 4000,
|
|
62
59
|
readWorkspace: async (workspace, report) => {
|
|
63
60
|
if (!workspace) return null;
|
|
64
61
|
const domain = await domainFor(ctx);
|
|
@@ -68,18 +65,5 @@ export function apply(ctx, config = {}) {
|
|
|
68
65
|
}
|
|
69
66
|
: {};
|
|
70
67
|
|
|
71
|
-
return
|
|
72
|
-
.then((Engine) => {
|
|
73
|
-
if (!Engine) {
|
|
74
|
-
ctx.logger?.warn?.("engram context-gc: dsh-compaction-basic unavailable — no compaction engine");
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
new Engine();
|
|
78
|
-
ctx.logger?.info?.(
|
|
79
|
-
`engram context-gc: compaction = ${mode === "context-gc" ? "Context GC (mechanical eviction + re-fetch pointers)" : "default LLM summarizer (gcReplacesCompaction:false)"}`,
|
|
80
|
-
);
|
|
81
|
-
})
|
|
82
|
-
.catch((error) => {
|
|
83
|
-
ctx.logger?.warn?.(`engram context-gc mount failed: ${String(error)}`);
|
|
84
|
-
});
|
|
68
|
+
return mountCompactionEngine(ctx, config, deps);
|
|
85
69
|
}
|