sage-mem 2.1.22 → 2.1.24
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/autodream/tools.js +7 -4
- package/lib/client.js +0 -79
- 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.24`** — 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.24`** —— 顶部 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/autodream/tools.js
CHANGED
|
@@ -30,7 +30,7 @@ import { createHash } from 'node:crypto'
|
|
|
30
30
|
import { auditMemoryDir, formatAudit, parseFrontmatterLite } from './audit.js'
|
|
31
31
|
import { archiveMemory } from '../memory/archive.js'
|
|
32
32
|
import { MAX_FILE_BYTES, STATE_ROOT } from '../memory/config.js'
|
|
33
|
-
import { INDEX_FILE_KEY, SESSION_LOG_KEY } from '../shared/md-name.js'
|
|
33
|
+
import { INDEX_FILE_KEY, SESSION_LOG_KEY, isPlainMdName } from '../shared/md-name.js'
|
|
34
34
|
import { stampHuman as localStamp } from '../shared/stamp.js'
|
|
35
35
|
import { writeFileAtomic, warnLog } from '../memory/util.js'
|
|
36
36
|
import { buildConflict, listConflicts, readConflict, sameConflict, writeConflict } from '../memory/conflicts.js'
|
|
@@ -58,10 +58,13 @@ export function safeMemoryPath(memoryDir, raw) {
|
|
|
58
58
|
if (typeof raw !== 'string') return null
|
|
59
59
|
const trimmed = raw.trim()
|
|
60
60
|
if (!trimmed) return null
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
// 文件名合法性**只用唯一判据**(`shared/md-name.js`):路径分隔符、冒号(NTFS 交替数据流)、
|
|
62
|
+
// 通配符与控制字符一律拒。这里曾经自己抄了一份、只拒了两种分隔符与上跳 ——
|
|
63
|
+
// 于是 `a:b.md` / `MEMORY.md:evil.md` 能一路走到 join,而它正是这条写路径的入口(2026-11-03 收敛)。
|
|
64
|
+
if (!isPlainMdName(trimmed)) return null
|
|
64
65
|
const base = basename(trimmed)
|
|
66
|
+
// 业务约束,比「文件名合法性」更严:不写隐藏文件。它是本函数比
|
|
67
|
+
// `isPlainMdName` 多出来的**唯一**一条,`test/shared-parity-test.mjs` 第 1 组盯着它。
|
|
65
68
|
if (base.startsWith('.')) return null
|
|
66
69
|
return join(memoryDir, base)
|
|
67
70
|
}
|
package/lib/client.js
CHANGED
|
@@ -224,59 +224,6 @@ window.__ModuleLoader__.load({
|
|
|
224
224
|
const StarmapRuntime = (function (require, _react) {
|
|
225
225
|
let react = _react;
|
|
226
226
|
const h = react.createElement;
|
|
227
|
-
// ── 手写 strict codec(浏览器无 zod,typert 只要求 parse 方法)──
|
|
228
|
-
// isStr / isNum / strSchema 来自 05-shared.js(这个 IIFE 在 factory 作用域内,看得到)。
|
|
229
|
-
const starSchema = {
|
|
230
|
-
parse(v) {
|
|
231
|
-
if (v === null || typeof v !== "object") throw new Error("invalid star");
|
|
232
|
-
isStr(v.file); isStr(v.kind); isStr(v.title); isStr(v.desc); isNum(v.bytes); isNum(v.mtimeMs);
|
|
233
|
-
return v;
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
const listSchema = {
|
|
237
|
-
parse(v) {
|
|
238
|
-
if (v === null || typeof v !== "object") throw new Error("invalid payload");
|
|
239
|
-
isNum(v.count);
|
|
240
|
-
if (!Array.isArray(v.stars)) throw new Error("expected stars array");
|
|
241
|
-
v.stars.forEach((s) => starSchema.parse(s));
|
|
242
|
-
return v;
|
|
243
|
-
},
|
|
244
|
-
};
|
|
245
|
-
const readSchema = {
|
|
246
|
-
parse(v) {
|
|
247
|
-
if (v === null || typeof v !== "object") throw new Error("invalid payload");
|
|
248
|
-
isStr(v.name); isStr(v.content);
|
|
249
|
-
return v;
|
|
250
|
-
},
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const TYPERT_REMOTE = {
|
|
254
|
-
package: "sage-starmap",
|
|
255
|
-
descriptors: [
|
|
256
|
-
{
|
|
257
|
-
id: "sage-starmap#starmap/listStars",
|
|
258
|
-
service: "starmap",
|
|
259
|
-
namespace: "starmap",
|
|
260
|
-
method: "listStars",
|
|
261
|
-
invocation: { kind: "direct" },
|
|
262
|
-
parameters: [],
|
|
263
|
-
result: { mode: "strict", typeSymbol: "sage-starmap/types#StarList", schema: listSchema, create: () => listSchema },
|
|
264
|
-
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
id: "sage-starmap#starmap/readFile",
|
|
268
|
-
service: "starmap",
|
|
269
|
-
namespace: "starmap",
|
|
270
|
-
method: "readFile",
|
|
271
|
-
invocation: { kind: "direct" },
|
|
272
|
-
parameters: [
|
|
273
|
-
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-starmap/types#FileName", schema: strSchema, create: () => strSchema } },
|
|
274
|
-
],
|
|
275
|
-
result: { mode: "strict", typeSymbol: "sage-starmap/types#FileContent", schema: readSchema, create: () => readSchema },
|
|
276
|
-
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
277
|
-
},
|
|
278
|
-
],
|
|
279
|
-
};
|
|
280
227
|
|
|
281
228
|
/** 错误详情尽量展开,避免 "[object Object]" 式黑洞。 */
|
|
282
229
|
function detail(e) {
|
|
@@ -1694,32 +1641,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1694
1641
|
body);
|
|
1695
1642
|
}
|
|
1696
1643
|
|
|
1697
|
-
const inject = ["slots", "remote"];
|
|
1698
|
-
|
|
1699
|
-
/**
|
|
1700
|
-
* Client 插件:$mount strict remote contribution(第三方 remote 不在
|
|
1701
|
-
* 宿主的固定 remote 清单里,必须自己挂),再注册星图子槽(B 方案起不再有右缘浮标与全屏 overlay)。
|
|
1702
|
-
*/
|
|
1703
|
-
async function apply(ctx) {
|
|
1704
|
-
appCtx = ctx;
|
|
1705
|
-
try {
|
|
1706
|
-
await ctx.remote.$mount(TYPERT_REMOTE);
|
|
1707
|
-
} catch (e) {
|
|
1708
|
-
// remote 注册失败不拖死 UI:星图打开时再向用户报错
|
|
1709
|
-
console.error("sage-starmap: remote mount failed", e);
|
|
1710
|
-
}
|
|
1711
|
-
injectCss();
|
|
1712
|
-
// B 方案:星图不再占对话主界面(去掉右缘 ✦ 浮标 + 全屏 overlay),
|
|
1713
|
-
// 改为注入 sage-mem 记忆管理页的「星图」子槽(settings.memory.starmap),
|
|
1714
|
-
// 由记忆管理页的标签栏切换渲染,作为并列视图。
|
|
1715
|
-
ctx.slots.inject("settings.memory.starmap", () => {
|
|
1716
|
-
ctx.slots.register(
|
|
1717
|
-
{ name: "settings.memory.starmap", id: "sage-starmap", order: 10, label: "记忆星图" },
|
|
1718
|
-
() => h(StarMap, { ctx: appCtx }),
|
|
1719
|
-
);
|
|
1720
|
-
});
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
1644
|
injectCss();
|
|
1724
1645
|
return { StarMap: StarMap };
|
|
1725
1646
|
|
package/package.json
CHANGED