@modusensus/dsh-mneme 0.8.7 → 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,7 +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 怎么用记忆:什么时候该查、什么时候该写、拿不准就不动",
411
+ "memory.features.continuityRescueEnabled": "压缩边缘抢救",
412
+ "memory.features.continuityRescueEnabled.hint": "长对话被压缩前,先存一份「正在做什么 / 下一步 / 未决问题」的快照,让关键上下文活过压缩",
384
413
  "memory.features.parentOff": "父开关关闭时不生效",
385
414
  "memory.features.autoSummarize": "自动总结",
386
415
  "memory.features.autoSummarize.hint": "对话结束自动提炼记忆条目",
@@ -395,17 +424,24 @@ window.__ModuleLoader__.load({
395
424
  "memory.features.entityExtractionReasoning.low": "低",
396
425
  "memory.features.entityExtractionReasoning.medium": "中",
397
426
  "memory.features.entityExtractionReasoning.high": "高",
398
- "memory.features.entityExtractionModelHint": "Provider/模型留空 = 跟随主对话模型;思考强度 none = 服务商默认",
427
+ "memory.features.summarizeReasoningEffort": "蒸馏思考强度",
428
+ "memory.features.summarizeReasoningEffort.off": "关闭思考",
429
+ "memory.features.summarizeReasoningEffort.none": "跟随默认",
430
+ "memory.features.summarizeReasoningEffort.low": "低",
431
+ "memory.features.summarizeReasoningEffort.medium": "中",
432
+ "memory.features.summarizeReasoningEffort.high": "高",
433
+ "memory.features.summarizeReasoningEffort.hint": "思考型模型建议选「低」或「关闭思考」,避免推理占满输出导致总结失败",
434
+ "memory.features.entityExtractionModelHint": "Provider / 模型留空 = 跟随主对话模型;思考强度选「跟随默认」= 服务商默认",
399
435
  "memory.features.codingRetrospect": "编码记忆蒸馏",
400
- "memory.features.codingRetrospect.hint": "用完整转录(含工具调用与报错)提炼踩坑、约束与被否决方案",
436
+ "memory.features.codingRetrospect.hint": "回顾写代码的完整过程(含报错与工具调用),沉淀踩坑、约束和被否决的方案",
401
437
  "memory.features.rerankEnabled": "结果重排",
402
438
  "memory.features.rerankEnabled.hint": "本地重排模型对召回结果精排,更慢更准",
403
439
  "memory.features.heatEnabled": "热度衰减",
404
- "memory.features.heatEnabled.hint": "按遗忘曲线给记忆降温:久未访问热度越低,参与注入排序与睡眠降级判定",
440
+ "memory.features.heatEnabled.hint": "像遗忘曲线一样给记忆降温:越久没用到排得越靠后,不占注入名额",
405
441
  "memory.features.documentMemoryEnabled": "document 型记忆",
406
- "memory.features.documentMemoryEnabled.hint": "agent 产长文档入库为指针行:注册校验(文件存在 + evidence 求交)、摘要 + 路径落库、去重与 supersede 记账;全文归 agent 按需读,注入只带摘要行(默认关)",
442
+ "memory.features.documentMemoryEnabled.hint": "Agent 写的长文档只在记忆里放一张「摘要卡」:正文仍由 Agent 保管、按需读取,注入时只带摘要,不占上下文",
407
443
  "memory.features.resilientModelDownload": "模型下载断点续传",
408
- "memory.features.resilientModelDownload.hint": "模型文件下载中断后从已下载部分续传并自动重试,失败会记录中断位置;关闭后回到一次性下载",
444
+ "memory.features.resilientModelDownload.hint": "模型下载中断后从断点续传并自动重试;关闭则回到一次性下载",
409
445
  "memory.features.searchSemanticDedup": "语义去重",
410
446
  "memory.features.searchSemanticDedup.hint": "搜索结果中意思相近的条目只保留一条",
411
447
  "memory.features.autoDream": "记忆巩固",
@@ -435,13 +471,13 @@ window.__ModuleLoader__.load({
435
471
  "memory.features.conflictFreezeEnabled": "冲突冻结",
436
472
  "memory.features.conflictFreezeEnabled.hint": "巩固发现互相矛盾的记忆时先冻结待确认",
437
473
  "memory.features.scopeEnabled": "作用域标注",
438
- "memory.features.scopeEnabled.hint": "按会话身份(agent/工作区)给新记忆打归属标注;重启 DSH 后生效",
474
+ "memory.features.scopeEnabled.hint": "新记忆自动记下来自哪个会话(Agent / 工作区),供隔离与检索过滤使用",
439
475
  "memory.features.strictScope": "严格隔离",
440
- "memory.features.strictScope.hint": "检索与注入硬过滤,只对显式声明的归属生效:显式收窄到他者作用域的记忆不可见;载体自动标注只降权保留可见(真正的物理隔离请用 sensitivity)。重启 DSH 后生效",
476
+ "memory.features.strictScope.hint": "开启后,其他会话明确设为私有的记忆对你完全不可见;关闭时仍可见、只是排到后面。要做到彻底隔离,请用条目的「敏感度」字段",
441
477
  "memory.features.trustEpistemicWeighting": "可信度加权",
442
478
  "memory.features.trustEpistemicWeighting.hint": "按来源可信度调整召回排序(实验性)",
443
479
  "memory.features.reflectionFailureTracking": "反思失败追踪",
444
- "memory.features.reflectionFailureTracking.hint": "记录巩固决策的失败样本供后续改进",
480
+ "memory.features.reflectionFailureTracking.hint": "记录巩固失败的案例供后续改进(诊断用)",
445
481
  "memory.features.embedRoute": "语义检索路线",
446
482
  "memory.features.embedProvider": "Embedding 提供方",
447
483
  "memory.features.embedProvider.openai": "OpenAI 兼容接口",
@@ -456,6 +492,10 @@ window.__ModuleLoader__.load({
456
492
  "memory.features.dreamProvider": "巩固模型 Provider",
457
493
  "memory.features.dreamModel": "巩固用模型名",
458
494
  "memory.features.dreamModelHint": "留空 = 跟随主对话模型;只影响记忆巩固(autoDream)用的模型",
495
+ "memory.features.dreamPeakHours": "高峰时段(不做梦)",
496
+ "memory.features.dreamPeakHours.hint": "设置忙碌时段,巩固会避开这些时间、事后补跑。写法:09:00-18:00,多段用逗号分隔,可带星期(如 mon-fri 08:00-12:00),支持跨零点;留空 = 不限制",
497
+ "memory.features.summarizePeakHours": "高峰时段(不蒸馏)",
498
+ "memory.features.summarizePeakHours.hint": "与巩固侧同一份写法;蒸馏会避开这些时段,窗口先攒着、非高峰一次蒸完",
459
499
  "memory.features.sleepProvider": "睡眠 Provider",
460
500
  "memory.features.sleepModel": "睡眠模型",
461
501
  "memory.features.sleepModelHint": "留空 = 用巩固模型或当前模型;建议选非思考模型",
@@ -466,7 +506,7 @@ window.__ModuleLoader__.load({
466
506
  "memory.features.modelTestFail": "测试失败",
467
507
  "memory.features.modelTestHint": "真实发起一次最小巩固调用,验证 Provider/模型连通与 effort 支持",
468
508
  "memory.features.routeStaleMark": "(不在可用列表)",
469
- "memory.features.routeStaleHint": "不在当前可用列表,多为切换 Provider 后的旧值:请改选,或点「测试连通性」当场验证;改动保存后重启 DSH 生效。",
509
+ "memory.features.routeStaleHint": "该值不在当前可用列表(常见于切换过 Provider):请重新选择,或点「测试连通性」当场验证",
470
510
  "memory.explorer.viewCards": "卡片",
471
511
  "memory.explorer.viewTimeline": "时间线",
472
512
  "memory.explorer.viewAria": "视图切换",
@@ -519,16 +559,20 @@ window.__ModuleLoader__.load({
519
559
  "memory.explorer.detail.editTitle": "标题",
520
560
  "memory.explorer.detail.editContent": "内容",
521
561
  "memory.explorer.detail.editImportance": "重要性",
562
+ "memory.explorer.detail.starLabel": "设为 {n} 星",
522
563
  "memory.status.dream": "最近巩固",
523
564
  "memory.status.dreamNever": "尚未运行",
524
565
  "memory.status.conflicts": "待确认冲突",
525
566
  "memory.status.conflictsHint": "冻结的矛盾记忆,等待人工确认",
526
567
  "memory.status.injectSuppressed": "极简模式下注入按宿主设计关闭",
527
- "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",
528
569
  "memory.status.injectPreview": "注入预览",
529
570
  "memory.status.injectPreviewNone": "暂无预览——尚未发生注入(新会话或注入已关闭)",
530
- "memory.status.injectPreview.chars": "总体积 {chars} 字符",
571
+ "memory.status.injectPreview.chars": "总体积",
531
572
  "memory.status.injectPreview.charsUnit": " 字符",
573
+ "memory.status.injectPreview.maxItems": "注入上限",
574
+ "memory.status.injectPreview.threshold": "相关性门槛",
575
+ "memory.status.injectPreview.scope": "会话归属",
532
576
  "memory.status.injectPreview.query": "查询「{query}…」",
533
577
  "memory.status.injectPreview.hot": "hot memory",
534
578
  "memory.status.injectPreview.adaptiveOn": "自适应条数",
@@ -567,11 +611,19 @@ window.__ModuleLoader__.load({
567
611
  "memory.status.consolidatedEmpty": "autoDream / autoSummarize 沉淀的记忆会出现在这里",
568
612
  "memory.status.archivedMemories": "已归档的记忆",
569
613
  "memory.status.heatDistribution": "热度分布",
570
- "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} 条采样",
571
618
  "memory.status.recallStats": "记忆复用",
572
- "memory.status.recallHint": "复用率 {rate} · 僵尸 {zombie}/{active}(豁免 {exempt})· 30 天回执 {runs} 次 · Top:{top}",
573
- "memory.status.recallInject": "注入 {runs} 轮 {count} 条,槽位填充 {fill}%",
574
- "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}",
575
627
  "memory.status.viewAll": "查看全部",
576
628
  "memory.status.depositedCount": "沉淀的记忆({n})",
577
629
  "memory.status.archivedCount": "已归档的记忆({n})",
@@ -593,7 +645,7 @@ window.__ModuleLoader__.load({
593
645
  "memory.status.vectorInitHint": "embedder 不可达,正在重试",
594
646
  "memory.status.vectorRuntimeMissing": "缺少本地推理运行时",
595
647
  "memory.status.vectorRuntimeHint": "本地推理运行时未就绪({status})",
596
- "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)",
597
649
  "memory.runtime.title": "本地推理运行时",
598
650
  "memory.runtime.available": "已就绪",
599
651
  "memory.runtime.missing": "未就绪 —— 只有用本地嵌入(embedProvider: local)时才需要它",
@@ -609,6 +661,8 @@ window.__ModuleLoader__.load({
609
661
  "memory.status.vectorUnconfigured": "未配置",
610
662
  "memory.status.vectorUnconfiguredHint": "未填 embedding 端点/模型或未启用,语义召回不可用",
611
663
  "memory.status.vectorDegradedHint": "已索引 0 / {m} 条,语义召回实际不可用",
664
+ "memory.status.sec.overview": "库内一览",
665
+ "memory.status.sec.engine": "后台运转",
612
666
  "memory.status.llm": "LLM 消耗",
613
667
  "memory.status.llmCalls": "近 7 天 · {n} 次调用",
614
668
  "memory.status.error": "加载失败"
@@ -621,7 +675,13 @@ window.__ModuleLoader__.load({
621
675
  "memory.tab.project": "Projects",
622
676
  "memory.tab.decision": "Decisions",
623
677
  "memory.tab.history": "History",
678
+ "memory.tab.summary": "Summaries",
624
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",
625
685
  "memory.settings.profile": "User Profile",
626
686
  "memory.settings.profileHint": "Describe yourself once — the agent reads it every turn.",
627
687
  "memory.settings.profileSave": "Save Profile",
@@ -726,22 +786,25 @@ window.__ModuleLoader__.load({
726
786
  "memory.settings.apiTokenPlaceholder": "Empty = no auth (default)",
727
787
  "memory.settings.apiTokenSave": "Save Token",
728
788
  "memory.settings.apiTokenSaved": "Token saved",
729
- "memory.settings.feedback.title": "Help & feedback",
730
- "memory.settings.feedback.desc": "Stuck? Search the existing issues, or tell us what happened:",
731
- "memory.settings.feedback.newIssue": "Open a GitHub issue (environment info prefilled)",
732
- "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",
733
795
  "memory.settings.feedback.browse": "Browse known issues",
796
+ "memory.settings.feedback.browse.sub": "Check if it's already reported",
734
797
  "memory.settings.feedback.hint": "Search for an existing issue first — it saves a duplicate.",
735
798
  "memory.settings.version.outdated": "🆕 New version {v} available (running {c})",
736
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.",
737
800
  "memory.settings.mode.title": "Runtime mode",
738
- "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.",
739
802
  "memory.settings.mode.light": "Light",
740
803
  "memory.settings.mode.standard": "Standard",
741
804
  "memory.settings.mode.savedHint": "Saved. Takes effect after restarting DSH",
742
805
  "memory.settings.mode.offList": "Off: consolidation (autoDream) · entity extraction · semantic search",
743
806
  "memory.settings.extapi.title": "External API",
744
- "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.",
745
808
  "memory.settings.extapi.enabled": "Enable",
746
809
  "memory.settings.extapi.disabled": "Disable",
747
810
  "memory.settings.extapi.address": "Address",
@@ -756,11 +819,11 @@ window.__ModuleLoader__.load({
756
819
  "memory.tab.constraint": "Constraints",
757
820
  "memory.tab.document": "Documents",
758
821
  "memory.features.title": "Features",
759
- "memory.features.desc": "Toggle backend capabilities. Changes take effect after restarting DSH.",
760
- "memory.features.group.core": "Core",
761
- "memory.features.group.enhance": "Enhancement",
762
- "memory.features.group.dream": "Consolidation",
763
- "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",
764
827
  "memory.features.group.advanced": "Advanced",
765
828
  "memory.features.advancedToggle": "Advanced (injection · reflection · experimental)",
766
829
  "memory.features.restartHint": "Takes effect after restarting DSH",
@@ -768,7 +831,9 @@ window.__ModuleLoader__.load({
768
831
  "memory.features.autoInject": "Auto injection",
769
832
  "memory.features.autoInject.hint": "Carry relevant memories into every turn",
770
833
  "memory.features.injectGuidanceEnabled": "Capability guide",
771
- "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",
835
+ "memory.features.continuityRescueEnabled": "Compaction-edge rescue",
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",
772
837
  "memory.features.parentOff": "Inactive while auto injection is off",
773
838
  "memory.features.autoSummarize": "Auto summarization",
774
839
  "memory.features.autoSummarize.hint": "Distill memory entries when a conversation ends",
@@ -783,17 +848,24 @@ window.__ModuleLoader__.load({
783
848
  "memory.features.entityExtractionReasoning.low": "Low",
784
849
  "memory.features.entityExtractionReasoning.medium": "Medium",
785
850
  "memory.features.entityExtractionReasoning.high": "High",
786
- "memory.features.entityExtractionModelHint": "Provider / model empty = follow the main conversation model; reasoning none = provider default",
851
+ "memory.features.summarizeReasoningEffort": "Distill reasoning effort",
852
+ "memory.features.summarizeReasoningEffort.off": "No reasoning",
853
+ "memory.features.summarizeReasoningEffort.none": "Follow default",
854
+ "memory.features.summarizeReasoningEffort.low": "Low",
855
+ "memory.features.summarizeReasoningEffort.medium": "Medium",
856
+ "memory.features.summarizeReasoningEffort.high": "High",
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",
787
859
  "memory.features.codingRetrospect": "Coding retrospection",
788
- "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",
789
861
  "memory.features.rerankEnabled": "Reranking",
790
862
  "memory.features.rerankEnabled.hint": "Rerank recalled results with a local model — slower, more precise",
791
863
  "memory.features.heatEnabled": "Heat decay",
792
- "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",
793
865
  "memory.features.documentMemoryEnabled": "Document memory",
794
- "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",
795
867
  "memory.features.resilientModelDownload": "Resumable model downloads",
796
- "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",
797
869
  "memory.features.searchSemanticDedup": "Semantic dedup",
798
870
  "memory.features.searchSemanticDedup.hint": "Keep one entry when search hits near-duplicates",
799
871
  "memory.features.autoDream": "Memory consolidation",
@@ -823,13 +895,13 @@ window.__ModuleLoader__.load({
823
895
  "memory.features.conflictFreezeEnabled": "Conflict freezing",
824
896
  "memory.features.conflictFreezeEnabled.hint": "Freeze contradictory memories for confirmation during consolidation",
825
897
  "memory.features.scopeEnabled": "Scope tagging",
826
- "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",
827
899
  "memory.features.strictScope": "Strict isolation",
828
- "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",
829
901
  "memory.features.trustEpistemicWeighting": "Credibility weighting",
830
902
  "memory.features.trustEpistemicWeighting.hint": "Adjust recall ranking by source credibility (experimental)",
831
903
  "memory.features.reflectionFailureTracking": "Reflection failure tracking",
832
- "memory.features.reflectionFailureTracking.hint": "Record failed consolidation decisions for later improvement",
904
+ "memory.features.reflectionFailureTracking.hint": "Record failed consolidation cases for later improvement (diagnostics)",
833
905
  "memory.features.embedRoute": "Semantic search route",
834
906
  "memory.features.embedProvider": "Embedding provider",
835
907
  "memory.features.embedProvider.openai": "OpenAI-compatible API",
@@ -844,6 +916,10 @@ window.__ModuleLoader__.load({
844
916
  "memory.features.dreamProvider": "Consolidation provider",
845
917
  "memory.features.dreamModel": "Consolidation model",
846
918
  "memory.features.dreamModelHint": "Leave empty to follow the main conversation model; only affects autoDream consolidation",
919
+ "memory.features.dreamPeakHours": "Peak hours (no dreaming)",
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",
921
+ "memory.features.summarizePeakHours": "Peak hours (no distillation)",
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",
847
923
  "memory.features.sleepProvider": "Sleep provider",
848
924
  "memory.features.sleepModel": "Sleep model",
849
925
  "memory.features.sleepModelHint": "Leave empty to reuse the consolidation model; a non-reasoning model is recommended",
@@ -854,7 +930,7 @@ window.__ModuleLoader__.load({
854
930
  "memory.features.modelTestFail": "Test failed",
855
931
  "memory.features.modelTestHint": "Fires one minimal consolidation call to verify provider/model connectivity and effort support",
856
932
  "memory.features.routeStaleMark": " (not in list)",
857
- "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",
858
934
  "memory.explorer.viewCards": "Cards",
859
935
  "memory.explorer.viewTimeline": "Timeline",
860
936
  "memory.explorer.viewAria": "Switch view",
@@ -907,16 +983,20 @@ window.__ModuleLoader__.load({
907
983
  "memory.explorer.detail.editTitle": "Title",
908
984
  "memory.explorer.detail.editContent": "Content",
909
985
  "memory.explorer.detail.editImportance": "Importance",
986
+ "memory.explorer.detail.starLabel": "Set importance to {n} stars",
910
987
  "memory.status.dream": "Last consolidation",
911
988
  "memory.status.dreamNever": "Not yet run",
912
989
  "memory.status.conflicts": "Pending conflicts",
913
990
  "memory.status.conflictsHint": "Frozen contradictory memories awaiting confirmation",
914
991
  "memory.status.injectSuppressed": "Injection disabled by host minimal preset",
915
- "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",
916
993
  "memory.status.injectPreview": "Injection preview",
917
994
  "memory.status.injectPreviewNone": "No preview yet — no injection has happened (new session or injection off)",
918
- "memory.status.injectPreview.chars": "total {chars} chars",
995
+ "memory.status.injectPreview.chars": "Total",
919
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",
920
1000
  "memory.status.injectPreview.query": "query \"{query}…\"",
921
1001
  "memory.status.injectPreview.hot": "hot memory",
922
1002
  "memory.status.injectPreview.adaptiveOn": "adaptive budget",
@@ -955,11 +1035,19 @@ window.__ModuleLoader__.load({
955
1035
  "memory.status.consolidatedEmpty": "Memories deposited by autoDream / autoSummarize appear here",
956
1036
  "memory.status.archivedMemories": "Archived memories",
957
1037
  "memory.status.heatDistribution": "Heat distribution",
958
- "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}",
959
1042
  "memory.status.recallStats": "Recall reuse",
960
- "memory.status.recallHint": "reuse {rate} · zombie {zombie}/{active} (exempt {exempt}) · {runs} runs in 30d · top: {top}",
961
- "memory.status.recallInject": "injected {runs} turns · {count} items ({fill}% slots)",
962
- "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",
963
1051
  "memory.status.viewAll": "View all",
964
1052
  "memory.status.depositedCount": "Deposited memories ({n})",
965
1053
  "memory.status.archivedCount": "Archived memories ({n})",
@@ -981,7 +1069,7 @@ window.__ModuleLoader__.load({
981
1069
  "memory.status.vectorInitHint": "embedder unreachable, retrying",
982
1070
  "memory.status.vectorRuntimeMissing": "Local inference runtime missing",
983
1071
  "memory.status.vectorRuntimeHint": "Local inference runtime not ready ({status})",
984
- "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)",
985
1073
  "memory.runtime.title": "Local inference runtime",
986
1074
  "memory.runtime.available": "ready",
987
1075
  "memory.runtime.missing": "not ready — only needed when you use local embedding (embedProvider: local)",
@@ -997,6 +1085,8 @@ window.__ModuleLoader__.load({
997
1085
  "memory.status.vectorUnconfigured": "Not configured",
998
1086
  "memory.status.vectorUnconfiguredHint": "No embedding endpoint/model configured — semantic recall is off",
999
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",
1000
1090
  "memory.status.llm": "LLM Usage",
1001
1091
  "memory.status.llmCalls": "Last 7 days · {n} calls",
1002
1092
  "memory.status.error": "Failed to load"
@@ -1176,8 +1266,8 @@ window.__ModuleLoader__.load({
1176
1266
  // --- settings: quiet stacked sections, one concern per section ---
1177
1267
  ".mneme-set{flex:1;min-height:0;overflow-y:auto;padding:8px 24px 48px;box-sizing:border-box}",
1178
1268
  ".mneme-set-inner{max-width:720px;margin:0 auto}",
1179
- ".mneme-set-sec{padding:20px 0 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}",
1180
- ".mneme-set-sec:last-child{border-bottom:none}",
1269
+ // 设置页各节一律用 boxed 卡(.mneme-set-card)+ 分组标题(.mneme-set-grouphead):
1270
+ // 旧的「无框 set-sec + 有框 set-card」混排是版面杂乱的一半来源
1181
1271
  ".mneme-set-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);margin-bottom:4px}",
1182
1272
  ".mneme-set-desc{font-size:13px;line-height:19px;color:var(--dsw-alias-label-tertiary);margin-bottom:14px}",
1183
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}",
@@ -1245,7 +1335,6 @@ window.__ModuleLoader__.load({
1245
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)}",
1246
1336
  // 字符串开关的输入框(provider/model 等)与其子块容器
1247
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}",
1248
- ".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}",
1249
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)}",
1250
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}",
1251
1340
  ".mneme-featsub .mneme-featnum{padding:6px 0;border-bottom:none}",
@@ -1352,8 +1441,36 @@ window.__ModuleLoader__.load({
1352
1441
  ".mneme-xemptyico{display:block;margin:0 auto 6px;opacity:.7}",
1353
1442
  // --- status sub-view: responsive stat-card grid (auto-fill, ~220px min) ---
1354
1443
  ".mneme-status{flex:1;min-height:0;overflow-y:auto;padding:20px 24px 40px;box-sizing:border-box}",
1355
- ".mneme-statusgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;max-width:1000px;margin:0 auto}",
1356
- ".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)}",
1357
1474
  // --- 状态页工作台:让用户看见插件在干活(动态/沉淀/归档) ---
1358
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}",
1359
1476
  ".mneme-wblist{max-width:1000px;display:flex;flex-direction:column;gap:6px}",
@@ -1376,9 +1493,29 @@ window.__ModuleLoader__.load({
1376
1493
  // --- settings cards: boxed cards for the runtime-mode and external-API
1377
1494
  // sections — each card owns its fetch/PUT state, so it renders as a
1378
1495
  // self-contained unit inside the stacked settings view ---
1379
- ".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}",
1380
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}",
1381
- ".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)}"
1382
1519
  ].join("\n");
1383
1520
  if (typeof document !== "undefined" && document.querySelector(`style[data-plugin-css="${CSS_TAG}"]`) === null) {
1384
1521
  const tag = document.createElement("style");
@@ -1751,7 +1888,9 @@ window.__ModuleLoader__.load({
1751
1888
  h("div", { className: "mneme-gs-title" },
1752
1889
  h("span", null, selected.node.name),
1753
1890
  h("span", { className: "mneme-gs-meta" },
1754
- `${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}`)
1755
1894
  ),
1756
1895
  selected.node.name !== entityName && h("button", {
1757
1896
  className: "mneme-footbtn",
@@ -1931,7 +2070,7 @@ window.__ModuleLoader__.load({
1931
2070
  // 「重置用户配置」,子项自己勾着的值要留着,也应该能提前设好。同一份关系在
1932
2071
  // 后端 src/config.js 的 INJECT_CHILD_FLAGS(运行时闸门),两侧漂移由
1933
2072
  // test/inject-parent-gate.test.js 钉住。
1934
- const FEATURE_CHILDREN = { autoInject: ["injectGuidanceEnabled"] };
2073
+ const FEATURE_CHILDREN = { autoInject: ["injectGuidanceEnabled", "continuityRescueEnabled"] };
1935
2074
  const FEATURE_GROUPS = [
1936
2075
  { key: "group.core", items: ["autoInject", "autoSummarize", "hotMemoryEnabled", "memoryQualityFilter.enabled", "llmAudit.enabled"] },
1937
2076
  { key: "group.enhance", items: ["entityExtractionEnabled", "codingRetrospect", "rerankEnabled", "resilientModelDownload", "searchSemanticDedup", "bm25SearchEnabled", "heatEnabled", "documentMemoryEnabled"] },
@@ -1942,10 +2081,16 @@ window.__ModuleLoader__.load({
1942
2081
  const FEATURE_ADVANCED_BOOLS = ["hybridInject", "selectiveInjectEnabled", "adaptiveThresholdEnabled", "reflectionUpdateEnabled", "reflectionFailureTracking", "conflictFreezeEnabled", "trustEpistemicWeighting"];
1943
2082
  // 字符串键(blur/Enter 提交,空串合法 = 跟随默认):巩固模型与语义
1944
2083
  // 检索路线。embedProvider 是枚举,用下拉单独渲染。
1945
- const FEATURE_STRINGS = ["dreamProvider", "dreamModel", "sleepProvider", "sleepModel", "entityExtractionProvider", "entityExtractionModel", "localEmbedModel", "ollamaBaseUrl", "ollamaModel"];
2084
+ const FEATURE_STRINGS = ["dreamProvider", "dreamModel", "sleepProvider", "sleepModel", "entityExtractionProvider", "entityExtractionModel", "localEmbedModel", "ollamaBaseUrl", "ollamaModel",
2085
+ // Issue #239 第 4 项:错峰时段串(巩固侧与蒸馏侧)。此前只有后端白名单、
2086
+ // 面板调不到——两个错峰键一个能调一个不能比都不给更让人困惑。
2087
+ "dreamPeakHours", "summarizePeakHours"];
1946
2088
  const EMBED_PROVIDERS = ["openai", "local", "ollama"];
1947
2089
  // 实体抽取思考强度(issue #109):与后端 FEATURE_FLAG_ENUMS 枚举对齐。
1948
2090
  const ENTITY_REASONING = ["none", "low", "medium", "high"];
2091
+ // 蒸馏思考强度(issue #315):比 entity 多一个 off(显式关思考,思考型模型
2092
+ // 蒸馏防推理烧预算)。后端枚举含 off,面板必须能选到,否则操作者用不上。
2093
+ const SUMMARIZE_REASONING = ["off", "none", "low", "medium", "high"];
1949
2094
 
1950
2095
  function FeatureRow({ name, hint, on, disabled, onToggle, sub }) {
1951
2096
  return h("div", { className: "mneme-featrow", style: sub ? { paddingLeft: 18, opacity: 0.86 } : undefined },
@@ -2201,7 +2346,11 @@ window.__ModuleLoader__.load({
2201
2346
  Array.isArray(routes)
2202
2347
  ? routeSelects("dreamProvider", "dreamModel", dreamTest, setDreamTest, "dreamReasoningEffort")
2203
2348
  : h(react.Fragment, null, strRow("dreamProvider"), strRow("dreamModel")),
2204
- h("div", { className: "mneme-featsubhint" }, t("memory.features.dreamModelHint"))
2349
+ h("div", { className: "mneme-featsubhint" }, t("memory.features.dreamModelHint")),
2350
+ // Issue #239 第 4 项镜像到巩固:高峰时段串(空 = 关闭)。放在 autoDream
2351
+ // 子块内——它是巩固的排程,开关关掉时不该还在界面上留着可编辑的输入框。
2352
+ strRow("dreamPeakHours"),
2353
+ h("div", { className: "mneme-featsubhint" }, t("memory.features.dreamPeakHours.hint"))
2205
2354
  );
2206
2355
 
2207
2356
  // 睡眠模型:sleepModeEnabled 开着才展开(sleepProvider/sleepModel 随本版
@@ -2231,6 +2380,27 @@ window.__ModuleLoader__.load({
2231
2380
  h("div", { className: "mneme-featsubhint" }, t("memory.features.entityExtractionModelHint"))
2232
2381
  );
2233
2382
 
2383
+ // 蒸馏思考强度(issue #315):autoSummarize 开着才展开,档位与实体抽取
2384
+ // 同款枚举下拉、即时提交。蒸馏没有独立 provider/model 路由键(跟随会话
2385
+ // 头或 config 文件的 summarizeProvider/summarizeModel),不上连通性测试。
2386
+ const summarizeSub = eff.autoSummarize && h("div", { className: "mneme-featsub" },
2387
+ h("div", { className: "mneme-featnum" },
2388
+ h("span", { className: "mneme-featnumlabel" }, t("memory.features.summarizeReasoningEffort")),
2389
+ h("select", {
2390
+ className: "mneme-select",
2391
+ value: eff.summarizeReasoningEffort || "none",
2392
+ disabled: busy,
2393
+ onChange: (e) => put({ summarizeReasoningEffort: e.target.value })
2394
+ },
2395
+ SUMMARIZE_REASONING.map((r) => h("option", { key: r, value: r }, t(`memory.features.summarizeReasoningEffort.${r}`))))
2396
+ ),
2397
+ h("div", { className: "mneme-featsubhint" }, t("memory.features.summarizeReasoningEffort.hint")),
2398
+ // Issue #239 第 4 项:蒸馏侧错峰时段串(空 = 关闭)。与思考强度同处一个
2399
+ // autoSummarize 子块——两处错峰开关都能在面板上调(巩固侧见 dreamSub)。
2400
+ strRow("summarizePeakHours"),
2401
+ h("div", { className: "mneme-featsubhint" }, t("memory.features.summarizePeakHours.hint"))
2402
+ );
2403
+
2234
2404
  if (error && !state) return h("section", { className: "mneme-set-card" },
2235
2405
  h("div", { className: "mneme-set-title" }, t("memory.features.title")),
2236
2406
  h("div", { className: "mneme-set-hint" }, error));
@@ -2248,6 +2418,7 @@ window.__ModuleLoader__.load({
2248
2418
  FEATURE_GROUPS.map((g) => h(react.Fragment, { key: g.key },
2249
2419
  h("div", { className: "mneme-featgroup" }, t(`memory.features.${g.key}`)),
2250
2420
  g.items.map(flagRow),
2421
+ g.key === "group.core" && h(react.Fragment, null, summarizeSub),
2251
2422
  g.key === "group.enhance" && h(react.Fragment, null, embedSub, entitySub),
2252
2423
  g.key === "group.dream" && h(react.Fragment, null, dreamSub, sleepSub)
2253
2424
  )),
@@ -2377,6 +2548,14 @@ window.__ModuleLoader__.load({
2377
2548
  const mailHref = "mailto:work@modusensus.space?subject="
2378
2549
  + encodeURIComponent(`[dsh-mneme 反馈] ${pkgVersion} / ${platformLabel()}`)
2379
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)));
2380
2559
 
2381
2560
  // Runtime mode + external API — two independent fetches: one failing
2382
2561
  // endpoint only errors its own card, never the other one.
@@ -2585,7 +2764,7 @@ window.__ModuleLoader__.load({
2585
2764
  // 版本自检横幅 — 仅 outdated 时渲染(up-to-date/ahead/unknown/失败
2586
2765
  // 全部零渲染)。钉子警示:安装时指定过版本号的 profile 会被 pnpm
2587
2766
  // 挡住常规升级(#174 报障者的实际成因);市场收录新发布约有 1 天延迟。
2588
- updateInfo && h("section", { className: "mneme-set-sec" },
2767
+ updateInfo && h("section", { className: "mneme-set-card" },
2589
2768
  h("div", { className: "mneme-set-title" },
2590
2769
  t("memory.settings.version.outdated")
2591
2770
  .replace("{v}", updateInfo.latest)
@@ -2593,8 +2772,10 @@ window.__ModuleLoader__.load({
2593
2772
  ),
2594
2773
  h("div", { className: "mneme-featsubhint" }, t("memory.settings.version.outdatedHint"))
2595
2774
  ),
2775
+ // —— 个性化:画像 / 规则 / 自定义指令(Agent 怎么对你) ——
2776
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.personal")),
2596
2777
  // 用户画像 — who the agent is talking to
2597
- h("section", { className: "mneme-set-sec" },
2778
+ h("section", { className: "mneme-set-card" },
2598
2779
  h("div", { className: "mneme-set-title" }, t("memory.settings.profile")),
2599
2780
  h("div", { className: "mneme-set-desc" }, t("memory.settings.profileHint")),
2600
2781
  h("textarea", {
@@ -2609,7 +2790,7 @@ window.__ModuleLoader__.load({
2609
2790
  )
2610
2791
  ),
2611
2792
  // 规则 — numbered rows, hover reveals the delete affordance
2612
- h("section", { className: "mneme-set-sec" },
2793
+ h("section", { className: "mneme-set-card" },
2613
2794
  h("div", { className: "mneme-set-title" }, t("memory.settings.rules")),
2614
2795
  h("div", { className: "mneme-set-desc" }, t("memory.settings.rulesHint")),
2615
2796
  rules.length === 0 && h("div", { className: "mneme-xempty" }, t("memory.settings.empty")),
@@ -2638,7 +2819,7 @@ window.__ModuleLoader__.load({
2638
2819
  )
2639
2820
  ),
2640
2821
  // 自定义指令 — slash commands as titled rows
2641
- h("section", { className: "mneme-set-sec" },
2822
+ h("section", { className: "mneme-set-card" },
2642
2823
  h("div", { className: "mneme-set-title" }, t("memory.settings.commands")),
2643
2824
  h("div", { className: "mneme-set-desc" }, t("memory.settings.commandsHint")),
2644
2825
  commands.length === 0 && h("div", { className: "mneme-xempty" }, t("memory.settings.empty")),
@@ -2668,9 +2849,8 @@ window.__ModuleLoader__.load({
2668
2849
  )
2669
2850
  )
2670
2851
  ),
2671
- // 功能开关 — 0.7.13/0.7.14 后端能力的前端总闸(codingRetrospect、
2672
- // 智能调速器参数、实体抽取、巩固等);重启 DSH 后生效。
2673
- h(FeaturesCard, { t }),
2852
+ // —— 记忆引擎:运行模式(粗粒度)在前,功能开关(细粒度)紧随 ——
2853
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.engine")),
2674
2854
  // 运行模式 — light vs standard chip radios; each click PUTs and the
2675
2855
  // change only lands after a DSH restart (green saved hint says so).
2676
2856
  h("section", { className: "mneme-set-card" },
@@ -2697,6 +2877,30 @@ window.__ModuleLoader__.load({
2697
2877
  t("memory.settings.mode.offList"))
2698
2878
  )
2699
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")),
2700
2904
  // 外部访问 API — standalone HTTP service for plugins/CLI/desktop tools;
2701
2905
  // the token is generated and kept by the backend, so it is read-only
2702
2906
  // here with a copy affordance. Changes need a DSH restart.
@@ -2760,26 +2964,10 @@ window.__ModuleLoader__.load({
2760
2964
  )
2761
2965
  )
2762
2966
  ),
2763
- // 向量搜索 — semantic recall over an embeddings API
2764
- h("section", { className: "mneme-set-sec" },
2765
- h("div", { className: "mneme-set-title" }, t("memory.settings.vectorTitle")),
2766
- h("div", { className: "mneme-set-desc" }, t("memory.settings.vectorHint")),
2767
- h("label", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 10, fontSize: 13, color: "var(--dsw-alias-label-primary)" } },
2768
- h("input", { type: "checkbox", checked: !!vector.enabled, onChange: (e) => setVector({ ...vector, enabled: e.target.checked }) }),
2769
- h("span", null, t("memory.settings.vectorEnabled"))
2770
- ),
2771
- h("input", { className: "mneme-set-input", value: vector.baseUrl, placeholder: t("memory.settings.vectorBaseUrl"), onChange: (e) => setVector({ ...vector, baseUrl: e.target.value }) }),
2772
- h("input", { className: "mneme-set-input", type: "password", value: vector.apiKey, placeholder: t("memory.settings.vectorApiKey"), onChange: (e) => setVector({ ...vector, apiKey: e.target.value }) }),
2773
- h("input", { className: "mneme-set-input", value: vector.model, placeholder: t("memory.settings.vectorModel"), onChange: (e) => setVector({ ...vector, model: e.target.value }) }),
2774
- h("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" } },
2775
- h("button", { className: "mneme-btn", onClick: saveVector }, t("memory.settings.vectorSave")),
2776
- vectorSaved && h("span", { className: "mneme-saved" }, t("memory.settings.vectorSaved")),
2777
- h("button", { className: "mneme-btn", onClick: reindex, disabled: reindexing }, reindexing ? t("memory.settings.vectorReindexing") : t("memory.settings.vectorReindex")),
2778
- reindexMsg && h("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary, #666)" } }, reindexMsg)
2779
- )
2780
- ),
2967
+ // 向量搜索卡片已上移到「搜索」分组(与功能开关里的语义检索路线相邻),
2968
+ // 这里不再重复渲染。
2781
2969
  // API Token — advanced, last
2782
- h("section", { className: "mneme-set-sec" },
2970
+ h("section", { className: "mneme-set-card" },
2783
2971
  h("div", { className: "mneme-set-title" }, t("memory.settings.apiTokenTitle")),
2784
2972
  h("div", { className: "mneme-set-desc" }, t("memory.settings.apiTokenHint")),
2785
2973
  h("div", { style: { display: "flex", gap: 8 } },
@@ -2795,18 +2983,25 @@ window.__ModuleLoader__.load({
2795
2983
  ),
2796
2984
  apiTokenSaved && h("div", { style: { marginTop: 8 } }, h("span", { className: "mneme-saved" }, t("memory.settings.apiTokenSaved")))
2797
2985
  ),
2798
- // 帮助与反馈 — 反馈问题三入口(新建 issue 预填 / 邮件 / 浏览已知问题)。
2986
+ // —— 帮助:意见与反馈(图标行 + 版本 footer,兼当「关于」收尾) ——
2987
+ h("div", { className: "mneme-set-grouphead" }, t("memory.settings.group.help")),
2988
+ // 反馈三入口:新建 issue 预填(版本+平台)/ 邮件 / 浏览已知问题。
2799
2989
  // 纯前端链接零后端成本;插件版本来自 /info,平台取 userAgent。GitHub
2800
2990
  // 仓库当前没有 issue 模板,故用 issues/new?title=&body= 直接预填。
2801
- h("section", { className: "mneme-set-sec" },
2991
+ h("section", { className: "mneme-set-card" },
2802
2992
  h("div", { className: "mneme-set-title" }, t("memory.settings.feedback.title")),
2803
2993
  h("div", { className: "mneme-set-desc" }, t("memory.settings.feedback.desc")),
2804
- h("div", { style: { display: "flex", flexDirection: "column", gap: 2 } },
2805
- h("a", { className: "mneme-feed-link", href: issueHref, target: "_blank", rel: "noopener noreferrer" }, t("memory.settings.feedback.newIssue")),
2806
- h("a", { className: "mneme-feed-link", href: mailHref }, t("memory.settings.feedback.email")),
2807
- 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" })
2808
3001
  ),
2809
- 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
+ )
2810
3005
  )
2811
3006
  );
2812
3007
  }
@@ -2910,9 +3105,11 @@ window.__ModuleLoader__.load({
2910
3105
 
2911
3106
  // --- Status sub-view: a responsive grid of stat cards. Every card owns
2912
3107
  // its fetch, loading ("…") and error state, so one failing endpoint
2913
- // never blanks or blocks the others. ---
2914
- function StatusCard({ t, title, loading, error, num, cap }) {
2915
- 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" },
2916
3113
  h("h3", { className: "mneme-xcolhead" }, title),
2917
3114
  loading
2918
3115
  ? h("div", { className: "mneme-statusnum" }, "…")
@@ -2920,7 +3117,14 @@ window.__ModuleLoader__.load({
2920
3117
  ? h("div", { className: "mneme-statuscap", style: { color: "var(--dsw-alias-state-error,#c33)" } }, t("memory.status.error"))
2921
3118
  : h(react.Fragment, null,
2922
3119
  h("div", { className: "mneme-statusnum" }, num),
2923
- 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
2924
3128
  )
2925
3129
  );
2926
3130
  }
@@ -2947,16 +3151,15 @@ window.__ModuleLoader__.load({
2947
3151
  .catch(() => { if (!cancelled) setState({ loading: false, error: true, total: 0, byType: [] }); });
2948
3152
  return () => { cancelled = true; };
2949
3153
  }, []);
2950
- const cap = state.byType
2951
- .map(([ty, n]) => `${typeLabel(t, ty)} ${n === null ? "—" : n}`)
2952
- .join(" · ");
3154
+ const rows = state.byType
3155
+ .map(([ty, n]) => ({ label: typeLabel(t, ty), value: n === null ? "—" : String(n) }));
2953
3156
  return h(StatusCard, {
2954
3157
  t,
2955
3158
  title: t("memory.status.memories"),
2956
3159
  loading: state.loading,
2957
3160
  error: state.error,
2958
3161
  num: state.total.toLocaleString(),
2959
- cap
3162
+ rows
2960
3163
  });
2961
3164
  }
2962
3165
 
@@ -2984,14 +3187,14 @@ window.__ModuleLoader__.load({
2984
3187
  .catch(() => { if (!cancelled) setState({ loading: false, error: true, total: 0, byType: [] }); });
2985
3188
  return () => { cancelled = true; };
2986
3189
  }, []);
2987
- 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) }));
2988
3191
  return h(StatusCard, {
2989
3192
  t,
2990
3193
  title: t("memory.status.entities"),
2991
3194
  loading: state.loading,
2992
3195
  error: state.error,
2993
3196
  num: state.total.toLocaleString(),
2994
- cap
3197
+ rows
2995
3198
  });
2996
3199
  }
2997
3200
 
@@ -3158,7 +3361,9 @@ window.__ModuleLoader__.load({
3158
3361
  loading: state.loading,
3159
3362
  error: state.error,
3160
3363
  num,
3161
- cap
3364
+ cap,
3365
+ // 概览区三张卡在 2 列档位会剩下半行空洞:向量卡在该档位跨满整行
3366
+ className: "mneme-statuscard--vectorwide"
3162
3367
  }),
3163
3368
  !state.loading && !state.error && localBlocked
3164
3369
  ? h("div", { className: "mneme-statuscap", style: { marginTop: "6px" } },
@@ -3293,29 +3498,40 @@ window.__ModuleLoader__.load({
3293
3498
  h("div", { className: "mneme-statuscap" }, t("memory.status.injectPreviewNone"))
3294
3499
  );
3295
3500
  }
3296
- const params = [
3297
- `maxItems=${snap.maxItems}`,
3298
- `threshold=${snap.threshold}`,
3299
- snap.adaptive ? t("memory.status.injectPreview.adaptiveOn") : null,
3300
- snap.scoped ? `scope=${snap.scoped.agent_scope || snap.scoped.workspace_scope}` : null,
3301
- snap.rotated > 0 ? `${t("memory.status.injectPreview.rotated")} ${snap.rotated}` : null
3302
- ].filter(Boolean).join(" · ");
3303
- 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" },
3304
3520
  h("h3", { className: "mneme-xcolhead" }, t("memory.status.injectPreview")),
3305
- h("div", { className: "mneme-statuscap" },
3306
- params,
3307
- ` · ${t("memory.status.injectPreview.chars").replace("{chars}", String(snap.totalChars))}`,
3308
- snap.query ? ` · ${t("memory.status.injectPreview.query").replace("{query}", snap.query.slice(0, 24))}` : ""
3309
- ),
3310
- snap.hotChars > 0 && h("div", { className: "mneme-statuscap", style: { marginTop: 4 } },
3311
- `${t("memory.status.injectPreview.hot")} · ${snap.hotChars}${t("memory.status.injectPreview.charsUnit")}`),
3312
- 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 } },
3313
3527
  (snap.entries || []).length === 0
3314
3528
  ? h("div", { className: "mneme-statuscap" }, t("memory.status.injectPreview.empty"))
3315
3529
  : (snap.entries || []).map((m) => h("div", { key: m.id, style: { display: "flex", gap: 8, alignItems: "baseline", fontSize: 12, padding: "2px 0" } },
3316
3530
  h("span", { className: "mneme-xcolhead" }, typeLabel(t, m.type)),
3317
3531
  h("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, m.title || "—"),
3318
- 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")}`))))
3319
3535
  );
3320
3536
  }
3321
3537
 
@@ -3608,18 +3824,34 @@ window.__ModuleLoader__.load({
3608
3824
  return () => { cancelled = true; };
3609
3825
  }, []);
3610
3826
  if (state.off) return null;
3611
- return h(StatusCard, {
3612
- t,
3613
- title: t("memory.status.heatDistribution"),
3614
- loading: state.loading,
3615
- error: false,
3616
- num: `${state.hot}`,
3617
- cap: t("memory.status.heatHint")
3618
- .replace("{hot}", String(state.hot))
3619
- .replace("{warm}", String(state.warm))
3620
- .replace("{cold}", String(state.cold))
3621
- .replace("{sample}", String(state.sample))
3622
- });
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
+ ));
3623
3855
  }
3624
3856
 
3625
3857
  // 记忆复用卡(#217):只读聚合 /recall-stats(Top-N 召回 + 僵尸率 +
@@ -3675,19 +3907,26 @@ window.__ModuleLoader__.load({
3675
3907
  return () => { cancelled = true; };
3676
3908
  }, []);
3677
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);
3678
3921
  return h(StatusCard, {
3679
3922
  t,
3680
3923
  title: t("memory.status.recallStats"),
3681
3924
  loading: state.loading,
3682
3925
  error: false,
3683
3926
  num: state.rate ?? "—",
3684
- cap: t("memory.status.recallHint")
3685
- .replace("{rate}", state.rate ?? "—")
3686
- .replace("{zombie}", String(state.zombie))
3687
- .replace("{active}", String(state.active))
3688
- .replace("{exempt}", String(state.exempt))
3689
- .replace("{runs}", String(state.runs))
3690
- .replace("{top}", state.top || "—") + (state.inject ? " · " + state.inject : "") + (state.archive ? " · " + state.archive : "")
3927
+ rows,
3928
+ // 引擎区五张卡是奇数:复用卡信息量最大,宽容器下跨两列补齐行尾空洞
3929
+ className: "mneme-statuscard--wide"
3691
3930
  });
3692
3931
  }
3693
3932
 
@@ -3701,12 +3940,17 @@ window.__ModuleLoader__.load({
3701
3940
  if (queueRef.current.scrollIntoView) queueRef.current.scrollIntoView({ block: "start", behavior: "smooth" });
3702
3941
  };
3703
3942
  return h("div", { className: "mneme-status" },
3704
- 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" },
3705
3946
  h(MemoriesStatusCard, { t }),
3706
3947
  h(EntitiesStatusCard, { t }),
3707
- h(VectorStatusCard, { t }),
3708
- 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" },
3709
3952
  h(DreamStatusCards, { t, onGotoQueue: gotoQueue }),
3953
+ h(LlmStatusCard, { t }),
3710
3954
  h(HeatStatusCard, { t }),
3711
3955
  h(RecallStatsCard, { t }),
3712
3956
  h(InjectStatusCard, { t }),
@@ -3831,12 +4075,16 @@ window.__ModuleLoader__.load({
3831
4075
  h("div", { className: "mneme-dmeta" },
3832
4076
  h("span", { className: "mneme-dmetakey" }, t("memory.explorer.importance")),
3833
4077
  editing
3834
- ? h("select", {
3835
- className: "mneme-select",
3836
- style: { height: 26, fontSize: 12, justifySelf: "start" },
3837
- value: importance,
3838
- onChange: (e) => setImportance(Number(e.target.value))
3839
- }, [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 }))))
3840
4088
  : h(ImportanceStars, { className: "mneme-dmetaval", value: memory.importance || 0 }),
3841
4089
  memory.heat != null && h(react.Fragment, null,
3842
4090
  h("span", { className: "mneme-dmetakey" }, t("memory.explorer.heat")),
@@ -4488,7 +4736,7 @@ window.__ModuleLoader__.load({
4488
4736
  key: v,
4489
4737
  className: minImp === v ? "mneme-chip mneme-active" : "mneme-chip",
4490
4738
  onClick: () => setMinImp(v)
4491
- }, v === 0 ? t("memory.tab.all") : `★${v}+`))
4739
+ }, v === 0 ? t("memory.tab.all") : h(react.Fragment, null, h(StarGlyph, { size: 11 }), ` ${v}+`)))
4492
4740
  ),
4493
4741
  h("div", { className: "mneme-xcolhead" }, t("memory.explorer.sourceFilter")),
4494
4742
  h("div", { className: "mneme-xrow" },