@a9i5k4/dsh-auto-memory 3.1.0 → 3.1.3
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/docs/CONTRIBUTORS.html +2 -2
- package/docs/HANDBOOK.md +13 -9
- package/lib/client.js +786 -134
- package/lib/config-io.js +59 -6
- package/lib/context-host.js +10 -1
- package/lib/evidence-store.js +27 -1
- package/lib/index.js +937 -51
- package/lib/jsonl-tail-cursor.js +75 -0
- package/lib/m7-index-sync-host.js +4 -6
- package/lib/memory-hub.js +25 -2
- package/lib/migrate-pack.js +431 -0
- package/lib/python-setup.js +109 -27
- package/lib/recall-stats.js +242 -0
- package/lib/rules-layer.js +106 -15
- package/lib/semantic-js.js +25 -7
- package/lib/shadow-host.js +41 -2
- package/lib/subagent-gc.js +5 -1
- package/lib/wb-sidecar.js +8 -3
- package/package.json +1 -1
package/lib/shadow-host.js
CHANGED
|
@@ -40,7 +40,30 @@ export function truncateAuditEvent(ev) {
|
|
|
40
40
|
return e
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
/**
|
|
44
|
+
* ★P3-9(组2,2026-09-22):诊断**节流**表。
|
|
45
|
+
* 原先 `no-paths` 每个 Segment 都直接 console.error ⇒ 单次历史回放能刷出上百行。
|
|
46
|
+
* 表放**模块级**而非闭包级:同进程多实例共享 ⇒ 不会各自持一份而双写。
|
|
47
|
+
* 语义同 index.js 的 diagThrottled:首条立即透出,窗口内重复压掉。
|
|
48
|
+
*/
|
|
49
|
+
const DIAG_THROTTLE_MS_V1 = 300000
|
|
50
|
+
const _diagAt = new Map()
|
|
51
|
+
function shouldReportDiag(key) {
|
|
52
|
+
try {
|
|
53
|
+
const now = Date.now()
|
|
54
|
+
if (now - (Number(_diagAt.get(key)) || 0) < DIAG_THROTTLE_MS_V1) return false
|
|
55
|
+
_diagAt.set(key, now)
|
|
56
|
+
} catch (_) { /* 计时失败不阻断上报 */ }
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {{engine: object, onDiag?: Function|null, recallStats?: object|null}} opts
|
|
62
|
+
* `recallStats` = 召回统计实例(可选)。**依赖注入而非模块级单例**:本模块保持零耦合,
|
|
63
|
+
* 测试可传假对象(不碰真磁盘);不传时埋点整段跳过,行为与从前逐字节相同。
|
|
64
|
+
* ★命名:不得叫 `stats` —— 本函数内部已有同名 const(shadow 自身计数器),会作用域冲突。
|
|
65
|
+
*/
|
|
66
|
+
export function createShadowHost({ engine, onDiag = null, recallStats = null }) {
|
|
44
67
|
const states = new WeakMap() // runtime → shadow state(lazy)
|
|
45
68
|
const volatileRing = [] // ≤64 events(最小投影)
|
|
46
69
|
const stats = { evaluated: 0, retrieved: 0, prefetched: 0, suppressed: 0, stale: 0, errors: 0 }
|
|
@@ -58,6 +81,13 @@ export function createShadowHost({ engine }) {
|
|
|
58
81
|
engine.config.shadowRetrievalEnabled === true &&
|
|
59
82
|
engine.config.memoryAnchorEnabled === true
|
|
60
83
|
|
|
84
|
+
/** ★P3-9(组2):节流上报。未注入 onDiag 时回落 console.error(保持既有行为,只去掉刷屏)。 */
|
|
85
|
+
function reportDiag(key, msg) {
|
|
86
|
+
if (!shouldReportDiag(key)) return
|
|
87
|
+
if (typeof onDiag === 'function') { try { onDiag(key, msg); return } catch (_) { /* 回落 */ } }
|
|
88
|
+
try { console.error(msg) } catch (_) {}
|
|
89
|
+
}
|
|
90
|
+
|
|
61
91
|
function stateFor(runtime) {
|
|
62
92
|
let st = states.get(runtime)
|
|
63
93
|
if (!st) {
|
|
@@ -225,7 +255,7 @@ export function createShadowHost({ engine }) {
|
|
|
225
255
|
return
|
|
226
256
|
}
|
|
227
257
|
const paths = pathsByKey.get(String(runtime.key || '')) || null
|
|
228
|
-
if (!paths) {
|
|
258
|
+
if (!paths) { reportDiag('shadow:no-paths', '[shadow-diag] no-paths'); stats.suppressed++; pushVolatile({ reason: 'no-paths-captured', contextVersion: seg.contextVersion }); return }
|
|
229
259
|
// window:segments ring 最近 8 条(含当前)
|
|
230
260
|
const ringItems = runtime.segments ? runtime.segments.snapshot() : []
|
|
231
261
|
const win = ringItems.slice(-8).map((w) => ({
|
|
@@ -320,6 +350,15 @@ export function createShadowHost({ engine }) {
|
|
|
320
350
|
if (dec.action === 'retrieve') stats.retrieved++
|
|
321
351
|
else stats.prefetched++
|
|
322
352
|
st.recentHits.push({ queryDigest: qp.queryDigest, fresh: ls.kept.length > 0, memoryIds: ls.kept.map((k) => k.memoryId) })
|
|
353
|
+
// ★③ 召回统计 · shadow 通道(2026-09-22 用户拍板「分开计算」):
|
|
354
|
+
// 这条通路 = 系统**主动判断该唤起**,与「模型主动检索」是两回事,必须分账。
|
|
355
|
+
// 语义:命中率(kept 空 ⇒ 唤起了但没东西)+ 哪些内容被系统认为该唤起。
|
|
356
|
+
// ★只读:不改 ls / st / 决策,不影响任何 shadow 行为(守卫断言)。
|
|
357
|
+
if (recallStats && typeof recallStats.observe === 'function') {
|
|
358
|
+
try {
|
|
359
|
+
recallStats.observe(ls.kept.map((k) => ({ id: k.memoryId, layer: k.sourceClass || k.scope || 'shadow' })), { channel: 'shadow' })
|
|
360
|
+
} catch (_) {}
|
|
361
|
+
}
|
|
323
362
|
if (st.recentHits.length > 64) st.recentHits.shift()
|
|
324
363
|
st.completedKeys.add(qp.queryDigest + ':' + snapshotOut.memoryIndexVersion)
|
|
325
364
|
if (st.completedKeys.size > 256) { const first = st.completedKeys.values().next().value; st.completedKeys.delete(first) }
|
package/lib/subagent-gc.js
CHANGED
|
@@ -201,7 +201,11 @@ export async function scanPluginSubagentSessions(opts = {}) {
|
|
|
201
201
|
// 按 mtime 取最新存在的文件,兼容两代命名。
|
|
202
202
|
let file = ''
|
|
203
203
|
let st = null
|
|
204
|
-
|
|
204
|
+
// ★v3.1.3:不再固定候选名 —— 扫目录取任意 session.*\.jsonl[.zstd](兼容未来 vN 命名)。
|
|
205
|
+
let names = []
|
|
206
|
+
try { names = readdirSync(dir) } catch (_) { names = [] }
|
|
207
|
+
const hits = names.filter((n) => /^session[.-].*\.jsonl(\.zstd)?$/i.test(n) && !/backup|corrupt/i.test(n))
|
|
208
|
+
for (const name of (hits.length ? hits : ['session.v3.jsonl.zstd', 'session.jsonl.zstd'])) {
|
|
205
209
|
const cand = path.join(dir, name)
|
|
206
210
|
try {
|
|
207
211
|
const s = await stat(cand)
|
package/lib/wb-sidecar.js
CHANGED
|
@@ -668,7 +668,10 @@ export function buildKanbanPre(index, opts = {}) {
|
|
|
668
668
|
source: String(c.source || ''),
|
|
669
669
|
section: String(c.section || ''),
|
|
670
670
|
preview: body.replace(/\s+/g, ' ').trim().slice(0, 400),
|
|
671
|
-
|
|
671
|
+
// ★v3.1.2 性能:full 不再内联进看板载荷(实测每卡≤6000 字符、1178 卡合计 0.85 MB,
|
|
672
|
+
// 且 lanes+matrix 双份 ⇒ 1.7 MB 纯冗余;前端默认只渲染 preview,full 仅「展开全文」需要)。
|
|
673
|
+
// 改为只带长度标示,正文由 kanban-card 路由按 id 单取。
|
|
674
|
+
fullLen: body.length,
|
|
672
675
|
tags: t.tags,
|
|
673
676
|
sectionTags: t.sectionTags,
|
|
674
677
|
cues: (Array.isArray(c.cues) ? c.cues : []).slice(0, 3),
|
|
@@ -698,7 +701,8 @@ export function buildKanbanPre(index, opts = {}) {
|
|
|
698
701
|
source: String(e.source || ''),
|
|
699
702
|
section: String(e.section || ''),
|
|
700
703
|
preview: String(e.preview || '').slice(0, 400),
|
|
701
|
-
|
|
704
|
+
// ★v3.1.2 性能:同 sectionCards 分支 —— 不内联 full,仅带长度(见上)。
|
|
705
|
+
fullLen: String(e.preview || '').length,
|
|
702
706
|
tags: t.tags,
|
|
703
707
|
sectionTags: t.sectionTags,
|
|
704
708
|
cues: (Array.isArray(e.cues) ? e.cues : []).slice(0, 3),
|
|
@@ -842,7 +846,8 @@ export function buildKanbanMatrixPre(cards, opts = {}) {
|
|
|
842
846
|
docTitle: String(c.docTitle || ''),
|
|
843
847
|
source: String(c.source || ''),
|
|
844
848
|
preview: body.replace(/\s+/g, ' ').trim().slice(0, 220),
|
|
845
|
-
|
|
849
|
+
// ★v3.1.2 性能:矩阵卡同样不内联 full(同 lanes 口径)——带长度标示,点开时按 id 单取。
|
|
850
|
+
fullLen: body.length,
|
|
846
851
|
bullets: Number(c.bullets) || 0,
|
|
847
852
|
criteria: String(c.criteria || 'unknown'),
|
|
848
853
|
badge: criteriaBadgePre(c.criteria),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a9i5k4/dsh-auto-memory",
|
|
3
3
|
"description": "Proactive associative memory for DSH: zero-prompt recall injected before the model speaks, three-layer auto-consolidation, skill crystallization, and Astra-style context management - handoff ledgers, PLAN whiteboard, water-level sensing. Local-first, model-agnostic, zero deps. 主动联想记忆+Astra 式上下文管理:自动唤回/自动沉淀/技能固化/交接账本与白板跨窗口续命/水位感知。",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|