sage-mem 1.3.0 → 1.4.0
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 -0
- package/README.zh.md +1 -0
- package/lib/client.js +74 -138
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -499,6 +499,7 @@ Module boundaries (since 1.2.0):
|
|
|
499
499
|
- `lib/assembly/` — the four mounts: autodream / retrieval tools / observation / write gate
|
|
500
500
|
- `lib/memory/` — pure memory-layer functions and file operations; `lib/autodream/` — the autodream engine
|
|
501
501
|
- `lib/shared/` — zero-dependency cross-layer rules: file-name rule / local timestamps / the two size limits (**exactly one copy each**; `test/duplication-test.mjs` turns red otherwise)
|
|
502
|
+
- UI side: `client/*.js` is split per screen (`05-shared.js` holds the cross-screen primitives and type tables); `npm run build:client` concatenates them into `lib/client.js`
|
|
502
503
|
- Dependency direction: `memory` never imports `autodream`, `recall` depends only on `memory`, `assembly` never imports the composition root (`test/structure-test.mjs` turns red if that changes)
|
|
503
504
|
|
|
504
505
|
## Contributing
|
package/README.zh.md
CHANGED
|
@@ -503,6 +503,7 @@ memory/ 目录(markdown 文件,4 类)
|
|
|
503
503
|
- `lib/assembly/` —— 四块挂载:autodream / 检索工具 / 观测 / 写入门
|
|
504
504
|
- `lib/memory/` —— 记忆层的纯函数与文件操作;`lib/autodream/` —— 自动做梦引擎
|
|
505
505
|
- `lib/shared/` —— 跨层零依赖的小判据:文件名规则 / 本地时间戳 / 两个体积上限(**只许一份**,`test/duplication-test.mjs` 会红)
|
|
506
|
+
- 界面侧:`client/*.js` 按屏分片(`05-shared.js` 放跨屏小基元与类型词表),`npm run build:client` 拼成 `lib/client.js`
|
|
506
507
|
- 依赖方向:`memory` 不认识 `autodream`,`recall` 只依赖 `memory`,`assembly` 不反向依赖组合根(`test/structure-test.mjs` 会红)
|
|
507
508
|
|
|
508
509
|
## 参与开发
|
package/lib/client.js
CHANGED
|
@@ -22,13 +22,68 @@ window.__ModuleLoader__.load({
|
|
|
22
22
|
let react = require("react");
|
|
23
23
|
const h = react.createElement;
|
|
24
24
|
|
|
25
|
+
// ── 共享基元(1.4.0):跨屏复用的小东西只有这一份 ─────────────
|
|
26
|
+
// 这些名字原本在 10 / 20 / 50 三个分片各写一遍(isStr/isNum/strSchema/parseSchema/
|
|
27
|
+
// unwrap/fmtSize/hexA,以及类型词表 3 份)。分片共享同一个 factory 作用域,
|
|
28
|
+
// 所以收敛到本片之后,后面的分片直接用、不再各写一份。
|
|
29
|
+
const isStr = (v) => { if (typeof v !== "string") throw new Error("expected string"); };
|
|
30
|
+
const isBool = (v) => { if (typeof v !== "boolean") throw new Error("expected boolean"); };
|
|
31
|
+
const isNum = (v) => { if (typeof v !== "number") throw new Error("expected number"); };
|
|
32
|
+
function parseSchema(shape) {
|
|
33
|
+
return {
|
|
34
|
+
parse(value) {
|
|
35
|
+
if (value === null || typeof value !== "object") throw new Error("sage-mem: invalid payload");
|
|
36
|
+
for (const [key, check] of Object.entries(shape)) {
|
|
37
|
+
if (!(key in value)) throw new Error("sage-mem: missing field " + key);
|
|
38
|
+
check(value[key]);
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const strSchema = { parse(v) { isStr(v); return v; } };
|
|
45
|
+
|
|
46
|
+
/** 拆 typert remote 的 {ok, value} 信封。 */
|
|
47
|
+
function unwrap(result) {
|
|
48
|
+
return result && result.ok ? result.value : result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 字节数 → 人话。三个档位对记忆文件足够(单条上限 512 KB)。 */
|
|
52
|
+
function fmtSize(n) {
|
|
53
|
+
if (n < 1024) return n + " B";
|
|
54
|
+
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + " KB";
|
|
55
|
+
return (n / 1024 / 1024).toFixed(1) + " MB";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** #rrggbb + alpha → rgba()。星图的辉光/底盘用。 */
|
|
59
|
+
function hexA(hex, a) {
|
|
60
|
+
const n = parseInt(hex.slice(1), 16);
|
|
61
|
+
return "rgba(" + ((n >> 16) & 255) + "," + ((n >> 8) & 255) + "," + (n & 255) + "," + a.toFixed(3) + ")";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── 类型词表(唯一定义) ──
|
|
65
|
+
// 文件列表的排序 / 筛选 / 徽章、星图的 kind 标签与配色,全部从这里取。
|
|
66
|
+
const TYPE_ORDER = ["user", "feedback", "project", "reference"];
|
|
67
|
+
const TYPE_SORT = ["user", "feedback", "project", "reference", "special"];
|
|
68
|
+
const TYPE_LABEL = { user: "用户", feedback: "反馈", project: "项目", reference: "参考", special: "特殊" };
|
|
69
|
+
const TYPE_META = {
|
|
70
|
+
user: ["👤", TYPE_LABEL.user],
|
|
71
|
+
feedback: ["📌", TYPE_LABEL.feedback],
|
|
72
|
+
project: ["📁", TYPE_LABEL.project],
|
|
73
|
+
reference: ["🔗", TYPE_LABEL.reference],
|
|
74
|
+
};
|
|
75
|
+
// 星图配色:深色档(夜空)与浅色档(暖纸 + 矿物颜料)各一套,色相错开才分得清类型。
|
|
76
|
+
const TYPE_COLOR_DARK = {
|
|
77
|
+
user: "#e0c07a", feedback: "#7ec8da", project: "#ac9edc", reference: "#92ceaa", special: "#bcc3d0",
|
|
78
|
+
};
|
|
79
|
+
const TYPE_COLOR_LIGHT = {
|
|
80
|
+
user: "#a4652c", feedback: "#3a6f8f", project: "#6a5b8f", reference: "#4a7c63", special: "#5b5750",
|
|
81
|
+
};
|
|
25
82
|
const StarmapRuntime = (function (require, _react) {
|
|
26
83
|
let react = _react;
|
|
27
84
|
const h = react.createElement;
|
|
28
85
|
// ── 手写 strict codec(浏览器无 zod,typert 只要求 parse 方法)──
|
|
29
|
-
|
|
30
|
-
const isNum = (v) => { if (typeof v !== "number") throw new Error("expected number"); };
|
|
31
|
-
const strSchema = { parse(v) { isStr(v); return v; } };
|
|
86
|
+
// isStr / isNum / strSchema 来自 05-shared.js(这个 IIFE 在 factory 作用域内,看得到)。
|
|
32
87
|
const starSchema = {
|
|
33
88
|
parse(v) {
|
|
34
89
|
if (v === null || typeof v !== "object") throw new Error("invalid star");
|
|
@@ -81,11 +136,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
81
136
|
],
|
|
82
137
|
};
|
|
83
138
|
|
|
84
|
-
/** 拆 typert remote 的 {ok, value} 信封。 */
|
|
85
|
-
function unwrap(result) {
|
|
86
|
-
return result && result.ok ? result.value : result;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
139
|
/** 错误详情尽量展开,避免 "[object Object]" 式黑洞。 */
|
|
90
140
|
function detail(e) {
|
|
91
141
|
if (!e) return "未知错误";
|
|
@@ -114,15 +164,10 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
114
164
|
// 深空画布上够辨认,又不抢眼。
|
|
115
165
|
//
|
|
116
166
|
// 两档取值:`color` = 深色档(夜空画布),`light` = 浅色档(纸本设色)。
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
const KIND_META = {
|
|
120
|
-
|
|
121
|
-
feedback: { label: "反馈", color: "#7ec8da", light: "#3a6f8f" },
|
|
122
|
-
project: { label: "项目", color: "#ac9edc", light: "#6a5b8f" },
|
|
123
|
-
reference: { label: "参考", color: "#92ceaa", light: "#4a7c63" },
|
|
124
|
-
special: { label: "特殊", color: "#bcc3d0", light: "#5b5750" },
|
|
125
|
-
};
|
|
167
|
+
// 类型标签与配色来自 05-shared.js 的唯一定义;这里只是把它们组装成星图用的 meta。
|
|
168
|
+
const KIND_META = {};
|
|
169
|
+
for (const k of TYPE_SORT) KIND_META[k] = { label: TYPE_LABEL[k], color: TYPE_COLOR_DARK[k], light: TYPE_COLOR_LIGHT[k] };
|
|
170
|
+
|
|
126
171
|
/**
|
|
127
172
|
* 宿主主题挂钩 —— 与 ui-theme 同一处:body[data-ds-dark-theme] 存在即深色档。
|
|
128
173
|
*/
|
|
@@ -180,16 +225,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
180
225
|
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
181
226
|
}
|
|
182
227
|
|
|
183
|
-
function hexA(hex, a) {
|
|
184
|
-
const n = parseInt(hex.slice(1), 16);
|
|
185
|
-
return "rgba(" + ((n >> 16) & 255) + "," + ((n >> 8) & 255) + "," + (n & 255) + "," + a.toFixed(3) + ")";
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function fmtBytes(n) {
|
|
189
|
-
if (n >= 1024) return (n / 1024).toFixed(1) + " KB";
|
|
190
|
-
return n + " B";
|
|
191
|
-
}
|
|
192
|
-
|
|
193
228
|
function fmtDate(ms) {
|
|
194
229
|
if (!ms) return "";
|
|
195
230
|
const d = new Date(ms);
|
|
@@ -391,39 +426,12 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
391
426
|
return blocks;
|
|
392
427
|
}
|
|
393
428
|
|
|
394
|
-
// ── overlay 开合的模块级 store(footer 按钮与 overlay 共享)──
|
|
395
|
-
const uiStore = { open: false, subs: new Set() };
|
|
396
429
|
/** client context 由 apply 存入;Slot 组件经 props 或此兜底获取。 */
|
|
397
430
|
let appCtx = null;
|
|
398
|
-
function setOpen(v) {
|
|
399
|
-
uiStore.open = !!v;
|
|
400
|
-
uiStore.subs.forEach((fn) => fn(uiStore.open));
|
|
401
|
-
}
|
|
402
|
-
function useOpen() {
|
|
403
|
-
const s = react.useState(uiStore.open);
|
|
404
|
-
react.useEffect(() => {
|
|
405
|
-
const fn = (v) => s[1](v);
|
|
406
|
-
uiStore.subs.add(fn);
|
|
407
|
-
return () => { uiStore.subs.delete(fn); };
|
|
408
|
-
}, []);
|
|
409
|
-
return s[0];
|
|
410
|
-
}
|
|
411
|
-
|
|
412
431
|
// ── 样式(data-plugin-css 约定,幂等注入)──
|
|
413
432
|
const CSS = [
|
|
414
|
-
".smap-footer-btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--dsw-alias-border-l1,transparent);background:transparent;color:var(--dsw-alias-label-secondary,inherit);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;font-family:inherit;white-space:nowrap;}",
|
|
415
|
-
".smap-fab{position:fixed;right:0;top:15%;transform:translateY(-50%);z-index:900;width:36px;height:64px;border-radius:12px 0 0 12px;border:1px solid var(--dsw-alias-border-l1);border-right:none;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-brand-primary);font-size:17px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:.5;pointer-events:auto;transition:opacity .15s,background .15s,width .15s;box-shadow:-4px 0 18px rgba(0,0,0,.35);font-family:inherit;}",
|
|
416
|
-
".smap-fab:hover{opacity:1;width:46px;background:var(--dsw-alias-bg-layer-1);}",
|
|
417
|
-
".smap-footer-btn:hover{color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l2,#8886);}",
|
|
418
|
-
".smap-footer-icon{font-size:13px;line-height:1;}",
|
|
419
|
-
".smap-veil{position:fixed;inset:0;z-index:1000;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.45));backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;pointer-events:auto;animation:smap-fade-in .18s ease-out;}",
|
|
420
|
-
".smap-modal{width:min(980px,94vw);height:min(680px,92vh);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55);padding:16px 18px;display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;animation:smap-pop-in .22s cubic-bezier(.2,.9,.3,1.15);}",
|
|
421
|
-
"@keyframes smap-fade-in{from{opacity:0}to{opacity:1}}",
|
|
422
|
-
"@keyframes smap-pop-in{from{opacity:0;transform:scale(.96) translateY(10px)}to{opacity:1;transform:none}}",
|
|
423
433
|
".smap-card{background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:12px 14px;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;flex:1;min-height:0;}",
|
|
424
434
|
".smap-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap;}",
|
|
425
|
-
".smap-title{font-size:15px;font-weight:600;letter-spacing:.06em;}",
|
|
426
|
-
".smap-sub{font-size:11px;color:var(--dsw-alias-label-secondary);}",
|
|
427
435
|
".smap-spacer{flex:1;}",
|
|
428
436
|
".smap-search{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;color:var(--dsw-alias-label-primary);font-size:12px;padding:4px 9px;outline:none;width:160px;font-family:inherit;}",
|
|
429
437
|
".smap-search:focus{border-color:var(--dsw-alias-border-l2);}",
|
|
@@ -1358,7 +1366,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1358
1366
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
1359
1367
|
}
|
|
1360
1368
|
legendKids.push(h("span", { key: "count", className: "smap-count" },
|
|
1361
|
-
viewStars.length + " 条 · " +
|
|
1369
|
+
viewStars.length + " 条 · " + fmtSize(totalBytes) + (newest ? " · 最近更新 " + fmtDate(newest) : "") +
|
|
1362
1370
|
(showArchive && archivedN ? " · 档案馆 " + archivedN + " 颗暗星" : "") +
|
|
1363
1371
|
" · 单击看" + (showArchive && archivedN ? "详情" : "全文")));
|
|
1364
1372
|
|
|
@@ -1367,7 +1375,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1367
1375
|
const kids = [
|
|
1368
1376
|
h("div", { key: "t", className: "smap-tip-title" }, hover.star.title),
|
|
1369
1377
|
h("div", { key: "k", className: "smap-tip-kind" },
|
|
1370
|
-
meta.label + " · " + hover.star.file + " · " +
|
|
1378
|
+
meta.label + " · " + hover.star.file + " · " + fmtSize(hover.star.bytes)),
|
|
1371
1379
|
];
|
|
1372
1380
|
if (hover.star.archived === true) {
|
|
1373
1381
|
// 悬浮也要说清它是档案馆里的:暗星外表已经不同,别让人猜。
|
|
@@ -1391,7 +1399,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1391
1399
|
h("button", { className: "smap-btn", onClick: () => setSelected(null), title: "关闭" }, "×")),
|
|
1392
1400
|
h("div", { key: "meta", className: "smap-panel-meta" },
|
|
1393
1401
|
h("span", { className: "smap-meta-dot", style: { background: kindColor(meta) } }),
|
|
1394
|
-
meta.label + " · " + selected.star.file + " · " +
|
|
1402
|
+
meta.label + " · " + selected.star.file + " · " + fmtSize(selected.star.bytes) +
|
|
1395
1403
|
// 归档星的 mtime 是「当年写下」的时间,跟「什么时候收起来的」不是一回事 ——
|
|
1396
1404
|
// 这里只留「已归档」,具体时间在下面的归档块里给。
|
|
1397
1405
|
(selected.star.archived === true
|
|
@@ -1494,42 +1502,11 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1494
1502
|
body);
|
|
1495
1503
|
}
|
|
1496
1504
|
|
|
1497
|
-
// ── 全屏 overlay ─────────────────────────────────────────────
|
|
1498
|
-
function StarmapOverlay() {
|
|
1499
|
-
const open = useOpen();
|
|
1500
|
-
react.useEffect(() => {
|
|
1501
|
-
if (!open) return undefined;
|
|
1502
|
-
const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
|
|
1503
|
-
document.addEventListener("keydown", onKey);
|
|
1504
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
1505
|
-
}, [open]);
|
|
1506
|
-
if (!open) return null;
|
|
1507
|
-
return h("div", {
|
|
1508
|
-
className: "smap-veil",
|
|
1509
|
-
onMouseDown: (e) => { if (e.target === e.currentTarget) setOpen(false); },
|
|
1510
|
-
},
|
|
1511
|
-
h("div", { className: "smap-modal" },
|
|
1512
|
-
h(StarMap, { ctx: appCtx, onClose: () => setOpen(false) })));
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
// ── 窗口右缘浮标(唯一入口,不绑实例/会话/Run 卡片)────────────
|
|
1516
|
-
function StarmapEdgeTab() {
|
|
1517
|
-
const open = useOpen();
|
|
1518
|
-
if (open) return null;
|
|
1519
|
-
return h("button", {
|
|
1520
|
-
type: "button",
|
|
1521
|
-
className: "smap-fab",
|
|
1522
|
-
onClick: () => setOpen(true),
|
|
1523
|
-
title: "记忆星图 — 把 sage-mem 的记忆画成一片星空",
|
|
1524
|
-
"aria-label": "记忆星图",
|
|
1525
|
-
}, "✦");
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
1505
|
const inject = ["slots", "remote"];
|
|
1529
1506
|
|
|
1530
1507
|
/**
|
|
1531
1508
|
* Client 插件:$mount strict remote contribution(第三方 remote 不在
|
|
1532
|
-
* 宿主的固定 remote
|
|
1509
|
+
* 宿主的固定 remote 清单里,必须自己挂),再注册星图子槽(B 方案起不再有右缘浮标与全屏 overlay)。
|
|
1533
1510
|
*/
|
|
1534
1511
|
async function apply(ctx) {
|
|
1535
1512
|
appCtx = ctx;
|
|
@@ -1559,22 +1536,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1559
1536
|
|
|
1560
1537
|
|
|
1561
1538
|
// ── 手写 strict codec(浏览器无 zod,typert 只要求 parse 方法)──
|
|
1562
|
-
|
|
1563
|
-
return {
|
|
1564
|
-
parse(value) {
|
|
1565
|
-
if (value === null || typeof value !== "object") throw new Error("sage-mem: invalid payload");
|
|
1566
|
-
for (const [key, check] of Object.entries(shape)) {
|
|
1567
|
-
if (!(key in value)) throw new Error("sage-mem: missing field " + key);
|
|
1568
|
-
check(value[key]);
|
|
1569
|
-
}
|
|
1570
|
-
return value;
|
|
1571
|
-
},
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
const isStr = (v) => { if (typeof v !== "string") throw new Error("expected string"); };
|
|
1575
|
-
const isBool = (v) => { if (typeof v !== "boolean") throw new Error("expected boolean"); };
|
|
1576
|
-
const isNum = (v) => { if (typeof v !== "number") throw new Error("expected number"); };
|
|
1577
|
-
const strSchema = { parse(v) { isStr(v); return v; } };
|
|
1539
|
+
// 基元(parseSchema / isStr / isBool / isNum / strSchema)在 05-shared.js。
|
|
1578
1540
|
const fileSchema = parseSchema({ "file": isStr, "type": isStr, "description": isStr, "size": isNum });
|
|
1579
1541
|
const listSchema = { parse(v) { if (!Array.isArray(v)) throw new Error("expected array"); v.forEach((f) => fileSchema.parse(f)); return v; } };
|
|
1580
1542
|
const readSchema = parseSchema({ "name": isStr, "content": isStr });
|
|
@@ -2072,10 +2034,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2072
2034
|
// ── 工具行 + 工具面板(体检 / 归档候选 / 保留名原样编辑)──
|
|
2073
2035
|
// 三个新入口收在一行**轻量**文字按钮里:不跟主工具栏抢重量级,也不各占一块版面。
|
|
2074
2036
|
// 面板一次只开一个(Section 里一个 tool 状态),否则文件列表会被顶到屏幕外。
|
|
2075
|
-
".smem-tools{display:flex;align-items:center;gap:4px;flex-wrap:wrap;}",
|
|
2076
|
-
".smem-tool-btn{border:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:12px;font-family:inherit;cursor:pointer;padding:2px 8px;border-radius:6px;}",
|
|
2077
|
-
".smem-tool-btn:hover{color:var(--dsw-alias-label-primary);}",
|
|
2078
|
-
'.smem-tool-btn[data-on="1"]{color:var(--dsw-alias-brand-primary,#4d76e6);background:var(--dsw-alias-bg-layer-2);}',
|
|
2079
2037
|
// 工具抽屉:关着时**零占位**(工具栏里只有一个「工具 ▾」),点开才占版面。
|
|
2080
2038
|
// ⚠️ 可发现性不靠抽屉本身,靠头部带常显的「体检 N 个问题」徽标 —— 那是整个
|
|
2081
2039
|
// 抽屉方案能成立的前提(否则三个能力就退回「藏起来」了)。
|
|
@@ -2207,18 +2165,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2207
2165
|
".smem-star-link{color:var(--dsw-alias-brand-primary,#4d76e6);text-decoration:underline;}",
|
|
2208
2166
|
].join("\n");
|
|
2209
2167
|
|
|
2210
|
-
const TYPE_META = {
|
|
2211
|
-
user: ["👤", "用户"],
|
|
2212
|
-
feedback: ["📌", "反馈"],
|
|
2213
|
-
project: ["📁", "项目"],
|
|
2214
|
-
reference: ["🔗", "参考"],
|
|
2215
|
-
};
|
|
2216
|
-
const TYPE_ORDER = ["user", "feedback", "project", "reference"];
|
|
2217
|
-
// 筛选条上的显示名:emoji 在筛选条里太吵,只用文字;special 是星图的兜底类,
|
|
2218
|
-
// 文件列表里出现它说明 frontmatter 写了 type: special。
|
|
2219
|
-
const TYPE_LABEL = { user: "用户", feedback: "反馈", project: "项目", reference: "参考", special: "特殊" };
|
|
2220
|
-
const TYPE_SORT = ["user", "feedback", "project", "reference", "special"];
|
|
2221
|
-
|
|
2222
2168
|
/**
|
|
2223
2169
|
* 把输入框里的一串标签切成数组。
|
|
2224
2170
|
*
|
|
@@ -2467,17 +2413,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2467
2413
|
tagLine + "\nmetadata:\n node_type: memory\n type: " + type + "\n---\n\n";
|
|
2468
2414
|
}
|
|
2469
2415
|
|
|
2470
|
-
function fmtSize(n) {
|
|
2471
|
-
if (n < 1024) return n + " B";
|
|
2472
|
-
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + " KB";
|
|
2473
|
-
return (n / 1024 / 1024).toFixed(1) + " MB";
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
|
-
/** 拆 typert remote 的 {ok, value} 信封。 */
|
|
2477
|
-
function unwrap(result) {
|
|
2478
|
-
return result && result.ok ? result.value : result;
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
2416
|
function Chip(props) {
|
|
2482
2417
|
return h("button", {
|
|
2483
2418
|
type: "button",
|
|
@@ -2766,7 +2701,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2766
2701
|
standalone ? null : toolClose(props),
|
|
2767
2702
|
]),
|
|
2768
2703
|
r.problems
|
|
2769
|
-
? h("div", {
|
|
2704
|
+
? h("div", { key: "secs" }, [
|
|
2770
2705
|
section("索引悬空(索引里有、文件没了)", r.dangling, (x) => x.file),
|
|
2771
2706
|
section("漏索引(文件在、索引里没有)", r.unlisted, (x) => x.file),
|
|
2772
2707
|
section("type 与前缀对不上", r.typeMismatch, (x) => x.file + " · type=" + x.type + ",文件名前缀=" + x.prefix),
|
|
@@ -3252,7 +3187,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3252
3187
|
subtab("settings", "设置"),
|
|
3253
3188
|
subtab("records", "记录", String(snaps.length + runs.length + reports.length)),
|
|
3254
3189
|
]),
|
|
3255
|
-
segOf === "run" ? h("div", {
|
|
3190
|
+
segOf === "run" ? h("div", { key: "seg-run" }, [
|
|
3256
3191
|
h("div", { className: "smem-autodream-sec", key: "top" }, [
|
|
3257
3192
|
h("div", { className: "smem-autodream-row", key: "r" }, [
|
|
3258
3193
|
h("button", {
|
|
@@ -3376,7 +3311,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3376
3311
|
: null,
|
|
3377
3312
|
]),
|
|
3378
3313
|
]) : null,
|
|
3379
|
-
segOf === "settings" ? h("div", {
|
|
3314
|
+
segOf === "settings" ? h("div", { key: "seg-set" }, [
|
|
3380
3315
|
// 自动归档那一段(三档策略 + 三个阈值)**已挪到「自动归档」页签**(v0.9.9):
|
|
3381
3316
|
// 归档是确定性规则、不调模型,和这一页的「让模型整理」不是一件事;
|
|
3382
3317
|
// 同一件事只在一处设定,这里不再重复摆一份。
|
|
@@ -3477,7 +3412,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3477
3412
|
]) : null,
|
|
3478
3413
|
// ── 回滚点(新)──────────────────────────────────────────────
|
|
3479
3414
|
// 只改这一个文件、只用既有 h() 写法;数据全走 remote.autodream。
|
|
3480
|
-
segOf === "records" ? h("div", {
|
|
3415
|
+
segOf === "records" ? h("div", { key: "seg-rec" }, [
|
|
3481
3416
|
h("div", { className: "smem-autodream-sec", key: "snap" }, [
|
|
3482
3417
|
h("div", { className: "smem-autodream-row", key: "h" }, [
|
|
3483
3418
|
h("span", { key: "t", style: { fontWeight: "600", fontSize: "12.5px" } }, "回滚点"),
|
|
@@ -3706,7 +3641,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3706
3641
|
});
|
|
3707
3642
|
}
|
|
3708
3643
|
|
|
3709
|
-
return h("div", {
|
|
3644
|
+
return h("div", { }, [
|
|
3710
3645
|
// ── ① 它做什么(这一屏存在的理由写在最前面)──
|
|
3711
3646
|
h("div", { className: "smem-autodream-sec", key: "what" }, [
|
|
3712
3647
|
h("div", { className: "smem-autodream-row", key: "h" }, [
|
|
@@ -3898,7 +3833,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3898
3833
|
const rawBusy = sRawBusy[0], setRawBusy = sRawBusy[1];
|
|
3899
3834
|
const sRawLoading = react.useState(false);
|
|
3900
3835
|
const rawLoading = sRawLoading[0], setRawLoading = sRawLoading[1];
|
|
3901
|
-
|
|
3836
|
+
// renderSlot:shell 会经 props 传进来(见 80-apply 的 children 声明),
|
|
3837
|
+
// 但本插件改用并列 tab 渲染星图,不再调用它 —— 声明保留给 shell,这里不取。
|
|
3902
3838
|
|
|
3903
3839
|
function load() {
|
|
3904
3840
|
setLoading(true);
|
package/package.json
CHANGED