sage-mem 0.9.19 → 0.9.20
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/autodream-tools.js +23 -1
- package/package.json +1 -1
package/lib/autodream-tools.js
CHANGED
|
@@ -32,6 +32,8 @@ import { archiveMemory } from './memory/archive.js'
|
|
|
32
32
|
import { MAX_FILE_BYTES, STATE_ROOT } from './memory/config.js'
|
|
33
33
|
import { writeFileAtomic, warnLog } from './memory/util.js'
|
|
34
34
|
import { buildConflict, writeConflict } from './memory/conflicts.js'
|
|
35
|
+
import { memoryPathOf } from './memory/paths.js'
|
|
36
|
+
import { decideWriteIntent } from './memory/write-gate.js'
|
|
35
37
|
import { inspectMemoryEntry, reservedIdentitySet } from './memory/scan.js'
|
|
36
38
|
|
|
37
39
|
/** 单次 read_memory 返回的正文上限(字符)。超过就截断并明确告诉模型。 */
|
|
@@ -534,8 +536,28 @@ export function createToolRunner(opts) {
|
|
|
534
536
|
return null
|
|
535
537
|
}
|
|
536
538
|
const target = await fs.resolve(fullPath)
|
|
539
|
+
// ⚠️ **守卫必须由我们自己传。** `fs/write-intent` 只为「工具发起」的写入派发,
|
|
540
|
+
// 插件自己调 `writeText` 时一次都不发(实测)—— 不自己传,这次写入就是**无守卫**的,
|
|
541
|
+
// 那正是 D4 要避免的漏洞,也是「两套写入者静默互踩」的入口。
|
|
542
|
+
// 判定表与写门用的是同一个(`write-gate.js`),所以两条路的语义不会漂。
|
|
543
|
+
let expected
|
|
544
|
+
if (typeof fs.stat === 'function') {
|
|
545
|
+
try {
|
|
546
|
+
const info = await fs.stat(target)
|
|
547
|
+
expected = decideWriteIntent({
|
|
548
|
+
memoryPath: memoryPathOf(fullPath, memoryDir),
|
|
549
|
+
exists: !!info,
|
|
550
|
+
version: info?.version ?? null,
|
|
551
|
+
caller: undefined,
|
|
552
|
+
}).intent
|
|
553
|
+
} catch {
|
|
554
|
+
// 探不到就不猜:不传守卫(宿主按默认语义走),也绝不退化成 createIfAbsent ——
|
|
555
|
+
// 那对**其实存在**的文件是一次误拦。
|
|
556
|
+
expected = undefined
|
|
557
|
+
}
|
|
558
|
+
}
|
|
537
559
|
try {
|
|
538
|
-
return await fs.writeText(target, content)
|
|
560
|
+
return await fs.writeText(target, content, expected)
|
|
539
561
|
} catch (err) {
|
|
540
562
|
// 版本过期不是「写失败」,是**一次待判定的冲突**:有人在我们读入之后改过这份记忆。
|
|
541
563
|
// 落一条记录(保留哪边由人决定),然后**照旧把错误抛出去** ——
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sage-mem",
|
|
3
3
|
"description": "File-based memory plugin for DeepSeek Harness (DSH) — cross-session memory in plain markdown files, with a memory star-map view, type/tag filtering, retrieval aliases, and an optional autodream pass that consolidates memories on demand or on a schedule — with per-run rollback points, a per-file change declaration (what changed and why), and a separately selectable model for the consolidation pass",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.20",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|