sage-mem 1.4.0 → 1.5.1
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 +3 -0
- package/README.zh.md +3 -0
- package/lib/client.js +107 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -538,6 +538,9 @@ No. Serialized writes guarantee only **in-process** ordering; there is no file l
|
|
|
538
538
|
**Can I do without autodream?**
|
|
539
539
|
Yes, it is off by default. It and archiving are two different things: archiving is a deterministic rule (by idle days), calls no model and costs nothing.
|
|
540
540
|
|
|
541
|
+
**The plugin market says "the registry's latest is older than the installed version, updating would downgrade"?**
|
|
542
|
+
That is a **stale `/latest` cache on the download-region mirror**, not a mis-published package: the mirror's full metadata (the document pnpm reads) already has the new version, while the `/<pkg>/latest` shortcut still serves an old one. Retry after a minute or two; if it persists, temporarily switch the market's download region to "Global" (the origin registry, registry.npmjs.org), update, then switch back. To check what is actually published: `npm view sage-mem dist-tags`.
|
|
543
|
+
|
|
541
544
|
## Uninstall
|
|
542
545
|
|
|
543
546
|
```bash
|
package/README.zh.md
CHANGED
|
@@ -543,6 +543,9 @@ npm test # 全部断言(含三条守卫)
|
|
|
543
543
|
**能不用自动做梦吗?**
|
|
544
544
|
能,它默认就是关闭的。它和归档是两件事:归档是确定性规则(按闲置天数),不调模型、不花钱。
|
|
545
545
|
|
|
546
|
+
**插件市场报「registry 上的最新版比已装还旧,更新会降级」?**
|
|
547
|
+
那是**下载地区镜像的 `/latest` 缓存滞后**,不是包发错了:镜像的全量元数据(pnpm 读的那份)已经是新版,但 `/<包>/latest` 这个快捷入口还缓存着旧值。先等一两分钟重试;仍然不行就把插件市场的「下载地区」临时切到「全球」(直连 registry.npmjs.org)更新,完成后再切回。核对实际发布版本:`npm view sage-mem dist-tags`。
|
|
548
|
+
|
|
546
549
|
## 卸载
|
|
547
550
|
|
|
548
551
|
```bash
|
package/lib/client.js
CHANGED
|
@@ -2038,7 +2038,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2038
2038
|
// ⚠️ 可发现性不靠抽屉本身,靠头部带常显的「体检 N 个问题」徽标 —— 那是整个
|
|
2039
2039
|
// 抽屉方案能成立的前提(否则三个能力就退回「藏起来」了)。
|
|
2040
2040
|
".smem-drawer{position:relative;flex:none;}",
|
|
2041
|
-
".smem-drawer-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:6;min-width:236px;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.10);padding:6px;display:flex;flex-direction:column;gap:2px;}",
|
|
2041
|
+
".smem-drawer-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:6;min-width:236px;max-width:min(320px,calc(100vw - 24px));background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.10);padding:6px;display:flex;flex-direction:column;gap:2px;}",
|
|
2042
2042
|
".smem-drawer-item{display:flex;align-items:center;gap:8px;border:0;background:transparent;font-family:inherit;font-size:12.5px;color:var(--dsw-alias-label-primary);text-align:left;padding:6px 8px;border-radius:8px;cursor:pointer;}",
|
|
2043
2043
|
".smem-drawer-item:hover{background:var(--dsw-alias-bg-layer-2);}",
|
|
2044
2044
|
'.smem-drawer-item[data-on="1"]{background:var(--dsw-alias-bg-layer-2);font-weight:600;}',
|
|
@@ -2089,7 +2089,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2089
2089
|
'.smem-subtab--on:after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-label-primary);}',
|
|
2090
2090
|
".smem-subtab-n{opacity:.6;margin-left:5px;font-variant-numeric:tabular-nums;}",
|
|
2091
2091
|
// 五个注入参数排两列:一行放两个,扫读反而更清楚(吸收方案 A 的做法)。
|
|
2092
|
-
".smem-ad-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(
|
|
2092
|
+
".smem-ad-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:4px 18px;}",
|
|
2093
2093
|
".smem-ad-field{display:flex;align-items:center;gap:8px;min-width:0;}",
|
|
2094
2094
|
".smem-ad-field .smem-autodream-key{min-width:96px;}",
|
|
2095
2095
|
".smem-actions{display:flex;gap:6px;}",
|
|
@@ -2113,7 +2113,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2113
2113
|
'.smem-tab--on:after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-label-primary);}',
|
|
2114
2114
|
// 高度预算压到 62vh(原 70vh):设置弹窗本身高度有限,
|
|
2115
2115
|
// 70vh 在较矮的设置弹窗视口下会把星图底部的图例和计数挤出面板之外。
|
|
2116
|
-
".smem-starmap{display:flex;flex-direction:column;height:
|
|
2116
|
+
".smem-starmap{display:flex;flex-direction:column;height:clamp(320px,55vh,620px);min-height:280px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;overflow:hidden;}",
|
|
2117
2117
|
// ── 「自动做梦」面板 ──
|
|
2118
2118
|
// 融入型:全部走宿主变量,控件复用已有的 chip / input / btn 语言,不另造一套。
|
|
2119
2119
|
".smem-autodream{display:flex;flex-direction:column;gap:12px;}",
|
|
@@ -2160,6 +2160,21 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2160
2160
|
".smem-update{display:flex;align-items:center;gap:10px;flex-wrap:wrap;border:1px solid var(--dsw-alias-brand-primary,#4d76e6);border-radius:8px;padding:6px 10px;font-size:12px;background:var(--dsw-alias-bg-layer-1);}",
|
|
2161
2161
|
".smem-update-link{color:var(--dsw-alias-brand-primary,#4d76e6);text-decoration:underline;}",
|
|
2162
2162
|
".smem-update-x{margin-left:auto;border:0;background:transparent;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:0 2px;}",
|
|
2163
|
+
// ── 1.5.1:筛选汇总行(有筛选才出现)──
|
|
2164
|
+
".smem-filter-summary{width:100%;display:flex;align-items:center;flex-wrap:wrap;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary);}",
|
|
2165
|
+
".smem-sum-item{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:1px 8px;}",
|
|
2166
|
+
".smem-sum-x{border:0;background:transparent;color:inherit;cursor:pointer;font-size:12px;line-height:1;padding:0 0 0 2px;}",
|
|
2167
|
+
".smem-sum-clear{border:0;background:transparent;color:var(--dsw-alias-brand-primary,#4d76e6);font-size:12px;font-family:inherit;cursor:pointer;padding:2px 4px;}",
|
|
2168
|
+
// ── 1.5.0:动作分组 / 长文 clamp / 空态骨架 / 窄窗口 ──
|
|
2169
|
+
".smem-actions-sep{width:1px;height:16px;background:var(--dsw-alias-border-l2);margin:0 2px;align-self:center;}",
|
|
2170
|
+
".smem-clamp-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;cursor:pointer;}",
|
|
2171
|
+
".smem-clamp-2--open{-webkit-line-clamp:unset;display:block;}",
|
|
2172
|
+
".smem-skeleton{display:flex;flex-direction:column;gap:10px;padding:6px 0;}",
|
|
2173
|
+
".smem-skeleton-row{height:44px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);opacity:.55;}",
|
|
2174
|
+
".smem-empty{display:flex;flex-direction:column;align-items:flex-start;gap:8px;}",
|
|
2175
|
+
".smem-tabs-sep{width:1px;align-self:stretch;margin:6px 2px;background:var(--dsw-alias-border-l2);}",
|
|
2176
|
+
// 窄窗口(≤420px):头部带与筛选条各让一行,卡片动作允许换行、分隔符隐藏。
|
|
2177
|
+
"@media (max-width:420px){.smem-root{gap:10px;}.smem-head{gap:6px;}.smem-card-title{min-width:0;word-break:break-word;}.smem-actions{flex-wrap:wrap;}.smem-actions-sep{display:none;}.smem-num{width:56px;}.smem-search{min-width:100px;}}",
|
|
2163
2178
|
// ── 底部一行仓库链接(引流,不抢视线)──
|
|
2164
2179
|
".smem-star{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;font-size:12px;color:var(--dsw-alias-label-tertiary,#8b93a1);padding:2px 2px 0;}",
|
|
2165
2180
|
".smem-star-link{color:var(--dsw-alias-brand-primary,#4d76e6);text-decoration:underline;}",
|
|
@@ -2474,6 +2489,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2474
2489
|
]
|
|
2475
2490
|
: [
|
|
2476
2491
|
h("button", { type: "button", className: "smem-btn", key: "edit", onClick: function () { props.onEdit(item.file); } }, "编辑"),
|
|
2492
|
+
// 语义分组:左边只放「编辑」(安全、可逆),右边放「锁定 / 归档 / 删除」(对这条记忆的退役/保护决定)。
|
|
2493
|
+
h("span", { key: "sep", className: "smem-actions-sep", "aria-hidden": "true" }),
|
|
2477
2494
|
/**
|
|
2478
2495
|
* 锁定排在「编辑」与「归档」之间(用户 2026-10-11 指定):
|
|
2479
2496
|
* 它是「别归档这条」的开关,紧挨着归档才说得通。
|
|
@@ -2524,6 +2541,9 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2524
2541
|
function ArchivedCard(props) {
|
|
2525
2542
|
const item = props.item;
|
|
2526
2543
|
const meta = TYPE_META[item.type] || TYPE_META.reference;
|
|
2544
|
+
// 描述与归档理由都可能很长:默认各 clamp(描述 3 行 / 理由 2 行),点一下展开全文。
|
|
2545
|
+
const sDescOpen = react.useState(false);
|
|
2546
|
+
const descOpen = sDescOpen[0], setDescOpen = sDescOpen[1];
|
|
2527
2547
|
return h("div", { className: "smem-card smem-card--archived", key: item.file }, [
|
|
2528
2548
|
h("div", { className: "smem-card-head", key: "head" }, [
|
|
2529
2549
|
h("span", { className: "smem-badge", key: "badge", title: "类型 " + String(item.type) }, meta[0] + " " + meta[1]),
|
|
@@ -2539,9 +2559,18 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2539
2559
|
// 描述留在活动卡片里的同一个位置(标签下面),归档留痕块再往下 ——
|
|
2540
2560
|
// 否则「归档理由」像卡片结尾,后面孤零零一行描述没人认得它是什么。
|
|
2541
2561
|
item.description
|
|
2542
|
-
? h("div", {
|
|
2562
|
+
? h("div", {
|
|
2563
|
+
className: "smem-narrative", key: "desc",
|
|
2564
|
+
"data-clamp": descOpen ? "0" : "1",
|
|
2565
|
+
title: descOpen ? "点击收起" : "点击展开全文",
|
|
2566
|
+
onClick: function () { setDescOpen(!descOpen); },
|
|
2567
|
+
}, String(item.description))
|
|
2543
2568
|
: null,
|
|
2544
|
-
h("div", {
|
|
2569
|
+
h("div", {
|
|
2570
|
+
className: "smem-ar-reason smem-clamp-2" + (descOpen ? " smem-clamp-2--open" : ""),
|
|
2571
|
+
key: "why", title: "归档理由:" + (item.archivedReason || "(没写)"),
|
|
2572
|
+
onClick: function () { setDescOpen(!descOpen); },
|
|
2573
|
+
}, "归档理由:" + (item.archivedReason || "(没写)")),
|
|
2545
2574
|
props.editing
|
|
2546
2575
|
? h("div", { className: "smem-ar-edit", key: "edit" }, [
|
|
2547
2576
|
h("div", { className: "smem-ar-hint", key: "note" },
|
|
@@ -2578,7 +2607,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2578
2607
|
disabled: props.busy,
|
|
2579
2608
|
onClick: function () { props.onEdit(item.file); },
|
|
2580
2609
|
}, "编辑"),
|
|
2581
|
-
|
|
2610
|
+
h("span", { key: "sep", className: "smem-actions-sep", "aria-hidden": "true" }),
|
|
2611
|
+
h("button", {
|
|
2582
2612
|
type: "button", className: "smem-btn smem-btn-primary", key: "restore",
|
|
2583
2613
|
disabled: props.busy,
|
|
2584
2614
|
onClick: function () { props.onRestore(item.file); },
|
|
@@ -3724,6 +3754,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
3724
3754
|
const sNotice = react.useState("");
|
|
3725
3755
|
const notice = sNotice[0], setNotice = sNotice[1];
|
|
3726
3756
|
const sQuery = react.useState("");
|
|
3757
|
+
const sTagOpen = react.useState(false);
|
|
3758
|
+
const tagOpen = sTagOpen[0], setTagOpen = sTagOpen[1];
|
|
3727
3759
|
const query = sQuery[0], setQuery = sQuery[1];
|
|
3728
3760
|
const sExpanded = react.useState({});
|
|
3729
3761
|
const expanded = sExpanded[0], setExpanded = sExpanded[1];
|
|
@@ -4341,6 +4373,17 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4341
4373
|
return hay.indexOf(q) >= 0;
|
|
4342
4374
|
});
|
|
4343
4375
|
const hasFilter = !!(statusFilter !== "all" || typeFilter.length || tagFilter.length || q);
|
|
4376
|
+
// 标签最多平铺 6 个:再多就把筛选条撑成三行,而真正常用的标签通常就那几个。
|
|
4377
|
+
const TAG_VISIBLE_MAX = 6;
|
|
4378
|
+
const tagShown = tagOpen ? tagList : tagList.slice(0, TAG_VISIBLE_MAX);
|
|
4379
|
+
const tagHiddenCount = tagList.length - tagShown.length;
|
|
4380
|
+
// 汇总行里每一项都是「现在正在筛什么 + 单独撤掉它」;只出现有筛选时。
|
|
4381
|
+
function sumItem(label, onRemove) {
|
|
4382
|
+
return h("span", { className: "smem-sum-item", key: "sum-" + label }, [
|
|
4383
|
+
label,
|
|
4384
|
+
h("button", { type: "button", className: "smem-sum-x", key: "x", title: "撤掉这项筛选", onClick: onRemove }, "×"),
|
|
4385
|
+
]);
|
|
4386
|
+
}
|
|
4344
4387
|
// 两个计数永远一起露脸:用户不必先筛状态才知道档案馆里有没有东西。
|
|
4345
4388
|
const headerCount = (hasFilter ? "筛出 " + String(filtered.length) + " / " + String(statusItems.length) + " · " : "") +
|
|
4346
4389
|
"活动中 " + String(items.length) + " · 已归档 " + String(archiveItems.length);
|
|
@@ -4356,18 +4399,29 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4356
4399
|
// banner 只在**专门看归档**时出现,切到全部时不重复说一遍。
|
|
4357
4400
|
let filesView;
|
|
4358
4401
|
if (loading && totalCount === 0) {
|
|
4359
|
-
filesView = h("div", { className: "smem-
|
|
4402
|
+
filesView = h("div", { className: "smem-skeleton", key: "loading", "data-loading": "1" }, [0, 1, 2].map(function (i) {
|
|
4403
|
+
return h("div", { className: "smem-skeleton-row", key: i });
|
|
4404
|
+
}));
|
|
4360
4405
|
} else if (totalCount === 0) {
|
|
4361
|
-
filesView = h("div", { className: "smem-empty", key: "empty" },
|
|
4362
|
-
"
|
|
4406
|
+
filesView = h("div", { className: "smem-empty", key: "empty" }, [
|
|
4407
|
+
h("div", { key: "t" }, "还没有记忆文件。对话中值得记住的事会写到这里,也可以手动写入。"),
|
|
4408
|
+
h("button", { type: "button", className: "smem-btn smem-btn-primary", key: "add", onClick: openAdd }, "+ 添加记忆"),
|
|
4409
|
+
]);
|
|
4363
4410
|
} else if (statusFilter === "archived" && archiveItems.length === 0) {
|
|
4364
|
-
filesView = h("div", { className: "smem-empty", key: "empty" },
|
|
4365
|
-
"档案馆是空的 —— 在活动记忆那张卡上点「归档」,它就会收到这里。")
|
|
4411
|
+
filesView = h("div", { className: "smem-empty", key: "empty" }, [
|
|
4412
|
+
h("div", { key: "t" }, "档案馆是空的 —— 在活动记忆那张卡上点「归档」,它就会收到这里。"),
|
|
4413
|
+
h("button", { type: "button", className: "smem-btn", key: "back", onClick: function () { setStatusFilter("active"); } }, "回文件列表"),
|
|
4414
|
+
]);
|
|
4366
4415
|
} else if (statusFilter === "active" && items.length === 0) {
|
|
4367
|
-
filesView = h("div", { className: "smem-empty", key: "empty" },
|
|
4368
|
-
"活动记忆是空的 —— 状态筛到「已归档」还能捞出 " + archiveItems.length + " 条。")
|
|
4416
|
+
filesView = h("div", { className: "smem-empty", key: "empty" }, [
|
|
4417
|
+
h("div", { key: "t" }, "活动记忆是空的 —— 状态筛到「已归档」还能捞出 " + archiveItems.length + " 条。"),
|
|
4418
|
+
h("button", { type: "button", className: "smem-btn", key: "go", onClick: function () { setStatusFilter("archived"); } }, "切到已归档"),
|
|
4419
|
+
]);
|
|
4369
4420
|
} else if (filtered.length === 0) {
|
|
4370
|
-
filesView = h("div", { className: "smem-empty", key: "empty" },
|
|
4421
|
+
filesView = h("div", { className: "smem-empty", key: "empty" }, [
|
|
4422
|
+
h("div", { key: "t" }, "没有符合搜索或筛选条件的文件。"),
|
|
4423
|
+
h("button", { type: "button", className: "smem-btn", key: "clear", onClick: function () { setStatusFilter("all"); setTypeFilter([]); setTagFilter([]); setQuery(""); } }, "清除筛选"),
|
|
4424
|
+
]);
|
|
4371
4425
|
} else {
|
|
4372
4426
|
const list = h("div", { className: "smem-list", key: "list" }, filtered.map(function (it) {
|
|
4373
4427
|
if (it.archived === true) {
|
|
@@ -4427,25 +4481,26 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4427
4481
|
}
|
|
4428
4482
|
|
|
4429
4483
|
return h("div", { className: "smem-root" }, [
|
|
4430
|
-
h("div", { className: "smem-tabs", key: "tabs" }, [
|
|
4431
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "files" ? " smem-tab--on" : ""), key: "f", onClick: function () { setTab("files"); } }, "文件列表"),
|
|
4432
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "star" ? " smem-tab--on" : ""), key: "s", onClick: function () { setTab("star"); } }, "记忆星图"),
|
|
4433
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "autodream" ? " smem-tab--on" : ""), key: "d", onClick: function () { setTab("autodream"); } }, "自动做梦"),
|
|
4484
|
+
h("div", { className: "smem-tabs", key: "tabs", role: "tablist" }, [
|
|
4485
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "files" ? " smem-tab--on" : ""), key: "f", role: "tab", "aria-selected": tab === "files" ? "true" : "false", onClick: function () { setTab("files"); } }, "文件列表"),
|
|
4486
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "star" ? " smem-tab--on" : ""), key: "s", role: "tab", "aria-selected": tab === "star" ? "true" : "false", onClick: function () { setTab("star"); } }, "记忆星图"),
|
|
4487
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "autodream" ? " smem-tab--on" : ""), key: "d", role: "tab", "aria-selected": tab === "autodream" ? "true" : "false", onClick: function () { setTab("autodream"); } }, "自动做梦"),
|
|
4488
|
+
// 视觉分组:左边「看」(文件列表 / 星图),右边「设置 · 自动化」。
|
|
4489
|
+
h("span", { className: "smem-tabs-sep", key: "sep", "aria-hidden": "true" }),
|
|
4434
4490
|
// 「自动归档」排在自动做梦之后:归档是**确定性规则**(按闲置天数算,不调模型),
|
|
4435
4491
|
// 和「让模型整理记忆」是两件事。塞在自动做梦的设置里用户找不到
|
|
4436
4492
|
// (2026-10-11 用户原话:「扔这里连我都找不到」)。
|
|
4437
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "archive" ? " smem-tab--on" : ""), key: "ar", onClick: function () { setTab("archive"); } }, "自动归档"),
|
|
4493
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "archive" ? " smem-tab--on" : ""), key: "ar", role: "tab", "aria-selected": tab === "archive" ? "true" : "false", onClick: function () { setTab("archive"); } }, "自动归档"),
|
|
4438
4494
|
// 体检再排在「自动归档」之后、独立成一屏:它只报告不修改,和「文件列表」里的
|
|
4439
4495
|
// 增删改是两件事,塞在工具抽屉里会让人以为它是个动作按钮。
|
|
4440
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "audit" ? " smem-tab--on" : ""), key: "a", onClick: openAuditTab }, "体检"),
|
|
4496
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "audit" ? " smem-tab--on" : ""), key: "a", role: "tab", "aria-selected": tab === "audit" ? "true" : "false", onClick: openAuditTab }, "体检"),
|
|
4441
4497
|
]),
|
|
4442
4498
|
// 四个 tab 共用的一条头部带:我在哪 · 目录状态 · 活动/归档计数 · 体检徽标 · 待重启徽标 · 主操作。
|
|
4443
4499
|
// 层级形状固定:导航=下划线(.smem-tabs)、筛选=chip、动作=按钮,三种不混用。
|
|
4444
4500
|
h("div", { className: "smem-head", key: "head" }, [
|
|
4445
4501
|
h("span", { className: "smem-title", key: "t" }, "记忆管理"),
|
|
4446
|
-
|
|
4447
|
-
h("span", { className: "smem-dot" + (dirOk ? "" : " smem-dot--bad"), key: "dot", title: dirOk ? "memory 目录可读" : "memory 目录不可读" }),
|
|
4448
|
-
h("span", { className: "smem-muted", key: "st" }, dirOk ? "目录可读" : "目录不可读"),
|
|
4502
|
+
// 目录状态收进状态点的 title(不可读时下面另有一条 smem-err,错误本来就该显眼)。
|
|
4503
|
+
h("span", { className: "smem-dot" + (dirOk ? "" : " smem-dot--bad"), key: "dot", title: (dirOk ? "memory 目录可读" : "memory 目录不可读") + " · " + String(TAB_LABEL[tab] || "") }),
|
|
4449
4504
|
h("span", { className: "smem-badge", key: "cnt" }, headerCount),
|
|
4450
4505
|
// 体检徽标:**抽屉关着也一直看得见**,点它就切到「体检」那一屏。
|
|
4451
4506
|
h("button", {
|
|
@@ -4496,6 +4551,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4496
4551
|
type: "button", key: "btn",
|
|
4497
4552
|
className: "smem-btn" + (drawer ? " smem-btn-primary" : ""),
|
|
4498
4553
|
"aria-expanded": drawer ? "true" : "false",
|
|
4554
|
+
"aria-haspopup": "menu",
|
|
4499
4555
|
title: "归档候选 / 保留名编辑",
|
|
4500
4556
|
onClick: function () { setDrawer(!drawer); },
|
|
4501
4557
|
}, "工具 ▾"),
|
|
@@ -4565,6 +4621,24 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4565
4621
|
// 三排筛选:状态 / 类型 / 标签。组内 OR、组间 AND,再与搜索框 AND。
|
|
4566
4622
|
tab === "files" && totalCount
|
|
4567
4623
|
? h("div", { className: "smem-filters", key: "filters" }, [
|
|
4624
|
+
hasFilter
|
|
4625
|
+
? h("div", { className: "smem-filter-summary", key: "sum" }, [
|
|
4626
|
+
statusFilter !== "all"
|
|
4627
|
+
? sumItem("状态:" + (statusFilter === "active" ? "活动中" : "已归档"), function () { setStatusFilter("all"); })
|
|
4628
|
+
: null,
|
|
4629
|
+
typeFilter.map(function (t) {
|
|
4630
|
+
return sumItem("类型:" + (TYPE_LABEL[t] || t), function () { toggleIn(setTypeFilter, t); });
|
|
4631
|
+
}),
|
|
4632
|
+
tagFilter.map(function (g) {
|
|
4633
|
+
return sumItem("标签:#" + g, function () { toggleIn(setTagFilter, g); });
|
|
4634
|
+
}),
|
|
4635
|
+
query.trim() ? sumItem("搜索:" + query.trim(), function () { setQuery(""); }) : null,
|
|
4636
|
+
h("button", {
|
|
4637
|
+
type: "button", className: "smem-sum-clear", key: "all",
|
|
4638
|
+
onClick: function () { setStatusFilter("all"); setTypeFilter([]); setTagFilter([]); setQuery(""); },
|
|
4639
|
+
}, "清除全部"),
|
|
4640
|
+
])
|
|
4641
|
+
: null,
|
|
4568
4642
|
h("span", { className: "smem-filters-label", key: "lst" }, "状态"),
|
|
4569
4643
|
h("button", {
|
|
4570
4644
|
type: "button", key: "st-all", className: "smem-chip",
|
|
@@ -4600,13 +4674,20 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4600
4674
|
}),
|
|
4601
4675
|
tagList.length ? h("span", { className: "smem-sep", key: "sep" }) : null,
|
|
4602
4676
|
tagList.length ? h("span", { className: "smem-filters-label", key: "lgt" }, "标签") : null,
|
|
4603
|
-
|
|
4677
|
+
tagShown.map(function (g) {
|
|
4604
4678
|
return h("button", {
|
|
4605
4679
|
type: "button", key: "tag-" + g, className: "smem-chip",
|
|
4606
4680
|
"data-on": tagFilter.indexOf(g) >= 0 ? "1" : "0",
|
|
4607
4681
|
onClick: function () { toggleIn(setTagFilter, g); },
|
|
4608
4682
|
}, ["#" + g, h("span", { className: "smem-chip-n", key: "n" }, String(tagCounts[g]))]);
|
|
4609
4683
|
}),
|
|
4684
|
+
tagList.length > TAG_VISIBLE_MAX
|
|
4685
|
+
? h("button", {
|
|
4686
|
+
type: "button", key: "moretag", className: "smem-btn",
|
|
4687
|
+
title: tagOpen ? "收起标签" : "还有一些标签没显示",
|
|
4688
|
+
onClick: function () { setTagOpen(!tagOpen); },
|
|
4689
|
+
}, tagOpen ? "收起标签" : ("更多标签 (" + String(tagHiddenCount) + ")") )
|
|
4690
|
+
: null,
|
|
4610
4691
|
hasFilter
|
|
4611
4692
|
? h("button", {
|
|
4612
4693
|
type: "button", key: "clear", className: "smem-btn",
|
|
@@ -4615,8 +4696,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
4615
4696
|
: null,
|
|
4616
4697
|
])
|
|
4617
4698
|
: null,
|
|
4618
|
-
error ? h("div", { className: "smem-err", key: "err" }, "⚠ " + error) : null,
|
|
4619
|
-
notice && !error ? h("div", { className: "smem-ok", key: "ok" }, "✓ " + notice) : null,
|
|
4699
|
+
error ? h("div", { className: "smem-err", key: "err", role: "alert" }, "⚠ " + error) : null,
|
|
4700
|
+
notice && !error ? h("div", { className: "smem-ok", key: "ok", role: "status" }, "✓ " + notice) : null,
|
|
4620
4701
|
formOpen
|
|
4621
4702
|
? h("div", { className: "smem-form", key: "form" }, [
|
|
4622
4703
|
h("div", { className: "smem-form-title", key: "ft" }, editingFile ? "编辑 " + editingFile : "添加记忆"),
|
package/package.json
CHANGED