@modusensus/dsh-mneme 0.8.8 → 0.8.9

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/client.js CHANGED
@@ -129,7 +129,10 @@ window.__ModuleLoader__.load({
129
129
  check: [["path", { d: "M20 6 9 17l-5-5" }]],
130
130
  inbox: [["polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12" }], ["path", { d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" }]],
131
131
  activity: [["path", { d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2" }]],
132
- flame: [["path", { d: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z" }]]
132
+ flame: [["path", { d: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z" }]],
133
+ // 意见与反馈入口的行首图标(Lucide 数据,同上 ISC 惯例内联)
134
+ bug: [["path", { d: "m8 2 1.88 1.88" }], ["path", { d: "M14.12 3.88 16 2" }], ["path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }], ["path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" }], ["path", { d: "M12 20v-9" }], ["path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }], ["path", { d: "M6 13H2" }], ["path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }], ["path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }], ["path", { d: "M22 13h-4" }], ["path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" }]],
135
+ mail: [["rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }], ["path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" }]]
133
136
  };
134
137
  const Icon = ({ name, size = 16, className }) => {
135
138
  const parts = ICON_PATHS[name];
@@ -166,6 +169,21 @@ window.__ModuleLoader__.load({
166
169
  }))));
167
170
  };
168
171
 
172
+ // 单颗星(与 ImportanceStars 同一份 Lucide 路径):筛选 chip、实体提及数、
173
+ // 注入预览这类行内小指标用它渲染,替换此前的文本星号——文本星号角更尖锐,
174
+ // 与卡片/抽屉的 SVG 星并排时明显不同形(用户反馈后全线统一)。
175
+ const StarGlyph = ({ size = 11, filled = true }) => h("svg", {
176
+ width: size,
177
+ height: size,
178
+ viewBox: "0 0 24 24",
179
+ "aria-hidden": "true",
180
+ fill: filled ? "currentColor" : "none",
181
+ stroke: "currentColor",
182
+ strokeWidth: 1.6,
183
+ strokeLinejoin: "round",
184
+ style: { verticalAlign: "-1px" }
185
+ }, h("path", { d: STAR_PATH_D, opacity: filled ? 1 : 0.35 }));
186
+
169
187
  // 热度徽章(阶段二):flame 图标 + 整数百分比,三档配色(热/温/冷)。
170
188
  // /list 仅在 heatEnabled=true 时下发 heat 字段——缺省即不渲染,开关关闭
171
189
  // 时徽章全站自动消失,前端无需感知开关状态。
@@ -233,7 +251,13 @@ window.__ModuleLoader__.load({
233
251
  "memory.tab.project": "项目",
234
252
  "memory.tab.decision": "决策",
235
253
  "memory.tab.history": "历史",
254
+ "memory.tab.summary": "小结",
236
255
  "memory.settings.title": "记忆库设置",
256
+ "memory.settings.group.personal": "个性化",
257
+ "memory.settings.group.engine": "记忆引擎",
258
+ "memory.settings.group.search": "搜索",
259
+ "memory.settings.group.connect": "连接与安全",
260
+ "memory.settings.group.help": "帮助",
237
261
  "memory.settings.profile": "用户画像",
238
262
  "memory.settings.profileHint": "写一段自我介绍(角色、背景、偏好),Agent 每轮对话都会自动带上。",
239
263
  "memory.settings.profileSave": "保存画像",
@@ -338,22 +362,25 @@ window.__ModuleLoader__.load({
338
362
  "memory.settings.apiTokenPlaceholder": "留空 = 不鉴权(默认)",
339
363
  "memory.settings.apiTokenSave": "保存 Token",
340
364
  "memory.settings.apiTokenSaved": "Token 已保存",
341
- "memory.settings.feedback.title": "帮助与反馈",
342
- "memory.settings.feedback.desc": "遇到问题?先看看仓库已有的 issue,或直接把情况反馈过来:",
343
- "memory.settings.feedback.newIssue": "GitHub 新建 issue(自动带上环境信息)",
344
- "memory.settings.feedback.email": "邮件反馈(work@modusensus.space)",
345
- "memory.settings.feedback.browse": "浏览仓库已知问题",
365
+ "memory.settings.feedback.title": "意见与反馈",
366
+ "memory.settings.feedback.desc": "遇到问题?直接告诉我们,或先看看有没有人遇到过:",
367
+ "memory.settings.feedback.newIssue": "在 GitHub 上反馈问题",
368
+ "memory.settings.feedback.newIssue.sub": "自动带上插件版本与环境信息",
369
+ "memory.settings.feedback.email": "邮件反馈",
370
+ "memory.settings.feedback.email.sub": "work@modusensus.space",
371
+ "memory.settings.feedback.browse": "浏览已知问题",
372
+ "memory.settings.feedback.browse.sub": "先搜搜,省一份重复 issue",
346
373
  "memory.settings.feedback.hint": "反馈前先搜搜是否已有相同问题,能省一份重复的 issue~",
347
374
  "memory.settings.version.outdated": "🆕 有新版本 {v}(当前运行 {c})",
348
375
  "memory.settings.version.outdatedHint": "若安装时指定过版本号,常规升级不会跨大/小版本(pnpm 钉子)——请重新安装或在升级命令加 --latest;npm 已发布而市场暂未收录属正常(约 1 天延迟)。",
349
376
  "memory.settings.mode.title": "运行模式",
350
- "memory.settings.mode.desc": "轻量模式只保留核心的记忆读写与自动注入(关闭 autoDream 巩固、实体抽取、语义搜索等高级功能),适合只想「记住偏好」的轻量使用;标准模式开启全部功能。",
377
+ "memory.settings.mode.desc": "轻量模式只保留核心能力:记忆读写、自动注入、热记忆;巩固、实体抽取、语义搜索等全部关闭,适合低配机器或只想「记住偏好」的场景。标准模式开启全部功能。",
351
378
  "memory.settings.mode.light": "轻量",
352
379
  "memory.settings.mode.standard": "标准",
353
380
  "memory.settings.mode.savedHint": "已保存,重启 DSH 后生效",
354
381
  "memory.settings.mode.offList": "已关闭:巩固(autoDream)· 实体抽取 · 语义搜索",
355
382
  "memory.settings.extapi.title": "外部访问 API",
356
- "memory.settings.extapi.desc": "独立 HTTP 服务,供其他插件 / CLI / 桌面工具读写记忆,默认绑定 127.0.0.1。重启 DSH 后生效。",
383
+ "memory.settings.extapi.desc": "开放一个本机接口,让其他工具(插件、命令行、桌面应用)也能读写这份记忆库,默认只允许本机连接。改动保存后重启 DSH 生效。",
357
384
  "memory.settings.extapi.enabled": "启用",
358
385
  "memory.settings.extapi.disabled": "停用",
359
386
  "memory.settings.extapi.address": "地址",
@@ -368,11 +395,11 @@ window.__ModuleLoader__.load({
368
395
  "memory.tab.constraint": "工程约束",
369
396
  "memory.tab.document": "文档",
370
397
  "memory.features.title": "功能开关",
371
- "memory.features.desc": "按需启停后端能力,改动保存后重启 DSH 生效。",
372
- "memory.features.group.core": "核心",
373
- "memory.features.group.enhance": "记忆增强",
398
+ "memory.features.desc": "控制插件在后台做哪些事。改动即时保存,重启 DSH 后生效。",
399
+ "memory.features.group.core": "基础",
400
+ "memory.features.group.enhance": "检索与增强",
374
401
  "memory.features.group.dream": "巩固与睡眠",
375
- "memory.features.group.scope": "作用域隔离",
402
+ "memory.features.group.scope": "多会话隔离",
376
403
  "memory.features.group.advanced": "高级",
377
404
  "memory.features.advancedToggle": "高级(注入策略 · 反思 · 实验项)",
378
405
  "memory.features.restartHint": "重启 DSH 后生效",
@@ -380,9 +407,9 @@ window.__ModuleLoader__.load({
380
407
  "memory.features.autoInject": "自动注入",
381
408
  "memory.features.autoInject.hint": "每轮对话自动携带相关记忆",
382
409
  "memory.features.injectGuidanceEnabled": "能力说明",
383
- "memory.features.injectGuidanceEnabled.hint": "在工具描述与一次性提示段里说明怎么用记忆(何时查、何时写、拿不准就不做)",
410
+ "memory.features.injectGuidanceEnabled.hint": "教 Agent 怎么用记忆:什么时候该查、什么时候该写、拿不准就不动",
384
411
  "memory.features.continuityRescueEnabled": "压缩边缘抢救",
385
- "memory.features.continuityRescueEnabled.hint": "上下文即将被精简前,落一条连续性快照(正在做什么 / 下一步 / 未决问题)并追加到对话末尾,让它活过这次压缩",
412
+ "memory.features.continuityRescueEnabled.hint": "长对话被压缩前,先存一份「正在做什么 / 下一步 / 未决问题」的快照,让关键上下文活过压缩",
386
413
  "memory.features.parentOff": "父开关关闭时不生效",
387
414
  "memory.features.autoSummarize": "自动总结",
388
415
  "memory.features.autoSummarize.hint": "对话结束自动提炼记忆条目",
@@ -403,18 +430,18 @@ window.__ModuleLoader__.load({
403
430
  "memory.features.summarizeReasoningEffort.low": "低",
404
431
  "memory.features.summarizeReasoningEffort.medium": "中",
405
432
  "memory.features.summarizeReasoningEffort.high": "高",
406
- "memory.features.summarizeReasoningEffort.hint": "思考型模型建议选低档或关闭思考,避免推理烧光输出预算导致总结失败;改后重启 DSH 生效",
407
- "memory.features.entityExtractionModelHint": "Provider/模型留空 = 跟随主对话模型;思考强度 none = 服务商默认",
433
+ "memory.features.summarizeReasoningEffort.hint": "思考型模型建议选「低」或「关闭思考」,避免推理占满输出导致总结失败",
434
+ "memory.features.entityExtractionModelHint": "Provider / 模型留空 = 跟随主对话模型;思考强度选「跟随默认」= 服务商默认",
408
435
  "memory.features.codingRetrospect": "编码记忆蒸馏",
409
- "memory.features.codingRetrospect.hint": "用完整转录(含工具调用与报错)提炼踩坑、约束与被否决方案",
436
+ "memory.features.codingRetrospect.hint": "回顾写代码的完整过程(含报错与工具调用),沉淀踩坑、约束和被否决的方案",
410
437
  "memory.features.rerankEnabled": "结果重排",
411
438
  "memory.features.rerankEnabled.hint": "本地重排模型对召回结果精排,更慢更准",
412
439
  "memory.features.heatEnabled": "热度衰减",
413
- "memory.features.heatEnabled.hint": "按遗忘曲线给记忆降温:久未访问热度越低,参与注入排序与睡眠降级判定",
440
+ "memory.features.heatEnabled.hint": "像遗忘曲线一样给记忆降温:越久没用到排得越靠后,不占注入名额",
414
441
  "memory.features.documentMemoryEnabled": "document 型记忆",
415
- "memory.features.documentMemoryEnabled.hint": "agent 产长文档入库为指针行:注册校验(文件存在 + evidence 求交)、摘要 + 路径落库、去重与 supersede 记账;全文归 agent 按需读,注入只带摘要行(默认关)",
442
+ "memory.features.documentMemoryEnabled.hint": "Agent 写的长文档只在记忆里放一张「摘要卡」:正文仍由 Agent 保管、按需读取,注入时只带摘要,不占上下文",
416
443
  "memory.features.resilientModelDownload": "模型下载断点续传",
417
- "memory.features.resilientModelDownload.hint": "模型文件下载中断后从已下载部分续传并自动重试,失败会记录中断位置;关闭后回到一次性下载",
444
+ "memory.features.resilientModelDownload.hint": "模型下载中断后从断点续传并自动重试;关闭则回到一次性下载",
418
445
  "memory.features.searchSemanticDedup": "语义去重",
419
446
  "memory.features.searchSemanticDedup.hint": "搜索结果中意思相近的条目只保留一条",
420
447
  "memory.features.autoDream": "记忆巩固",
@@ -444,13 +471,13 @@ window.__ModuleLoader__.load({
444
471
  "memory.features.conflictFreezeEnabled": "冲突冻结",
445
472
  "memory.features.conflictFreezeEnabled.hint": "巩固发现互相矛盾的记忆时先冻结待确认",
446
473
  "memory.features.scopeEnabled": "作用域标注",
447
- "memory.features.scopeEnabled.hint": "按会话身份(agent/工作区)给新记忆打归属标注;重启 DSH 后生效",
474
+ "memory.features.scopeEnabled.hint": "新记忆自动记下来自哪个会话(Agent / 工作区),供隔离与检索过滤使用",
448
475
  "memory.features.strictScope": "严格隔离",
449
- "memory.features.strictScope.hint": "检索与注入硬过滤,只对显式声明的归属生效:显式收窄到他者作用域的记忆不可见;载体自动标注只降权保留可见(真正的物理隔离请用 sensitivity)。重启 DSH 后生效",
476
+ "memory.features.strictScope.hint": "开启后,其他会话明确设为私有的记忆对你完全不可见;关闭时仍可见、只是排到后面。要做到彻底隔离,请用条目的「敏感度」字段",
450
477
  "memory.features.trustEpistemicWeighting": "可信度加权",
451
478
  "memory.features.trustEpistemicWeighting.hint": "按来源可信度调整召回排序(实验性)",
452
479
  "memory.features.reflectionFailureTracking": "反思失败追踪",
453
- "memory.features.reflectionFailureTracking.hint": "记录巩固决策的失败样本供后续改进",
480
+ "memory.features.reflectionFailureTracking.hint": "记录巩固失败的案例供后续改进(诊断用)",
454
481
  "memory.features.embedRoute": "语义检索路线",
455
482
  "memory.features.embedProvider": "Embedding 提供方",
456
483
  "memory.features.embedProvider.openai": "OpenAI 兼容接口",
@@ -466,9 +493,9 @@ window.__ModuleLoader__.load({
466
493
  "memory.features.dreamModel": "巩固用模型名",
467
494
  "memory.features.dreamModelHint": "留空 = 跟随主对话模型;只影响记忆巩固(autoDream)用的模型",
468
495
  "memory.features.dreamPeakHours": "高峰时段(不做梦)",
469
- "memory.features.dreamPeakHours.hint": "空 = 关闭。逗号分隔、可带星期前缀、支持跨零点,如 09:00-18:00 或 mon-fri 08:00-12:00,14:00-18:00。命中时段不调模型,顺延到最近的高峰结束时刻补跑(最多顺延 dreamPeakMaxDeferMinutes 分钟,避免长高峰把巩固饿死)",
496
+ "memory.features.dreamPeakHours.hint": "设置忙碌时段,巩固会避开这些时间、事后补跑。写法:09:00-18:00,多段用逗号分隔,可带星期(如 mon-fri 08:00-12:00),支持跨零点;留空 = 不限制",
470
497
  "memory.features.summarizePeakHours": "高峰时段(不蒸馏)",
471
- "memory.features.summarizePeakHours.hint": "空 = 关闭。与上方巩固侧同一份时段语法;命中时蒸馏顺延到非高峰、窗口累积后一次蒸",
498
+ "memory.features.summarizePeakHours.hint": "与巩固侧同一份写法;蒸馏会避开这些时段,窗口先攒着、非高峰一次蒸完",
472
499
  "memory.features.sleepProvider": "睡眠 Provider",
473
500
  "memory.features.sleepModel": "睡眠模型",
474
501
  "memory.features.sleepModelHint": "留空 = 用巩固模型或当前模型;建议选非思考模型",
@@ -479,7 +506,7 @@ window.__ModuleLoader__.load({
479
506
  "memory.features.modelTestFail": "测试失败",
480
507
  "memory.features.modelTestHint": "真实发起一次最小巩固调用,验证 Provider/模型连通与 effort 支持",
481
508
  "memory.features.routeStaleMark": "(不在可用列表)",
482
- "memory.features.routeStaleHint": "不在当前可用列表,多为切换 Provider 后的旧值:请改选,或点「测试连通性」当场验证;改动保存后重启 DSH 生效。",
509
+ "memory.features.routeStaleHint": "该值不在当前可用列表(常见于切换过 Provider):请重新选择,或点「测试连通性」当场验证",
483
510
  "memory.explorer.viewCards": "卡片",
484
511
  "memory.explorer.viewTimeline": "时间线",
485
512
  "memory.explorer.viewAria": "视图切换",
@@ -532,16 +559,20 @@ window.__ModuleLoader__.load({
532
559
  "memory.explorer.detail.editTitle": "标题",
533
560
  "memory.explorer.detail.editContent": "内容",
534
561
  "memory.explorer.detail.editImportance": "重要性",
562
+ "memory.explorer.detail.starLabel": "设为 {n} 星",
535
563
  "memory.status.dream": "最近巩固",
536
564
  "memory.status.dreamNever": "尚未运行",
537
565
  "memory.status.conflicts": "待确认冲突",
538
566
  "memory.status.conflictsHint": "冻结的矛盾记忆,等待人工确认",
539
567
  "memory.status.injectSuppressed": "极简模式下注入按宿主设计关闭",
540
- "memory.status.injectSuppressedHint": "当前会话使用 minimal 预设,记忆注入 / 用户画像 / hot memory 不送达模型(宿主设计,非插件缺陷)。解法:切换标准模式,或在 ~/.dsh/settings.yaml 设 agent-presets.default: standard;过渡方案:把画像与规则写入 AGENTS.md",
568
+ "memory.status.injectSuppressedHint": "当前会话使用 minimal 预设:记忆注入 / 用户画像 / 热记忆不会送达模型(宿主设计,非插件缺陷)。切到标准模式,或在 ~/.dsh/settings.yaml 设 agent-presets.default: standard;过渡方案:把画像与规则写进 AGENTS.md",
541
569
  "memory.status.injectPreview": "注入预览",
542
570
  "memory.status.injectPreviewNone": "暂无预览——尚未发生注入(新会话或注入已关闭)",
543
- "memory.status.injectPreview.chars": "总体积 {chars} 字符",
571
+ "memory.status.injectPreview.chars": "总体积",
544
572
  "memory.status.injectPreview.charsUnit": " 字符",
573
+ "memory.status.injectPreview.maxItems": "注入上限",
574
+ "memory.status.injectPreview.threshold": "相关性门槛",
575
+ "memory.status.injectPreview.scope": "会话归属",
545
576
  "memory.status.injectPreview.query": "查询「{query}…」",
546
577
  "memory.status.injectPreview.hot": "hot memory",
547
578
  "memory.status.injectPreview.adaptiveOn": "自适应条数",
@@ -580,11 +611,19 @@ window.__ModuleLoader__.load({
580
611
  "memory.status.consolidatedEmpty": "autoDream / autoSummarize 沉淀的记忆会出现在这里",
581
612
  "memory.status.archivedMemories": "已归档的记忆",
582
613
  "memory.status.heatDistribution": "热度分布",
583
- "memory.status.heatHint": "热门(≥66%){hot} · 温热(33–66%){warm} · 冷却(<33%){cold},样本为最近 {sample} 条",
614
+ "memory.status.heat.hot": "热门(≥66%)",
615
+ "memory.status.heat.warm": "温热(33–66%)",
616
+ "memory.status.heat.cold": "冷却(<33%)",
617
+ "memory.status.heat.sample": "按最近 {sample} 条采样",
584
618
  "memory.status.recallStats": "记忆复用",
585
- "memory.status.recallHint": "复用率 {rate} · 僵尸 {zombie}/{active}(豁免 {exempt})· 30 天回执 {runs} 次 · Top:{top}",
586
- "memory.status.recallInject": "注入 {runs} 轮 {count} 条,槽位填充 {fill}%",
587
- "memory.status.recallArchive": "归档 {total} 行({add}/天),精确重复可压掉 {compress} 行",
619
+ "memory.status.recall.zombie": "僵尸记忆",
620
+ "memory.status.recall.exempt": "豁免",
621
+ "memory.status.recall.runs": "30 天回执",
622
+ "memory.status.recall.top": "常被召回",
623
+ "memory.status.recall.inject": "注入",
624
+ "memory.status.recall.archive": "归档",
625
+ "memory.status.recallInject": "{runs} 轮 · {count} 条 · 槽位 {fill}%",
626
+ "memory.status.recallArchive": "{total} 行 · +{add}/天 · 可压掉 {compress}",
588
627
  "memory.status.viewAll": "查看全部",
589
628
  "memory.status.depositedCount": "沉淀的记忆({n})",
590
629
  "memory.status.archivedCount": "已归档的记忆({n})",
@@ -606,7 +645,7 @@ window.__ModuleLoader__.load({
606
645
  "memory.status.vectorInitHint": "embedder 不可达,正在重试",
607
646
  "memory.status.vectorRuntimeMissing": "缺少本地推理运行时",
608
647
  "memory.status.vectorRuntimeHint": "本地推理运行时未就绪({status})",
609
- "memory.status.vectorRuntimeCost": "本地向量化要额外一份本地推理运行时(transformers + onnxruntime 闭包,解包后数百 MB)。下面的按钮会先尝试收编本机已有的那份(同盘则硬链接,不占额外空间),没有再按固定清单从 npm 取回(逐个校验 sha512)。也可以直接让 agent 处理,或在终端里自己跑:node scripts/mneme-runtime.mjs status / adopt [--from <node_modules>] / verify(详见 docs/LOCAL_MODEL.md §2.5)。",
648
+ "memory.status.vectorRuntimeCost": "本地向量化需要额外一份本地推理运行时(解包后数百 MB)。下面的按钮会优先收编本机已有的那份(同盘硬链接、不占额外空间),没有再从 npm 下载并逐个校验。也可以让 Agent 代劳,或在终端自己跑:node scripts/mneme-runtime.mjs status / adopt / verify(见 docs/LOCAL_MODEL.md)",
610
649
  "memory.runtime.title": "本地推理运行时",
611
650
  "memory.runtime.available": "已就绪",
612
651
  "memory.runtime.missing": "未就绪 —— 只有用本地嵌入(embedProvider: local)时才需要它",
@@ -622,6 +661,8 @@ window.__ModuleLoader__.load({
622
661
  "memory.status.vectorUnconfigured": "未配置",
623
662
  "memory.status.vectorUnconfiguredHint": "未填 embedding 端点/模型或未启用,语义召回不可用",
624
663
  "memory.status.vectorDegradedHint": "已索引 0 / {m} 条,语义召回实际不可用",
664
+ "memory.status.sec.overview": "库内一览",
665
+ "memory.status.sec.engine": "后台运转",
625
666
  "memory.status.llm": "LLM 消耗",
626
667
  "memory.status.llmCalls": "近 7 天 · {n} 次调用",
627
668
  "memory.status.error": "加载失败"
@@ -634,7 +675,13 @@ window.__ModuleLoader__.load({
634
675
  "memory.tab.project": "Projects",
635
676
  "memory.tab.decision": "Decisions",
636
677
  "memory.tab.history": "History",
678
+ "memory.tab.summary": "Summaries",
637
679
  "memory.settings.title": "Memory Settings",
680
+ "memory.settings.group.personal": "Personalization",
681
+ "memory.settings.group.engine": "Memory engine",
682
+ "memory.settings.group.search": "Search",
683
+ "memory.settings.group.connect": "Connections & safety",
684
+ "memory.settings.group.help": "Help",
638
685
  "memory.settings.profile": "User Profile",
639
686
  "memory.settings.profileHint": "Describe yourself once — the agent reads it every turn.",
640
687
  "memory.settings.profileSave": "Save Profile",
@@ -739,22 +786,25 @@ window.__ModuleLoader__.load({
739
786
  "memory.settings.apiTokenPlaceholder": "Empty = no auth (default)",
740
787
  "memory.settings.apiTokenSave": "Save Token",
741
788
  "memory.settings.apiTokenSaved": "Token saved",
742
- "memory.settings.feedback.title": "Help & feedback",
743
- "memory.settings.feedback.desc": "Stuck? Search the existing issues, or tell us what happened:",
744
- "memory.settings.feedback.newIssue": "Open a GitHub issue (environment info prefilled)",
745
- "memory.settings.feedback.email": "Email feedback (work@modusensus.space)",
789
+ "memory.settings.feedback.title": "Feedback",
790
+ "memory.settings.feedback.desc": "Something off? Tell us directly, or check if someone hit it first:",
791
+ "memory.settings.feedback.newIssue": "Report on GitHub",
792
+ "memory.settings.feedback.newIssue.sub": "Plugin version & environment prefilled",
793
+ "memory.settings.feedback.email": "Email us",
794
+ "memory.settings.feedback.email.sub": "work@modusensus.space",
746
795
  "memory.settings.feedback.browse": "Browse known issues",
796
+ "memory.settings.feedback.browse.sub": "Check if it's already reported",
747
797
  "memory.settings.feedback.hint": "Search for an existing issue first — it saves a duplicate.",
748
798
  "memory.settings.version.outdated": "🆕 New version {v} available (running {c})",
749
799
  "memory.settings.version.outdatedHint": "If the plugin was installed with a pinned version, regular upgrades never cross minor/major lines — reinstall or pass --latest. A fresh npm release may take about a day to appear in the market.",
750
800
  "memory.settings.mode.title": "Runtime mode",
751
- "memory.settings.mode.desc": "Light mode keeps only the core memory read/write and auto-injection (autoDream consolidation, entity extraction and semantic search are off) — for light use where you just want preferences remembered. Standard mode enables everything.",
801
+ "memory.settings.mode.desc": "Light mode keeps the core loop only: memory read/write, auto-injection and hot memory — consolidation, entity extraction and semantic search are all off. For modest machines or when you just want preferences remembered. Standard mode enables everything.",
752
802
  "memory.settings.mode.light": "Light",
753
803
  "memory.settings.mode.standard": "Standard",
754
804
  "memory.settings.mode.savedHint": "Saved. Takes effect after restarting DSH",
755
805
  "memory.settings.mode.offList": "Off: consolidation (autoDream) · entity extraction · semantic search",
756
806
  "memory.settings.extapi.title": "External API",
757
- "memory.settings.extapi.desc": "A standalone HTTP service for other plugins / CLIs / desktop tools to read and write memories, bound to 127.0.0.1 by default. Takes effect after restarting DSH.",
807
+ "memory.settings.extapi.desc": "Opens a local API so other tools (plugins, CLIs, desktop apps) can also read and write this memory store; binds to localhost only by default. Changes take effect after restarting DSH.",
758
808
  "memory.settings.extapi.enabled": "Enable",
759
809
  "memory.settings.extapi.disabled": "Disable",
760
810
  "memory.settings.extapi.address": "Address",
@@ -769,11 +819,11 @@ window.__ModuleLoader__.load({
769
819
  "memory.tab.constraint": "Constraints",
770
820
  "memory.tab.document": "Documents",
771
821
  "memory.features.title": "Features",
772
- "memory.features.desc": "Toggle backend capabilities. Changes take effect after restarting DSH.",
773
- "memory.features.group.core": "Core",
774
- "memory.features.group.enhance": "Enhancement",
775
- "memory.features.group.dream": "Consolidation",
776
- "memory.features.group.scope": "Scope isolation",
822
+ "memory.features.desc": "Choose what the plugin does in the background. Changes are saved immediately and take effect after restarting DSH.",
823
+ "memory.features.group.core": "Basics",
824
+ "memory.features.group.enhance": "Search & enrichment",
825
+ "memory.features.group.dream": "Consolidation & sleep",
826
+ "memory.features.group.scope": "Multi-session isolation",
777
827
  "memory.features.group.advanced": "Advanced",
778
828
  "memory.features.advancedToggle": "Advanced (injection · reflection · experimental)",
779
829
  "memory.features.restartHint": "Takes effect after restarting DSH",
@@ -781,9 +831,9 @@ window.__ModuleLoader__.load({
781
831
  "memory.features.autoInject": "Auto injection",
782
832
  "memory.features.autoInject.hint": "Carry relevant memories into every turn",
783
833
  "memory.features.injectGuidanceEnabled": "Capability guide",
784
- "memory.features.injectGuidanceEnabled.hint": "Explain how to use memory (when to search, when to save, when to do nothing) in tool descriptions plus a one-time prompt section",
834
+ "memory.features.injectGuidanceEnabled.hint": "Teach the agent how to use memory: when to search, when to save, when to leave things alone",
785
835
  "memory.features.continuityRescueEnabled": "Compaction-edge rescue",
786
- "memory.features.continuityRescueEnabled.hint": "Before context compaction, record a continuity snapshot (current work / next step / open questions) and append it near the end of the conversation so it survives the compaction",
836
+ "memory.features.continuityRescueEnabled.hint": "Before a long conversation gets compacted, store a snapshot of what's in progress / next steps / open questions so key context survives the compaction",
787
837
  "memory.features.parentOff": "Inactive while auto injection is off",
788
838
  "memory.features.autoSummarize": "Auto summarization",
789
839
  "memory.features.autoSummarize.hint": "Distill memory entries when a conversation ends",
@@ -804,18 +854,18 @@ window.__ModuleLoader__.load({
804
854
  "memory.features.summarizeReasoningEffort.low": "Low",
805
855
  "memory.features.summarizeReasoningEffort.medium": "Medium",
806
856
  "memory.features.summarizeReasoningEffort.high": "High",
807
- "memory.features.summarizeReasoningEffort.hint": "Prefer low or No reasoning for thinking models so reasoning cannot drain the output budget; takes effect after a DSH restart",
808
- "memory.features.entityExtractionModelHint": "Provider / model empty = follow the main conversation model; reasoning none = provider default",
857
+ "memory.features.summarizeReasoningEffort.hint": "For thinking models, prefer Low or No reasoning so thinking cannot fill the output budget and break summaries",
858
+ "memory.features.entityExtractionModelHint": "Provider / model empty = follow the main conversation model; reasoning \"Follow default\" = provider default",
809
859
  "memory.features.codingRetrospect": "Coding retrospection",
810
- "memory.features.codingRetrospect.hint": "Distill pitfalls, constraints and rejected solutions from full transcripts (tools and errors included)",
860
+ "memory.features.codingRetrospect.hint": "Review the full coding session (tools and errors included) and distill pitfalls, constraints and rejected solutions",
811
861
  "memory.features.rerankEnabled": "Reranking",
812
862
  "memory.features.rerankEnabled.hint": "Rerank recalled results with a local model — slower, more precise",
813
863
  "memory.features.heatEnabled": "Heat decay",
814
- "memory.features.heatEnabled.hint": "Decay memory heat since last access; feeds injection ranking and sleep demotion",
864
+ "memory.features.heatEnabled.hint": "Cool memories down like a forgetting curve: the longer unused, the lower they rank — they stop taking injection slots",
815
865
  "memory.features.documentMemoryEnabled": "Document memory",
816
- "memory.features.documentMemoryEnabled.hint": "Register agent-authored documents as pointer rows: existence + evidence validation, summary + path stored, dedupe + supersede bookkeeping; the full text stays agent-owned and is read on demand; injection carries the summary row only (off by default)",
866
+ "memory.features.documentMemoryEnabled.hint": "Long agent-authored documents are stored as a \"summary card\" only: the full text stays agent-owned and is read on demand, so injection carries the summary without filling the context",
817
867
  "memory.features.resilientModelDownload": "Resumable model downloads",
818
- "memory.features.resilientModelDownload.hint": "Resume model file downloads from received bytes and retry on failure; failures log where they stopped",
868
+ "memory.features.resilientModelDownload.hint": "Resume model downloads from where they stopped and retry automatically; off = one-shot downloads",
819
869
  "memory.features.searchSemanticDedup": "Semantic dedup",
820
870
  "memory.features.searchSemanticDedup.hint": "Keep one entry when search hits near-duplicates",
821
871
  "memory.features.autoDream": "Memory consolidation",
@@ -845,13 +895,13 @@ window.__ModuleLoader__.load({
845
895
  "memory.features.conflictFreezeEnabled": "Conflict freezing",
846
896
  "memory.features.conflictFreezeEnabled.hint": "Freeze contradictory memories for confirmation during consolidation",
847
897
  "memory.features.scopeEnabled": "Scope tagging",
848
- "memory.features.scopeEnabled.hint": "Stamp new memories with the writing session's identity (agent/workspace); takes effect after restarting DSH",
898
+ "memory.features.scopeEnabled.hint": "New memories record which session (agent / workspace) they came from, for isolation and filtered recall",
849
899
  "memory.features.strictScope": "Strict isolation",
850
- "memory.features.strictScope.hint": "Hard-filter search and injection for EXPLICITLY declared scopes only: memories explicitly narrowed to other agents/workspaces become invisible; auto carrier labels are demoted but stay visible (use sensitivity for true physical isolation). Takes effect after restarting DSH",
900
+ "memory.features.strictScope.hint": "When on, memories explicitly made private by other sessions become fully invisible; when off they stay visible but rank lower. For true isolation use a memory's sensitivity field",
851
901
  "memory.features.trustEpistemicWeighting": "Credibility weighting",
852
902
  "memory.features.trustEpistemicWeighting.hint": "Adjust recall ranking by source credibility (experimental)",
853
903
  "memory.features.reflectionFailureTracking": "Reflection failure tracking",
854
- "memory.features.reflectionFailureTracking.hint": "Record failed consolidation decisions for later improvement",
904
+ "memory.features.reflectionFailureTracking.hint": "Record failed consolidation cases for later improvement (diagnostics)",
855
905
  "memory.features.embedRoute": "Semantic search route",
856
906
  "memory.features.embedProvider": "Embedding provider",
857
907
  "memory.features.embedProvider.openai": "OpenAI-compatible API",
@@ -867,9 +917,9 @@ window.__ModuleLoader__.load({
867
917
  "memory.features.dreamModel": "Consolidation model",
868
918
  "memory.features.dreamModelHint": "Leave empty to follow the main conversation model; only affects autoDream consolidation",
869
919
  "memory.features.dreamPeakHours": "Peak hours (no dreaming)",
870
- "memory.features.dreamPeakHours.hint": "Empty = off. Comma-separated windows, optional weekday prefix, midnight-crossing allowed — e.g. 09:00-18:00 or mon-fri 08:00-12:00,14:00-18:00. Inside these windows no LLM call is made; the run is deferred to the nearest peak-end (capped by dreamPeakMaxDeferMinutes so an all-day peak cannot starve consolidation)",
920
+ "memory.features.dreamPeakHours.hint": "Busy hours for the machine; consolidation avoids them and catches up afterwards. Syntax: 09:00-18:00, several windows comma-separated, weekday prefix allowed (mon-fri 08:00-12:00), midnight-crossing allowed; empty = no limit",
871
921
  "memory.features.summarizePeakHours": "Peak hours (no distillation)",
872
- "memory.features.summarizePeakHours.hint": "Empty = off. Same window syntax as the consolidation side above; inside a peak, distillation is deferred and the window accumulates for one bigger run",
922
+ "memory.features.summarizePeakHours.hint": "Same syntax as the consolidation side above; distillation avoids these windows and accumulates the material for one run off-peak",
873
923
  "memory.features.sleepProvider": "Sleep provider",
874
924
  "memory.features.sleepModel": "Sleep model",
875
925
  "memory.features.sleepModelHint": "Leave empty to reuse the consolidation model; a non-reasoning model is recommended",
@@ -880,7 +930,7 @@ window.__ModuleLoader__.load({
880
930
  "memory.features.modelTestFail": "Test failed",
881
931
  "memory.features.modelTestHint": "Fires one minimal consolidation call to verify provider/model connectivity and effort support",
882
932
  "memory.features.routeStaleMark": " (not in list)",
883
- "memory.features.routeStaleHint": "Not in the currently available list, often a leftover from a provider switch: reselect, or run a connectivity test to verify now; changes take effect after restarting DSH.",
933
+ "memory.features.routeStaleHint": "This value is not in the currently available list (often a leftover from switching providers): reselect, or run a connectivity test to verify now",
884
934
  "memory.explorer.viewCards": "Cards",
885
935
  "memory.explorer.viewTimeline": "Timeline",
886
936
  "memory.explorer.viewAria": "Switch view",
@@ -933,16 +983,20 @@ window.__ModuleLoader__.load({
933
983
  "memory.explorer.detail.editTitle": "Title",
934
984
  "memory.explorer.detail.editContent": "Content",
935
985
  "memory.explorer.detail.editImportance": "Importance",
986
+ "memory.explorer.detail.starLabel": "Set importance to {n} stars",
936
987
  "memory.status.dream": "Last consolidation",
937
988
  "memory.status.dreamNever": "Not yet run",
938
989
  "memory.status.conflicts": "Pending conflicts",
939
990
  "memory.status.conflictsHint": "Frozen contradictory memories awaiting confirmation",
940
991
  "memory.status.injectSuppressed": "Injection disabled by host minimal preset",
941
- "memory.status.injectSuppressedHint": "This session uses the minimal preset: memory injection / user profile / hot memory never reach the model (by host design, not a plugin defect). Fix: switch to standard mode, or set agent-presets.default: standard in ~/.dsh/settings.yaml. Interim: put profile and rules in AGENTS.md",
992
+ "memory.status.injectSuppressedHint": "This session uses the minimal preset: memory injection / profile / hot memory never reach the model (by host design, not a plugin defect). Switch to standard mode, or set agent-presets.default: standard in ~/.dsh/settings.yaml. Interim: put profile and rules in AGENTS.md",
942
993
  "memory.status.injectPreview": "Injection preview",
943
994
  "memory.status.injectPreviewNone": "No preview yet — no injection has happened (new session or injection off)",
944
- "memory.status.injectPreview.chars": "total {chars} chars",
995
+ "memory.status.injectPreview.chars": "Total",
945
996
  "memory.status.injectPreview.charsUnit": " chars",
997
+ "memory.status.injectPreview.maxItems": "Max items",
998
+ "memory.status.injectPreview.threshold": "Relevance floor",
999
+ "memory.status.injectPreview.scope": "Session scope",
946
1000
  "memory.status.injectPreview.query": "query \"{query}…\"",
947
1001
  "memory.status.injectPreview.hot": "hot memory",
948
1002
  "memory.status.injectPreview.adaptiveOn": "adaptive budget",
@@ -981,11 +1035,19 @@ window.__ModuleLoader__.load({
981
1035
  "memory.status.consolidatedEmpty": "Memories deposited by autoDream / autoSummarize appear here",
982
1036
  "memory.status.archivedMemories": "Archived memories",
983
1037
  "memory.status.heatDistribution": "Heat distribution",
984
- "memory.status.heatHint": "hot (≥66%) {hot} · warm (33–66%) {warm} · cooled (<33%) {cold}, sampled from the latest {sample}",
1038
+ "memory.status.heat.hot": "Hot (≥66%)",
1039
+ "memory.status.heat.warm": "Warm (33–66%)",
1040
+ "memory.status.heat.cold": "Cooled (<33%)",
1041
+ "memory.status.heat.sample": "Sampled from the latest {sample}",
985
1042
  "memory.status.recallStats": "Recall reuse",
986
- "memory.status.recallHint": "reuse {rate} · zombie {zombie}/{active} (exempt {exempt}) · {runs} runs in 30d · top: {top}",
987
- "memory.status.recallInject": "injected {runs} turns · {count} items ({fill}% slots)",
988
- "memory.status.recallArchive": "archived {total} rows (+{add}/day) · {compress} exactly-duplicate rows compressible",
1043
+ "memory.status.recall.zombie": "Zombie memories",
1044
+ "memory.status.recall.exempt": "exempt",
1045
+ "memory.status.recall.runs": "Receipts (30d)",
1046
+ "memory.status.recall.top": "Most recalled",
1047
+ "memory.status.recall.inject": "Injected",
1048
+ "memory.status.recall.archive": "Archived",
1049
+ "memory.status.recallInject": "{runs} turns · {count} items · {fill}% slots",
1050
+ "memory.status.recallArchive": "{total} rows · +{add}/day · {compress} compressible",
989
1051
  "memory.status.viewAll": "View all",
990
1052
  "memory.status.depositedCount": "Deposited memories ({n})",
991
1053
  "memory.status.archivedCount": "Archived memories ({n})",
@@ -1007,7 +1069,7 @@ window.__ModuleLoader__.load({
1007
1069
  "memory.status.vectorInitHint": "embedder unreachable, retrying",
1008
1070
  "memory.status.vectorRuntimeMissing": "Local inference runtime missing",
1009
1071
  "memory.status.vectorRuntimeHint": "Local inference runtime not ready ({status})",
1010
- "memory.status.vectorRuntimeCost": "Local vectorization needs an extra local inference runtime (the transformers + onnxruntime closure, hundreds of MB unpacked). The button below first tries to adopt an existing copy on this machine (hardlinked when on the same volume, so no extra disk), and otherwise fetches it from npm against a pinned manifest (every tarball checked against its sha512). You can also just ask the agent, or run it yourself: node scripts/mneme-runtime.mjs status / adopt [--from <node_modules>] / verify (see docs/LOCAL_MODEL.md §2.5).",
1072
+ "memory.status.vectorRuntimeCost": "Local vectorization needs an extra local inference runtime (hundreds of MB unpacked). The button below first adopts an existing copy on this machine (hardlinked on the same volume, no extra disk) and otherwise fetches it from npm with per-file checksums. You can also just ask the agent, or run it yourself: node scripts/mneme-runtime.mjs status / adopt / verify (see docs/LOCAL_MODEL.md)",
1011
1073
  "memory.runtime.title": "Local inference runtime",
1012
1074
  "memory.runtime.available": "ready",
1013
1075
  "memory.runtime.missing": "not ready — only needed when you use local embedding (embedProvider: local)",
@@ -1023,6 +1085,8 @@ window.__ModuleLoader__.load({
1023
1085
  "memory.status.vectorUnconfigured": "Not configured",
1024
1086
  "memory.status.vectorUnconfiguredHint": "No embedding endpoint/model configured — semantic recall is off",
1025
1087
  "memory.status.vectorDegradedHint": "Indexed 0 / {m} items — semantic recall is effectively unavailable",
1088
+ "memory.status.sec.overview": "Library",
1089
+ "memory.status.sec.engine": "Background activity",
1026
1090
  "memory.status.llm": "LLM Usage",
1027
1091
  "memory.status.llmCalls": "Last 7 days · {n} calls",
1028
1092
  "memory.status.error": "Failed to load"
@@ -1202,8 +1266,8 @@ window.__ModuleLoader__.load({
1202
1266
  // --- settings: quiet stacked sections, one concern per section ---
1203
1267
  ".mneme-set{flex:1;min-height:0;overflow-y:auto;padding:8px 24px 48px;box-sizing:border-box}",
1204
1268
  ".mneme-set-inner{max-width:720px;margin:0 auto}",
1205
- ".mneme-set-sec{padding:20px 0 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}",
1206
- ".mneme-set-sec:last-child{border-bottom:none}",
1269
+ // 设置页各节一律用 boxed 卡(.mneme-set-card)+ 分组标题(.mneme-set-grouphead):
1270
+ // 旧的「无框 set-sec + 有框 set-card」混排是版面杂乱的一半来源
1207
1271
  ".mneme-set-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);margin-bottom:4px}",
1208
1272
  ".mneme-set-desc{font-size:13px;line-height:19px;color:var(--dsw-alias-label-tertiary);margin-bottom:14px}",
1209
1273
  ".mneme-set-input{box-sizing:border-box;width:100%;height:34px;padding:0 12px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary);font-family:inherit;font-size:13px;outline:none;margin-bottom:10px;transition:border-color .12s,box-shadow .12s}",
@@ -1271,7 +1335,6 @@ window.__ModuleLoader__.load({
1271
1335
  ".mneme-numinput:focus{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-business-primary) 15%,transparent)}",
1272
1336
  // 字符串开关的输入框(provider/model 等)与其子块容器
1273
1337
  ".mneme-strinput{box-sizing:border-box;width:240px;max-width:60%;height:30px;padding:0 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary);font-family:inherit;font-size:13px;outline:none;text-align:left;transition:border-color .12s,box-shadow .12s}",
1274
- ".mneme-feed-link{display:block;color:var(--dsw-alias-brand,var(--dsw-alias-label-primary));text-decoration:none;font-size:13px;line-height:20px;padding:4px 2px;border-radius:6px;transition:opacity .12s}.mneme-feed-link:hover{opacity:.8;text-decoration:underline}",
1275
1338
  ".mneme-strinput:focus{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-business-primary) 15%,transparent)}",
1276
1339
  ".mneme-featsub{margin:2px 0 8px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;display:flex;flex-direction:column;gap:6px}",
1277
1340
  ".mneme-featsub .mneme-featnum{padding:6px 0;border-bottom:none}",
@@ -1378,8 +1441,36 @@ window.__ModuleLoader__.load({
1378
1441
  ".mneme-xemptyico{display:block;margin:0 auto 6px;opacity:.7}",
1379
1442
  // --- status sub-view: responsive stat-card grid (auto-fill, ~220px min) ---
1380
1443
  ".mneme-status{flex:1;min-height:0;overflow-y:auto;padding:20px 24px 40px;box-sizing:border-box}",
1381
- ".mneme-statusgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;max-width:1000px;margin:0 auto}",
1382
- ".mneme-statuscard{min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:14px}",
1444
+ ".mneme-statusgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;max-width:1000px;margin:0 auto 12px}",
1445
+ ".mneme-statusgrid:last-of-type{margin-bottom:0}",
1446
+ // 概览区是单行三卡:auto-fit 让不满的轨道塌缩,三张卡恒等宽铺满、行尾不留洞
1447
+ ".mneme-statusgrid--overview{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}",
1448
+ // 跨列只在容器够放下 ≥2 列时生效(220px 最小轨 + 12px 间隙推出来的界);
1449
+ // 单列容器里 span 2 会撑出隐式轨道把布局撑爆,必须撤掉
1450
+ "@container (min-width:452px) and (max-width:683px){.mneme-statuscard--vectorwide{grid-column:span 2}}",
1451
+ "@container (min-width:452px){.mneme-statuscard--wide{grid-column:span 2}}",
1452
+ // 状态页分组标题(库内一览 / 后台运转):只做扫读锚点,压得比卡片标题低
1453
+ ".mneme-statushead{max-width:1000px;margin:0 auto 10px;font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-tertiary)}",
1454
+ ".mneme-statusgrid+.mneme-statushead{margin-top:26px}",
1455
+ ".mneme-statuscard{min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px 16px 14px}",
1456
+ // 指标行:一行一指标(label 左 / 数值右),取代「·」串联的说明长句——
1457
+ // 拥挤感的根源是把多指标压进一段会换行的散文
1458
+ ".mneme-statrows{margin-top:10px;display:flex;flex-direction:column;gap:4px}",
1459
+ ".mneme-statrow{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:12px;line-height:17px;color:var(--dsw-alias-label-tertiary)}",
1460
+ ".mneme-statrow>span:first-child{flex:none;white-space:nowrap}",
1461
+ ".mneme-statrow .mneme-heatdot{align-self:center}",
1462
+ ".mneme-statrowval{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-align:right}",
1463
+ ".mneme-statfoot{margin-top:8px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-dimmed)}",
1464
+ // 热度分布条:三档占比一图看清,行标只补数字(类名带双横线,与 heatdot 同款)
1465
+ ".mneme-heatbar{display:flex;height:6px;border-radius:3px;overflow:hidden;margin-top:12px;background:var(--dsw-alias-interactive-bg-hover)}",
1466
+ ".mneme-heatbar-seg{min-width:2px}",
1467
+ ".mneme-heatbar--hot{background:var(--dsw-alias-state-warning,#d97706)}",
1468
+ ".mneme-heatbar--warm{background:var(--dsw-alias-label-tertiary)}",
1469
+ ".mneme-heatbar--cold{background:var(--dsw-alias-label-dimmed)}",
1470
+ ".mneme-heatdot{flex:none;width:8px;height:8px;border-radius:50%}",
1471
+ ".mneme-heatdot--hot{background:var(--dsw-alias-state-warning,#d97706)}",
1472
+ ".mneme-heatdot--warm{background:var(--dsw-alias-label-tertiary)}",
1473
+ ".mneme-heatdot--cold{background:var(--dsw-alias-label-dimmed)}",
1383
1474
  // --- 状态页工作台:让用户看见插件在干活(动态/沉淀/归档) ---
1384
1475
  ".mneme-wbhead{margin:28px auto 10px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);max-width:1000px;display:flex;align-items:baseline;justify-content:space-between;gap:8px}",
1385
1476
  ".mneme-wblist{max-width:1000px;display:flex;flex-direction:column;gap:6px}",
@@ -1402,9 +1493,29 @@ window.__ModuleLoader__.load({
1402
1493
  // --- settings cards: boxed cards for the runtime-mode and external-API
1403
1494
  // sections — each card owns its fetch/PUT state, so it renders as a
1404
1495
  // self-contained unit inside the stacked settings view ---
1405
- ".mneme-set-card{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:14px;margin-bottom:12px}",
1496
+ ".mneme-set-card{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;margin-bottom:10px}",
1497
+ // 设置页分组标题(个性化 / 记忆引擎 / 搜索 / 连接与安全 / 帮助):
1498
+ // 先给「这一段在管什么」,卡片才是具体选项
1499
+ ".mneme-set-grouphead{font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-tertiary);margin:24px 0 10px}",
1500
+ ".mneme-set-grouphead:first-child{margin-top:8px}",
1406
1501
  ".mneme-set-token{font-family:monospace;font-size:12px;padding:7px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary);word-break:break-all;user-select:all}",
1407
- ".mneme-set-hint{font-size:12px;color:var(--dsw-alias-label-tertiary)}"
1502
+ ".mneme-set-hint{font-size:12px;color:var(--dsw-alias-label-tertiary)}",
1503
+ // --- 重要性编辑行:与查看态同一份 Lucide 星形(此前是文本星号下拉,角更尖锐且与其他星不统一) ---
1504
+ ".mneme-staredit{display:inline-flex;align-items:center;gap:1px;justify-self:start}",
1505
+ ".mneme-starbtn{border:none;background:none;cursor:pointer;padding:2px 1px;display:inline-flex;color:var(--dsw-alias-label-secondary);transition:transform .12s}",
1506
+ ".mneme-starbtn--on{color:var(--dsw-alias-state-warning,#d97706)}",
1507
+ ".mneme-starbtn:hover{transform:scale(1.12)}",
1508
+ ".mneme-starbtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px;border-radius:4px}",
1509
+ // --- 意见与反馈:图标行 + 版本 footer,收在设置页末尾当「关于」用 ---
1510
+ ".mneme-feedlist{display:flex;flex-direction:column;gap:4px}",
1511
+ ".mneme-feedrow{display:flex;align-items:flex-start;gap:10px;padding:9px 10px;border-radius:10px;text-decoration:none;transition:background .12s}",
1512
+ ".mneme-feedrow:hover{background:var(--dsw-alias-interactive-bg-hover)}",
1513
+ ".mneme-feedico{flex:none;width:28px;height:28px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}",
1514
+ ".mneme-feedrow:hover .mneme-feedico{background:var(--dsw-alias-interactive-bg-active)}",
1515
+ ".mneme-feedtext{display:flex;flex-direction:column;gap:1px;min-width:0}",
1516
+ ".mneme-feedname{font-size:13px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-primary)}",
1517
+ ".mneme-feedsub{font-size:12px;line-height:17px;color:var(--dsw-alias-label-tertiary)}",
1518
+ ".mneme-set-foot{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-top:12px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l1);font-size:12px;color:var(--dsw-alias-label-tertiary)}"
1408
1519
  ].join("\n");
1409
1520
  if (typeof document !== "undefined" && document.querySelector(`style[data-plugin-css="${CSS_TAG}"]`) === null) {
1410
1521
  const tag = document.createElement("style");
@@ -1777,7 +1888,9 @@ window.__ModuleLoader__.load({
1777
1888
  h("div", { className: "mneme-gs-title" },
1778
1889
  h("span", null, selected.node.name),
1779
1890
  h("span", { className: "mneme-gs-meta" },
1780
- `${entityTypeLabel(t, selected.node.type || "concept")} · ★${selected.node.mention_count ?? 1}`)
1891
+ `${entityTypeLabel(t, selected.node.type || "concept")} · `,
1892
+ h(StarGlyph, { size: 11 }),
1893
+ ` ${selected.node.mention_count ?? 1}`)
1781
1894
  ),
1782
1895
  selected.node.name !== entityName && h("button", {
1783
1896
  className: "mneme-footbtn",
@@ -2435,6 +2548,14 @@ window.__ModuleLoader__.load({
2435
2548
  const mailHref = "mailto:work@modusensus.space?subject="
2436
2549
  + encodeURIComponent(`[dsh-mneme 反馈] ${pkgVersion} / ${platformLabel()}`)
2437
2550
  + "&body=" + encodeURIComponent(feedbackBody);
2551
+ // 反馈行:图标 + 主标题 + 一句副标;锚点属性由调用点给(保持 href 字面量可被测试锁住)
2552
+ const feedRow = (iconName, label, sub, anchorProps) => h("a", {
2553
+ className: "mneme-feedrow", ...anchorProps
2554
+ },
2555
+ h("span", { className: "mneme-feedico", "aria-hidden": "true" }, h(Icon, { name: iconName, size: 14 })),
2556
+ h("span", { className: "mneme-feedtext" },
2557
+ h("span", { className: "mneme-feedname" }, label),
2558
+ h("span", { className: "mneme-feedsub" }, sub)));
2438
2559
 
2439
2560
  // Runtime mode + external API — two independent fetches: one failing
2440
2561
  // endpoint only errors its own card, never the other one.
@@ -2643,7 +2764,7 @@ window.__ModuleLoader__.load({
2643
2764
  // 版本自检横幅 — 仅 outdated 时渲染(up-to-date/ahead/unknown/失败
2644
2765
  // 全部零渲染)。钉子警示:安装时指定过版本号的 profile 会被 pnpm
2645
2766
  // 挡住常规升级(#174 报障者的实际成因);市场收录新发布约有 1 天延迟。
2646
- updateInfo && h("section", { className: "mneme-set-sec" },
2767
+ updateInfo && h("section", { className: "mneme-set-card" },
2647
2768
  h("div", { className: "mneme-set-title" },
2648
2769
  t("memory.settings.version.outdated")
2649
2770
  .replace("{v}", updateInfo.latest)
@@ -2651,8 +2772,10 @@ window.__ModuleLoader__.load({
2651
2772
  ),
2652
2773
  h("div", { className: "mneme-featsubhint" }, t("memory.settings.version.outdatedHint"))
2653
2774
  ),
2775
+ // —— 个性化:画像 / 规则 / 自定义指令(Agent 怎么对你) ——
2776
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.personal")),
2654
2777
  // 用户画像 — who the agent is talking to
2655
- h("section", { className: "mneme-set-sec" },
2778
+ h("section", { className: "mneme-set-card" },
2656
2779
  h("div", { className: "mneme-set-title" }, t("memory.settings.profile")),
2657
2780
  h("div", { className: "mneme-set-desc" }, t("memory.settings.profileHint")),
2658
2781
  h("textarea", {
@@ -2667,7 +2790,7 @@ window.__ModuleLoader__.load({
2667
2790
  )
2668
2791
  ),
2669
2792
  // 规则 — numbered rows, hover reveals the delete affordance
2670
- h("section", { className: "mneme-set-sec" },
2793
+ h("section", { className: "mneme-set-card" },
2671
2794
  h("div", { className: "mneme-set-title" }, t("memory.settings.rules")),
2672
2795
  h("div", { className: "mneme-set-desc" }, t("memory.settings.rulesHint")),
2673
2796
  rules.length === 0 && h("div", { className: "mneme-xempty" }, t("memory.settings.empty")),
@@ -2696,7 +2819,7 @@ window.__ModuleLoader__.load({
2696
2819
  )
2697
2820
  ),
2698
2821
  // 自定义指令 — slash commands as titled rows
2699
- h("section", { className: "mneme-set-sec" },
2822
+ h("section", { className: "mneme-set-card" },
2700
2823
  h("div", { className: "mneme-set-title" }, t("memory.settings.commands")),
2701
2824
  h("div", { className: "mneme-set-desc" }, t("memory.settings.commandsHint")),
2702
2825
  commands.length === 0 && h("div", { className: "mneme-xempty" }, t("memory.settings.empty")),
@@ -2726,9 +2849,8 @@ window.__ModuleLoader__.load({
2726
2849
  )
2727
2850
  )
2728
2851
  ),
2729
- // 功能开关 — 0.7.13/0.7.14 后端能力的前端总闸(codingRetrospect、
2730
- // 智能调速器参数、实体抽取、巩固等);重启 DSH 后生效。
2731
- h(FeaturesCard, { t }),
2852
+ // —— 记忆引擎:运行模式(粗粒度)在前,功能开关(细粒度)紧随 ——
2853
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.engine")),
2732
2854
  // 运行模式 — light vs standard chip radios; each click PUTs and the
2733
2855
  // change only lands after a DSH restart (green saved hint says so).
2734
2856
  h("section", { className: "mneme-set-card" },
@@ -2755,6 +2877,30 @@ window.__ModuleLoader__.load({
2755
2877
  t("memory.settings.mode.offList"))
2756
2878
  )
2757
2879
  ),
2880
+ // 功能开关 — 后端能力的细粒度闸门;改动即时保存,重启 DSH 后生效。
2881
+ h(FeaturesCard, { t }),
2882
+ // —— 搜索:语义召回 ——
2883
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.search")),
2884
+ // 向量搜索 — semantic recall over an embeddings API
2885
+ h("section", { className: "mneme-set-card" },
2886
+ h("div", { className: "mneme-set-title" }, t("memory.settings.vectorTitle")),
2887
+ h("div", { className: "mneme-set-desc" }, t("memory.settings.vectorHint")),
2888
+ h("label", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 10, fontSize: 13, color: "var(--dsw-alias-label-primary)" } },
2889
+ h("input", { type: "checkbox", checked: !!vector.enabled, onChange: (e) => setVector({ ...vector, enabled: e.target.checked }) }),
2890
+ h("span", null, t("memory.settings.vectorEnabled"))
2891
+ ),
2892
+ h("input", { className: "mneme-set-input", value: vector.baseUrl, placeholder: t("memory.settings.vectorBaseUrl"), onChange: (e) => setVector({ ...vector, baseUrl: e.target.value }) }),
2893
+ h("input", { className: "mneme-set-input", type: "password", value: vector.apiKey, placeholder: t("memory.settings.vectorApiKey"), onChange: (e) => setVector({ ...vector, apiKey: e.target.value }) }),
2894
+ h("input", { className: "mneme-set-input", value: vector.model, placeholder: t("memory.settings.vectorModel"), onChange: (e) => setVector({ ...vector, model: e.target.value }) }),
2895
+ h("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" } },
2896
+ h("button", { className: "mneme-btn", onClick: saveVector }, t("memory.settings.vectorSave")),
2897
+ vectorSaved && h("span", { className: "mneme-saved" }, t("memory.settings.vectorSaved")),
2898
+ h("button", { className: "mneme-btn", onClick: reindex, disabled: reindexing }, reindexing ? t("memory.settings.vectorReindexing") : t("memory.settings.vectorReindex")),
2899
+ reindexMsg && h("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary, #666)" } }, reindexMsg)
2900
+ )
2901
+ ),
2902
+ // —— 连接与安全:外部访问 API / 面板令牌 ——
2903
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.connect")),
2758
2904
  // 外部访问 API — standalone HTTP service for plugins/CLI/desktop tools;
2759
2905
  // the token is generated and kept by the backend, so it is read-only
2760
2906
  // here with a copy affordance. Changes need a DSH restart.
@@ -2818,26 +2964,10 @@ window.__ModuleLoader__.load({
2818
2964
  )
2819
2965
  )
2820
2966
  ),
2821
- // 向量搜索 — semantic recall over an embeddings API
2822
- h("section", { className: "mneme-set-sec" },
2823
- h("div", { className: "mneme-set-title" }, t("memory.settings.vectorTitle")),
2824
- h("div", { className: "mneme-set-desc" }, t("memory.settings.vectorHint")),
2825
- h("label", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 10, fontSize: 13, color: "var(--dsw-alias-label-primary)" } },
2826
- h("input", { type: "checkbox", checked: !!vector.enabled, onChange: (e) => setVector({ ...vector, enabled: e.target.checked }) }),
2827
- h("span", null, t("memory.settings.vectorEnabled"))
2828
- ),
2829
- h("input", { className: "mneme-set-input", value: vector.baseUrl, placeholder: t("memory.settings.vectorBaseUrl"), onChange: (e) => setVector({ ...vector, baseUrl: e.target.value }) }),
2830
- h("input", { className: "mneme-set-input", type: "password", value: vector.apiKey, placeholder: t("memory.settings.vectorApiKey"), onChange: (e) => setVector({ ...vector, apiKey: e.target.value }) }),
2831
- h("input", { className: "mneme-set-input", value: vector.model, placeholder: t("memory.settings.vectorModel"), onChange: (e) => setVector({ ...vector, model: e.target.value }) }),
2832
- h("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" } },
2833
- h("button", { className: "mneme-btn", onClick: saveVector }, t("memory.settings.vectorSave")),
2834
- vectorSaved && h("span", { className: "mneme-saved" }, t("memory.settings.vectorSaved")),
2835
- h("button", { className: "mneme-btn", onClick: reindex, disabled: reindexing }, reindexing ? t("memory.settings.vectorReindexing") : t("memory.settings.vectorReindex")),
2836
- reindexMsg && h("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary, #666)" } }, reindexMsg)
2837
- )
2838
- ),
2967
+ // 向量搜索卡片已上移到「搜索」分组(与功能开关里的语义检索路线相邻),
2968
+ // 这里不再重复渲染。
2839
2969
  // API Token — advanced, last
2840
- h("section", { className: "mneme-set-sec" },
2970
+ h("section", { className: "mneme-set-card" },
2841
2971
  h("div", { className: "mneme-set-title" }, t("memory.settings.apiTokenTitle")),
2842
2972
  h("div", { className: "mneme-set-desc" }, t("memory.settings.apiTokenHint")),
2843
2973
  h("div", { style: { display: "flex", gap: 8 } },
@@ -2853,18 +2983,25 @@ window.__ModuleLoader__.load({
2853
2983
  ),
2854
2984
  apiTokenSaved && h("div", { style: { marginTop: 8 } }, h("span", { className: "mneme-saved" }, t("memory.settings.apiTokenSaved")))
2855
2985
  ),
2856
- // 帮助与反馈 — 反馈问题三入口(新建 issue 预填 / 邮件 / 浏览已知问题)。
2986
+ // —— 帮助:意见与反馈(图标行 + 版本 footer,兼当「关于」收尾) ——
2987
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.help")),
2988
+ // 反馈三入口:新建 issue 预填(版本+平台)/ 邮件 / 浏览已知问题。
2857
2989
  // 纯前端链接零后端成本;插件版本来自 /info,平台取 userAgent。GitHub
2858
2990
  // 仓库当前没有 issue 模板,故用 issues/new?title=&body= 直接预填。
2859
- h("section", { className: "mneme-set-sec" },
2991
+ h("section", { className: "mneme-set-card" },
2860
2992
  h("div", { className: "mneme-set-title" }, t("memory.settings.feedback.title")),
2861
2993
  h("div", { className: "mneme-set-desc" }, t("memory.settings.feedback.desc")),
2862
- h("div", { style: { display: "flex", flexDirection: "column", gap: 2 } },
2863
- h("a", { className: "mneme-feed-link", href: issueHref, target: "_blank", rel: "noopener noreferrer" }, t("memory.settings.feedback.newIssue")),
2864
- h("a", { className: "mneme-feed-link", href: mailHref }, t("memory.settings.feedback.email")),
2865
- h("a", { className: "mneme-feed-link", href: "https://github.com/slow-stack/mneme/issues", target: "_blank", rel: "noopener noreferrer" }, t("memory.settings.feedback.browse"))
2994
+ h("div", { className: "mneme-feedlist" },
2995
+ feedRow("bug", t("memory.settings.feedback.newIssue"), t("memory.settings.feedback.newIssue.sub"),
2996
+ { href: issueHref, target: "_blank", rel: "noopener noreferrer" }),
2997
+ feedRow("mail", t("memory.settings.feedback.email"), t("memory.settings.feedback.email.sub"),
2998
+ { href: mailHref }),
2999
+ feedRow("search", t("memory.settings.feedback.browse"), t("memory.settings.feedback.browse.sub"),
3000
+ { href: "https://github.com/slow-stack/mneme/issues", target: "_blank", rel: "noopener noreferrer" })
2866
3001
  ),
2867
- h("div", { className: "mneme-featsubhint", style: { marginTop: 8 } }, t("memory.settings.feedback.hint"))
3002
+ h("div", { className: "mneme-set-foot" },
3003
+ h("span", null, `dsh-mneme v${pkgVersion}`)
3004
+ )
2868
3005
  )
2869
3006
  );
2870
3007
  }
@@ -2968,9 +3105,11 @@ window.__ModuleLoader__.load({
2968
3105
 
2969
3106
  // --- Status sub-view: a responsive grid of stat cards. Every card owns
2970
3107
  // its fetch, loading ("…") and error state, so one failing endpoint
2971
- // never blanks or blocks the others. ---
2972
- function StatusCard({ t, title, loading, error, num, cap }) {
2973
- return h("div", { className: "mneme-statuscard" },
3108
+ // never blanks or blocks the others.
3109
+ // 卡片解剖:标题(h3)→ 大数字 → 指标行(rows,一行一指标)→ 脚注
3110
+ // (foot,采样口径这类背景信息)。cap 仍保留给单句说明型卡片。
3111
+ function StatusCard({ t, title, loading, error, num, cap, rows, foot, className }) {
3112
+ return h("div", { className: className ? `mneme-statuscard ${className}` : "mneme-statuscard" },
2974
3113
  h("h3", { className: "mneme-xcolhead" }, title),
2975
3114
  loading
2976
3115
  ? h("div", { className: "mneme-statusnum" }, "…")
@@ -2978,7 +3117,14 @@ window.__ModuleLoader__.load({
2978
3117
  ? h("div", { className: "mneme-statuscap", style: { color: "var(--dsw-alias-state-error,#c33)" } }, t("memory.status.error"))
2979
3118
  : h(react.Fragment, null,
2980
3119
  h("div", { className: "mneme-statusnum" }, num),
2981
- cap ? h("div", { className: "mneme-statuscap" }, cap) : null
3120
+ rows && rows.length
3121
+ ? h("div", { className: "mneme-statrows" },
3122
+ rows.map((r, i) => h("div", { className: "mneme-statrow", key: r.key ?? i },
3123
+ h("span", null, r.label),
3124
+ h("span", { className: "mneme-statrowval", title: String(r.value) }, String(r.value))))
3125
+ )
3126
+ : cap ? h("div", { className: "mneme-statuscap" }, cap) : null,
3127
+ foot ? h("div", { className: "mneme-statfoot" }, foot) : null
2982
3128
  )
2983
3129
  );
2984
3130
  }
@@ -3005,16 +3151,15 @@ window.__ModuleLoader__.load({
3005
3151
  .catch(() => { if (!cancelled) setState({ loading: false, error: true, total: 0, byType: [] }); });
3006
3152
  return () => { cancelled = true; };
3007
3153
  }, []);
3008
- const cap = state.byType
3009
- .map(([ty, n]) => `${typeLabel(t, ty)} ${n === null ? "—" : n}`)
3010
- .join(" · ");
3154
+ const rows = state.byType
3155
+ .map(([ty, n]) => ({ label: typeLabel(t, ty), value: n === null ? "—" : String(n) }));
3011
3156
  return h(StatusCard, {
3012
3157
  t,
3013
3158
  title: t("memory.status.memories"),
3014
3159
  loading: state.loading,
3015
3160
  error: state.error,
3016
3161
  num: state.total.toLocaleString(),
3017
- cap
3162
+ rows
3018
3163
  });
3019
3164
  }
3020
3165
 
@@ -3042,14 +3187,14 @@ window.__ModuleLoader__.load({
3042
3187
  .catch(() => { if (!cancelled) setState({ loading: false, error: true, total: 0, byType: [] }); });
3043
3188
  return () => { cancelled = true; };
3044
3189
  }, []);
3045
- const cap = state.byType.map(([ty, n]) => `${entityTypeLabel(t, ty)} ${n}`).join(" · ");
3190
+ const rows = state.byType.map(([ty, n]) => ({ label: entityTypeLabel(t, ty), value: String(n) }));
3046
3191
  return h(StatusCard, {
3047
3192
  t,
3048
3193
  title: t("memory.status.entities"),
3049
3194
  loading: state.loading,
3050
3195
  error: state.error,
3051
3196
  num: state.total.toLocaleString(),
3052
- cap
3197
+ rows
3053
3198
  });
3054
3199
  }
3055
3200
 
@@ -3216,7 +3361,9 @@ window.__ModuleLoader__.load({
3216
3361
  loading: state.loading,
3217
3362
  error: state.error,
3218
3363
  num,
3219
- cap
3364
+ cap,
3365
+ // 概览区三张卡在 2 列档位会剩下半行空洞:向量卡在该档位跨满整行
3366
+ className: "mneme-statuscard--vectorwide"
3220
3367
  }),
3221
3368
  !state.loading && !state.error && localBlocked
3222
3369
  ? h("div", { className: "mneme-statuscap", style: { marginTop: "6px" } },
@@ -3351,29 +3498,40 @@ window.__ModuleLoader__.load({
3351
3498
  h("div", { className: "mneme-statuscap" }, t("memory.status.injectPreviewNone"))
3352
3499
  );
3353
3500
  }
3354
- const params = [
3355
- `maxItems=${snap.maxItems}`,
3356
- `threshold=${snap.threshold}`,
3357
- snap.adaptive ? t("memory.status.injectPreview.adaptiveOn") : null,
3358
- snap.scoped ? `scope=${snap.scoped.agent_scope || snap.scoped.workspace_scope}` : null,
3359
- snap.rotated > 0 ? `${t("memory.status.injectPreview.rotated")} ${snap.rotated}` : null
3360
- ].filter(Boolean).join(" · ");
3361
- return h("div", { className: "mneme-statuscard", style: { gridColumn: "1 / -1" } },
3501
+ // 参数改用指标行呈现:maxItems/threshold 这类裸键名换成白话标签,
3502
+ // 查询串这类背景信息放脚注。
3503
+ const rows = [
3504
+ { label: t("memory.status.injectPreview.maxItems"), value: String(snap.maxItems) },
3505
+ { label: t("memory.status.injectPreview.threshold"), value: String(snap.threshold) },
3506
+ snap.adaptive ? { label: t("memory.status.injectPreview.adaptiveOn"), value: "✓" } : null,
3507
+ snap.scoped
3508
+ ? { label: t("memory.status.injectPreview.scope"), value: snap.scoped.agent_scope || snap.scoped.workspace_scope }
3509
+ : null,
3510
+ snap.rotated > 0 ? { label: t("memory.status.injectPreview.rotated"), value: String(snap.rotated) } : null,
3511
+ snap.hotChars > 0
3512
+ ? { label: t("memory.status.injectPreview.hot"), value: `${snap.hotChars}${t("memory.status.injectPreview.charsUnit")}` }
3513
+ : null,
3514
+ { label: t("memory.status.injectPreview.chars"), value: `${snap.totalChars}${t("memory.status.injectPreview.charsUnit")}` }
3515
+ ].filter(Boolean);
3516
+ const foot = snap.query
3517
+ ? t("memory.status.injectPreview.query").replace("{query}", snap.query.slice(0, 24))
3518
+ : null;
3519
+ return h("div", { className: "mneme-statuscard mneme-statuscard--wide" },
3362
3520
  h("h3", { className: "mneme-xcolhead" }, t("memory.status.injectPreview")),
3363
- h("div", { className: "mneme-statuscap" },
3364
- params,
3365
- ` · ${t("memory.status.injectPreview.chars").replace("{chars}", String(snap.totalChars))}`,
3366
- snap.query ? ` · ${t("memory.status.injectPreview.query").replace("{query}", snap.query.slice(0, 24))}` : ""
3367
- ),
3368
- snap.hotChars > 0 && h("div", { className: "mneme-statuscap", style: { marginTop: 4 } },
3369
- `${t("memory.status.injectPreview.hot")} · ${snap.hotChars}${t("memory.status.injectPreview.charsUnit")}`),
3370
- h("div", { style: { marginTop: 6 } },
3521
+ h("div", { className: "mneme-statrows" },
3522
+ rows.map((r, i) => h("div", { className: "mneme-statrow", key: i },
3523
+ h("span", null, r.label),
3524
+ h("span", { className: "mneme-statrowval", title: String(r.value) }, String(r.value))))),
3525
+ foot ? h("div", { className: "mneme-statfoot" }, foot) : null,
3526
+ h("div", { style: { marginTop: 10 } },
3371
3527
  (snap.entries || []).length === 0
3372
3528
  ? h("div", { className: "mneme-statuscap" }, t("memory.status.injectPreview.empty"))
3373
3529
  : (snap.entries || []).map((m) => h("div", { key: m.id, style: { display: "flex", gap: 8, alignItems: "baseline", fontSize: 12, padding: "2px 0" } },
3374
3530
  h("span", { className: "mneme-xcolhead" }, typeLabel(t, m.type)),
3375
3531
  h("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, m.title || "—"),
3376
- h("span", { className: "mneme-xcolhead" }, `★${m.importance ?? "—"} · ${m.chars}${t("memory.status.injectPreview.charsUnit")}`))))
3532
+ h("span", { className: "mneme-xcolhead" },
3533
+ h(StarGlyph, { size: 11 }),
3534
+ ` ${m.importance ?? "—"} · ${m.chars}${t("memory.status.injectPreview.charsUnit")}`))))
3377
3535
  );
3378
3536
  }
3379
3537
 
@@ -3666,18 +3824,34 @@ window.__ModuleLoader__.load({
3666
3824
  return () => { cancelled = true; };
3667
3825
  }, []);
3668
3826
  if (state.off) return null;
3669
- return h(StatusCard, {
3670
- t,
3671
- title: t("memory.status.heatDistribution"),
3672
- loading: state.loading,
3673
- error: false,
3674
- num: `${state.hot}`,
3675
- cap: t("memory.status.heatHint")
3676
- .replace("{hot}", String(state.hot))
3677
- .replace("{warm}", String(state.warm))
3678
- .replace("{cold}", String(state.cold))
3679
- .replace("{sample}", String(state.sample))
3680
- });
3827
+ // 三档占比用堆叠条直接画出来(一眼读出分布),数字退到指标行;大数字
3828
+ // 不再放「热门数」——它曾被误读成总数。
3829
+ const total = state.hot + state.warm + state.cold;
3830
+ const tiers = [
3831
+ ["--hot", state.hot, t("memory.status.heat.hot")],
3832
+ ["--warm", state.warm, t("memory.status.heat.warm")],
3833
+ ["--cold", state.cold, t("memory.status.heat.cold")]
3834
+ ];
3835
+ return h("div", { className: "mneme-statuscard" },
3836
+ h("h3", { className: "mneme-xcolhead" }, t("memory.status.heatDistribution")),
3837
+ state.loading
3838
+ ? h("div", { className: "mneme-statusnum" }, "…")
3839
+ : h(react.Fragment, null,
3840
+ total > 0 && h("div", { className: "mneme-heatbar" },
3841
+ tiers.map(([tier, n]) => h("span", {
3842
+ key: tier,
3843
+ className: `mneme-heatbar-seg mneme-heatbar${tier}`,
3844
+ style: { flexGrow: n }
3845
+ }))),
3846
+ h("div", { className: "mneme-statrows" },
3847
+ tiers.map(([tier, n, label]) => h("div", { className: "mneme-statrow", key: tier },
3848
+ h("span", { style: { display: "flex", alignItems: "center", gap: 6 } },
3849
+ h("span", { className: `mneme-heatdot mneme-heatdot${tier}`, "aria-hidden": "true" }),
3850
+ label),
3851
+ h("span", { className: "mneme-statrowval" }, String(n))))),
3852
+ h("div", { className: "mneme-statfoot" },
3853
+ t("memory.status.heat.sample").replace("{sample}", String(state.sample)))
3854
+ ));
3681
3855
  }
3682
3856
 
3683
3857
  // 记忆复用卡(#217):只读聚合 /recall-stats(Top-N 召回 + 僵尸率 +
@@ -3733,19 +3907,26 @@ window.__ModuleLoader__.load({
3733
3907
  return () => { cancelled = true; };
3734
3908
  }, []);
3735
3909
  if (state.off) return null;
3910
+ // 大数字保留复用率;其余指标拆成一行一条,不再用「·」串成散文。
3911
+ const rows = [
3912
+ {
3913
+ label: t("memory.status.recall.zombie"),
3914
+ value: `${state.zombie}/${state.active}(${t("memory.status.recall.exempt")} ${state.exempt})`
3915
+ },
3916
+ { label: t("memory.status.recall.runs"), value: String(state.runs) },
3917
+ state.top && state.top !== "—" ? { label: t("memory.status.recall.top"), value: state.top } : null,
3918
+ state.inject ? { label: t("memory.status.recall.inject"), value: state.inject } : null,
3919
+ state.archive ? { label: t("memory.status.recall.archive"), value: state.archive } : null
3920
+ ].filter(Boolean);
3736
3921
  return h(StatusCard, {
3737
3922
  t,
3738
3923
  title: t("memory.status.recallStats"),
3739
3924
  loading: state.loading,
3740
3925
  error: false,
3741
3926
  num: state.rate ?? "—",
3742
- cap: t("memory.status.recallHint")
3743
- .replace("{rate}", state.rate ?? "—")
3744
- .replace("{zombie}", String(state.zombie))
3745
- .replace("{active}", String(state.active))
3746
- .replace("{exempt}", String(state.exempt))
3747
- .replace("{runs}", String(state.runs))
3748
- .replace("{top}", state.top || "—") + (state.inject ? " · " + state.inject : "") + (state.archive ? " · " + state.archive : "")
3927
+ rows,
3928
+ // 引擎区五张卡是奇数:复用卡信息量最大,宽容器下跨两列补齐行尾空洞
3929
+ className: "mneme-statuscard--wide"
3749
3930
  });
3750
3931
  }
3751
3932
 
@@ -3759,12 +3940,17 @@ window.__ModuleLoader__.load({
3759
3940
  if (queueRef.current.scrollIntoView) queueRef.current.scrollIntoView({ block: "start", behavior: "smooth" });
3760
3941
  };
3761
3942
  return h("div", { className: "mneme-status" },
3762
- h("div", { className: "mneme-statusgrid" },
3943
+ // 两个分组标题把九张卡拆成「库内一览 / 后台运转」两段扫读单元
3944
+ h("div", { className: "mneme-statushead" }, t("memory.status.sec.overview")),
3945
+ h("div", { className: "mneme-statusgrid mneme-statusgrid--overview" },
3763
3946
  h(MemoriesStatusCard, { t }),
3764
3947
  h(EntitiesStatusCard, { t }),
3765
- h(VectorStatusCard, { t }),
3766
- h(LlmStatusCard, { t }),
3948
+ h(VectorStatusCard, { t })
3949
+ ),
3950
+ h("div", { className: "mneme-statushead" }, t("memory.status.sec.engine")),
3951
+ h("div", { className: "mneme-statusgrid" },
3767
3952
  h(DreamStatusCards, { t, onGotoQueue: gotoQueue }),
3953
+ h(LlmStatusCard, { t }),
3768
3954
  h(HeatStatusCard, { t }),
3769
3955
  h(RecallStatsCard, { t }),
3770
3956
  h(InjectStatusCard, { t }),
@@ -3889,12 +4075,16 @@ window.__ModuleLoader__.load({
3889
4075
  h("div", { className: "mneme-dmeta" },
3890
4076
  h("span", { className: "mneme-dmetakey" }, t("memory.explorer.importance")),
3891
4077
  editing
3892
- ? h("select", {
3893
- className: "mneme-select",
3894
- style: { height: 26, fontSize: 12, justifySelf: "start" },
3895
- value: importance,
3896
- onChange: (e) => setImportance(Number(e.target.value))
3897
- }, [1, 2, 3, 4, 5].map((n) => h("option", { key: n, value: n }, "★".repeat(n))))
4078
+ ? h("div", { className: "mneme-staredit", role: "radiogroup", "aria-label": t("memory.explorer.detail.editImportance") },
4079
+ [1, 2, 3, 4, 5].map((n) => h("button", {
4080
+ key: n,
4081
+ type: "button",
4082
+ role: "radio",
4083
+ "aria-checked": String(importance === n),
4084
+ "aria-label": t("memory.explorer.detail.starLabel").replace("{n}", String(n)),
4085
+ className: importance >= n ? "mneme-starbtn mneme-starbtn--on" : "mneme-starbtn",
4086
+ onClick: () => setImportance(n)
4087
+ }, h(StarGlyph, { size: 15, filled: importance >= n }))))
3898
4088
  : h(ImportanceStars, { className: "mneme-dmetaval", value: memory.importance || 0 }),
3899
4089
  memory.heat != null && h(react.Fragment, null,
3900
4090
  h("span", { className: "mneme-dmetakey" }, t("memory.explorer.heat")),
@@ -4546,7 +4736,7 @@ window.__ModuleLoader__.load({
4546
4736
  key: v,
4547
4737
  className: minImp === v ? "mneme-chip mneme-active" : "mneme-chip",
4548
4738
  onClick: () => setMinImp(v)
4549
- }, v === 0 ? t("memory.tab.all") : `★${v}+`))
4739
+ }, v === 0 ? t("memory.tab.all") : h(react.Fragment, null, h(StarGlyph, { size: 11 }), ` ${v}+`)))
4550
4740
  ),
4551
4741
  h("div", { className: "mneme-xcolhead" }, t("memory.explorer.sourceFilter")),
4552
4742
  h("div", { className: "mneme-xrow" },