sage-mem 2.1.9 → 2.1.10
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.md +1 -1
- package/lib/client.js +11 -12
- package/lib/memory/write-protocol.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
**Cross-session memory for DeepSeek Harness — plain markdown files, no database, no worker.**
|
|
14
14
|
|
|
15
|
-
**Current release: `2.1.
|
|
15
|
+
**Current release: `2.1.10`** — the npm badge above is the dynamic source of truth. **Contract baseline: `1.0.0`** — the first stable release, whose public commitments, the capability boundaries and the list of things it explicitly cannot do are frozen in the
|
|
16
16
|
[frozen contract](https://github.com/gezi-wen/sage-mem/blob/main/docs/1.0.0-contract.md).
|
|
17
17
|
|
|
18
18
|
If it is useful to you, a Star is the most direct feedback.
|
package/README.zh.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
> File-based cross-session memory for DeepSeek Harness — every memory is a plain markdown file you can open, edit and delete. No database, no worker, no port.
|
|
16
16
|
|
|
17
|
-
**当前发布版本:`2.1.
|
|
17
|
+
**当前发布版本:`2.1.10`** —— 顶部 npm 徽章是动态权威。**契约基线:`1.0.0`** —— 第一个稳定版,公开承诺、能力边界与「明确做不到」的清单冻结在
|
|
18
18
|
[契约冻结](https://github.com/gezi-wen/sage-mem/blob/main/docs/1.0.0-contract.md)。
|
|
19
19
|
|
|
20
20
|
如果它对你有用,给个 Star 是最直接的反馈。
|
package/lib/client.js
CHANGED
|
@@ -6051,23 +6051,22 @@ h("span", { key: "sep", className: "smem-actions-sep", "aria-hidden": "true" }),
|
|
|
6051
6051
|
function createIndexSkeleton() {
|
|
6052
6052
|
setError(null);
|
|
6053
6053
|
setNotice("");
|
|
6054
|
-
if (!remote || typeof remote.
|
|
6054
|
+
if (!remote || typeof remote.writeRaw !== "function") {
|
|
6055
6055
|
setError(t("error.noRaw"));
|
|
6056
6056
|
return;
|
|
6057
6057
|
}
|
|
6058
6058
|
setBusy(true);
|
|
6059
|
-
//
|
|
6060
|
-
|
|
6059
|
+
// 2.1.10(Q10):只调**一个意图接口**(writeRaw 的 createIfAbsent):
|
|
6060
|
+
// 服务端负责「全新安装、memory 目录还不存在」时先建父目录;
|
|
6061
|
+
// 已有索引 → 明确回 already_exists(逐字节不动)。绝不再「先读一次、读失败就当
|
|
6062
|
+
// 可以覆盖」—— 读失败也可能是权限错误,而那正是会顶掉一份真索引的路。
|
|
6063
|
+
remote.writeRaw("MEMORY.md", INDEX_SKELETON, { create: true }).then(function (res) {
|
|
6064
|
+
const out = unwrap(res);
|
|
6061
6065
|
setBusy(false);
|
|
6062
|
-
setNotice(t("notice.indexExists"));
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
setBusy(false);
|
|
6067
|
-
if (out && out.ok === false) { setError(out.error || t("error.skeletonFailed")); return; }
|
|
6068
|
-
setNotice(t("notice.indexCreated"));
|
|
6069
|
-
load();
|
|
6070
|
-
});
|
|
6066
|
+
if (out && out.code === "already_exists") { setNotice(t("notice.indexExists")); return; }
|
|
6067
|
+
if (out && out.ok === false) { setError(out.error || t("error.skeletonFailed")); return; }
|
|
6068
|
+
setNotice(t("notice.indexCreated"));
|
|
6069
|
+
load();
|
|
6071
6070
|
}).catch(function (e) {
|
|
6072
6071
|
setBusy(false);
|
|
6073
6072
|
setError(String((e && e.message) || e));
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { createHash } from 'node:crypto'
|
|
25
|
+
import { mkdir } from 'node:fs/promises'
|
|
26
|
+
import { dirname } from 'node:path'
|
|
25
27
|
import { readVerified } from './scan.js'
|
|
26
28
|
import { warnLog, writeFileAtomic, writeFileExclusive } from './util.js'
|
|
27
29
|
|
|
@@ -70,6 +72,10 @@ export async function writeSnapshot(target, content, gate, opts, meta) {
|
|
|
70
72
|
if (o.create === true) {
|
|
71
73
|
if (gate?.ok) return rejected(ERR_ALREADY_EXISTS, `sage-mem: ${name} 已经存在,新建不会覆盖它(要改正文请打开它)`)
|
|
72
74
|
try {
|
|
75
|
+
// 2.1.10(Q10):createIfAbsent 也负责「全新安装、父目录还不存在」这一种:
|
|
76
|
+
// writeFileExclusive 的临时文件落在同一目录,目录不在就会 ENOENT(审查实测)。
|
|
77
|
+
// 只建父目录、绝不动目标文件 —— 「建立索引骨架」这个意图由调用方一次说清。
|
|
78
|
+
await mkdir(dirname(target), { recursive: true })
|
|
73
79
|
await writeFileExclusive(target, content)
|
|
74
80
|
} catch (err) {
|
|
75
81
|
if (err?.code === 'EEXIST') return rejected(ERR_ALREADY_EXISTS, `sage-mem: ${name} 刚刚被别的写入建出来了,新建没有覆盖它`)
|
package/package.json
CHANGED