dsh-prime-memory 0.22.2 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.en.md +421 -0
  2. package/CHANGELOG.ja.md +416 -0
  3. package/CHANGELOG.ko.md +416 -0
  4. package/CHANGELOG.md +120 -0
  5. package/dist/client.js +1266 -845
  6. package/dist/config.d.ts +131 -1341
  7. package/dist/config.js +89 -4
  8. package/dist/conflict-service.d.ts +7 -1
  9. package/dist/conflict-service.js +7 -1
  10. package/dist/contract.d.ts +211 -0
  11. package/dist/domain-gate.d.ts +11 -0
  12. package/dist/domain-gate.js +15 -0
  13. package/dist/hooks/obsolete-notice.d.ts +26 -0
  14. package/dist/hooks/obsolete-notice.js +64 -0
  15. package/dist/hooks/recall.d.ts +39 -0
  16. package/dist/hooks/recall.js +110 -30
  17. package/dist/index.d.ts +1 -1127
  18. package/dist/index.js +52 -2
  19. package/dist/memory-types.d.ts +69 -0
  20. package/dist/memory-types.js +165 -0
  21. package/dist/memport/format.d.ts +6 -1
  22. package/dist/memport/format.js +42 -2
  23. package/dist/pipeline/l1.d.ts +44 -2
  24. package/dist/pipeline/l1.js +163 -9
  25. package/dist/pipeline/md-sync.d.ts +65 -0
  26. package/dist/pipeline/md-sync.js +456 -0
  27. package/dist/pipeline/ruminate.d.ts +46 -1
  28. package/dist/pipeline/ruminate.js +109 -0
  29. package/dist/pipeline/runner.d.ts +10 -0
  30. package/dist/pipeline/runner.js +13 -2
  31. package/dist/pipeline/workspace-relink.d.ts +60 -0
  32. package/dist/pipeline/workspace-relink.js +73 -0
  33. package/dist/projection/recall.d.ts +51 -13
  34. package/dist/projection/recall.js +47 -12
  35. package/dist/prompts/examples.d.ts +73 -0
  36. package/dist/prompts/examples.js +178 -0
  37. package/dist/prompts/l1-dedup.d.ts +9 -3
  38. package/dist/prompts/l1-dedup.js +34 -13
  39. package/dist/prompts/l1-extraction.d.ts +5 -3
  40. package/dist/prompts/l1-extraction.js +49 -4
  41. package/dist/settings.d.ts +8 -0
  42. package/dist/settings.js +16 -1
  43. package/dist/stats.d.ts +12 -0
  44. package/dist/stats.js +352 -17
  45. package/dist/store/embedding-source.d.ts +8 -0
  46. package/dist/store/embedding-source.js +39 -2
  47. package/dist/store/file-versions.d.ts +2 -0
  48. package/dist/store/file-versions.js +2 -0
  49. package/dist/store/graph-store.d.ts +14 -0
  50. package/dist/store/graph-store.js +35 -0
  51. package/dist/store/l1-snapshot.d.ts +26 -1
  52. package/dist/store/l1-snapshot.js +53 -8
  53. package/dist/store/l1.d.ts +94 -3
  54. package/dist/store/l1.js +169 -4
  55. package/dist/store/memory-md-archive.d.ts +84 -0
  56. package/dist/store/memory-md-archive.js +155 -0
  57. package/dist/store/memory-md-disable.d.ts +74 -0
  58. package/dist/store/memory-md-disable.js +302 -0
  59. package/dist/store/memory-md-export.d.ts +50 -0
  60. package/dist/store/memory-md-export.js +227 -0
  61. package/dist/store/memory-md-ledger.d.ts +94 -0
  62. package/dist/store/memory-md-ledger.js +243 -0
  63. package/dist/store/memory-md-orphan.d.ts +27 -0
  64. package/dist/store/memory-md-orphan.js +153 -0
  65. package/dist/store/memory-md-parse.d.ts +35 -0
  66. package/dist/store/memory-md-parse.js +85 -0
  67. package/dist/store/memory-md-run.d.ts +48 -0
  68. package/dist/store/memory-md-run.js +151 -0
  69. package/dist/store/memory-md-skeleton.d.ts +18 -0
  70. package/dist/store/memory-md-skeleton.js +61 -0
  71. package/dist/store/memory-md-sync.d.ts +59 -0
  72. package/dist/store/memory-md-sync.js +152 -0
  73. package/dist/store/memory-md-types.d.ts +243 -0
  74. package/dist/store/memory-md-types.js +10 -0
  75. package/dist/store/memory-md.d.ts +117 -0
  76. package/dist/store/memory-md.js +230 -0
  77. package/dist/store/obsolete-notices.d.ts +39 -0
  78. package/dist/store/obsolete-notices.js +153 -0
  79. package/dist/store/recall-feedback.d.ts +75 -0
  80. package/dist/store/recall-feedback.js +213 -0
  81. package/dist/store/recall-usage.d.ts +11 -0
  82. package/dist/store/recall-usage.js +29 -0
  83. package/dist/store/session-recalled.d.ts +38 -3
  84. package/dist/store/session-recalled.js +156 -9
  85. package/dist/store/sqlite.d.ts +66 -0
  86. package/dist/store/sqlite.js +233 -15
  87. package/dist/store/supersede.d.ts +1 -1
  88. package/dist/store/supersede.js +1 -1
  89. package/dist/tools/index.d.ts +4 -0
  90. package/dist/tools/index.js +26 -7
  91. package/dist/tools/slots.d.ts +2 -1
  92. package/dist/tools/slots.js +2 -1
  93. package/dist/types.d.ts +24 -7
  94. package/dist/types.js +10 -2
  95. package/dist/util/maturity.d.ts +20 -3
  96. package/dist/util/maturity.js +18 -1
  97. package/dist/util/md-name.d.ts +129 -0
  98. package/dist/util/md-name.js +366 -0
  99. package/dist/util/md-normalize.d.ts +23 -0
  100. package/dist/util/md-normalize.js +131 -0
  101. package/dist/workspace-route.d.ts +22 -0
  102. package/dist/workspace-route.js +66 -0
  103. package/dsh.plugin.json +1 -1
  104. package/package.json +6 -5
package/dist/client.js CHANGED
@@ -32,7 +32,7 @@ var __defProp = Object.defineProperty;
32
32
  module.exports = __toCommonJS(entry_exports);
33
33
 
34
34
  // client/src/panel.tsx
35
- var import_react21 = require("react");
35
+ var import_react22 = require("react");
36
36
 
37
37
  // client/src/sidebar-icon.ts
38
38
  var BOOK_ICON_SVG = '<svg data-mem-icon="1" viewBox="0 0 16 16" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink:0"><path d="M8 3.4C6.6 2.5 4.6 2.4 2.9 3.1v9.3c1.7-.7 3.7-.6 5.1.3 1.4-.9 3.4-1 5.1-.3V3.1C11.4 2.4 9.4 2.5 8 3.4Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M8 3.4v9.3" stroke="currentColor" stroke-width="1.2"/></svg>';
@@ -264,6 +264,108 @@ var __defProp = Object.defineProperty;
264
264
  sceneTitle: { fontSize: 13, fontWeight: 600, fontFamily: "ui-monospace, Consolas, monospace", color: "var(--dsh-mem-text-1)" }
265
265
  };
266
266
 
267
+ // src/memory-types.ts
268
+ var HOST_MEMORY_TYPES = [
269
+ // —— 个人可见(chat 族):用户画像的四类 ——
270
+ "user_info",
271
+ "user_hobby",
272
+ "user_communication",
273
+ "user_behavior",
274
+ // —— 项目轴(work 族)——
275
+ "project_introduction",
276
+ "project_tech_stack",
277
+ "project_architecture",
278
+ "project_build_configuration",
279
+ "project_dependency_configuration",
280
+ "project_ide_configuration",
281
+ "project_scm_configuration",
282
+ "project_environment_configuration",
283
+ "project_rule",
284
+ // —— 开发规范轴(work 族)——
285
+ "development_code_specification",
286
+ "development_practice_specification",
287
+ "development_test_specification",
288
+ "development_comment_specification",
289
+ // —— 经验轴(work 族)——
290
+ "task_summary_experience",
291
+ "task_breakdown_experience",
292
+ "task_flow_experience",
293
+ "task_experience",
294
+ "tool_experience",
295
+ "mcp_experience",
296
+ "skill_experience",
297
+ "learned_skill_experience",
298
+ "expert_experience",
299
+ "important_decision_experience",
300
+ "common_pitfalls_experience",
301
+ "history_task_reference_files"
302
+ ];
303
+ var LEGACY_MEMORY_TYPES = [
304
+ "persona",
305
+ "episodic",
306
+ "instruction",
307
+ "work_fact",
308
+ "work_task",
309
+ "work_method",
310
+ "work_artifact"
311
+ ];
312
+ var UNCLASSIFIED_DIR = "unclassified";
313
+ var MEMORY_TYPE_VOCABULARY = /* @__PURE__ */ new Set([
314
+ ...LEGACY_MEMORY_TYPES,
315
+ ...HOST_MEMORY_TYPES
316
+ ]);
317
+ var TYPE_FAMILY_MAP = Object.freeze(
318
+ (() => {
319
+ const map = {};
320
+ for (const t of LEGACY_MEMORY_TYPES) map[t] = t.startsWith("work") ? "work" : "chat";
321
+ for (const t of HOST_MEMORY_TYPES) map[t] = t.startsWith("user_") ? "chat" : "work";
322
+ map[UNCLASSIFIED_DIR] = "chat";
323
+ return map;
324
+ })()
325
+ );
326
+ var MEMORY_TYPE_LABELS = Object.freeze({
327
+ persona: "画像偏好",
328
+ episodic: "客观事件",
329
+ instruction: "全局指令",
330
+ work_fact: "工作事实",
331
+ work_task: "工作任务",
332
+ work_method: "工作方法",
333
+ work_artifact: "工作资产",
334
+ user_info: "用户信息",
335
+ user_hobby: "用户爱好",
336
+ user_communication: "沟通风格",
337
+ user_behavior: "行为规范",
338
+ project_introduction: "项目介绍",
339
+ project_tech_stack: "技术栈",
340
+ project_architecture: "架构设计",
341
+ project_build_configuration: "构建配置",
342
+ project_dependency_configuration: "依赖配置",
343
+ project_ide_configuration: "IDE 配置",
344
+ project_scm_configuration: "版本控制配置",
345
+ project_environment_configuration: "环境配置",
346
+ project_rule: "项目规则",
347
+ development_code_specification: "代码规范",
348
+ development_practice_specification: "实践规范",
349
+ development_test_specification: "测试规范",
350
+ development_comment_specification: "注释规范",
351
+ task_summary_experience: "任务总结",
352
+ task_breakdown_experience: "任务拆解",
353
+ task_flow_experience: "任务流程",
354
+ task_experience: "任务经验",
355
+ tool_experience: "工具经验",
356
+ mcp_experience: "MCP 经验",
357
+ skill_experience: "技能经验",
358
+ learned_skill_experience: "习得技能",
359
+ expert_experience: "专家经验",
360
+ important_decision_experience: "重要决策",
361
+ common_pitfalls_experience: "常见陷阱",
362
+ history_task_reference_files: "历史参考文件",
363
+ [UNCLASSIFIED_DIR]: "未分类"
364
+ });
365
+ function slugOf(type) {
366
+ return type.replace(/_/g, "-");
367
+ }
368
+
267
369
  // client/src/theme.ts
268
370
  var THEME_STYLE_ID = "dsh-mem-theme-style";
269
371
  var LIGHT_TOK = [
@@ -346,6 +448,18 @@ var __defProp = Object.defineProperty;
346
448
  " --dsh-mem-shadow-card: var(--dsw-shadow-lv1, 0 2px 4px 0 rgba(0,0,0,0.3));",
347
449
  " --dsh-mem-shadow-pop: var(--dsw-shadow-lv3, 0 0 1px 0 rgba(0,0,0,.2), 0 0 4px 0 rgba(0,0,0,.02), 0 12px 32px 0 rgba(0,0,0,0.08));"
348
450
  ];
451
+ var EXT_LIGHT = ["#8a5a00", "#0757b4", "#116629", "#6f42c1", "#b43a6f", "#076f6b", "#7a5c00", "#4a6fa5"];
452
+ var EXT_DARK = ["#e3b341", "#6cb2ff", "#6fca74", "#c297ff", "#f077b6", "#56d4c8", "#d9b64a", "#9db8e8"];
453
+ var EXT_TAG_RULES = HOST_MEMORY_TYPES.map(
454
+ (t, i) => `.dsh-mem-tag-${slugOf(t)} { --dsh-mem-tag-c: ${EXT_LIGHT[i % EXT_LIGHT.length]}; }`
455
+ ).concat(
456
+ HOST_MEMORY_TYPES.map(
457
+ (t, i) => `body[data-ds-dark-theme] .dsh-mem-tag-${slugOf(t)} { --dsh-mem-tag-c: ${EXT_DARK[i % EXT_DARK.length]}; }`
458
+ ),
459
+ // 兜底桶固定中性灰:它代表“没归类”,不该带族色暗示。
460
+ `.dsh-mem-tag-${UNCLASSIFIED_DIR} { --dsh-mem-tag-c: #8a93a1; }`,
461
+ `body[data-ds-dark-theme] .dsh-mem-tag-${UNCLASSIFIED_DIR} { --dsh-mem-tag-c: #9aa4b2; }`
462
+ );
349
463
  var COMPONENT_CSS = [
350
464
  // conic 角度要 @property 注册才能插值动画;不支持 @property 的浏览器里
351
465
  // var(--dsh-mem-angle) 无定义 → conic 层失效 → background 整条退化为无背景
@@ -452,6 +566,8 @@ var __defProp = Object.defineProperty;
452
566
  "body[data-ds-dark-theme] .dsh-mem-tag-work-fact { --dsh-mem-tag-c: #6cb2ff; }",
453
567
  "body[data-ds-dark-theme] .dsh-mem-tag-work-task { --dsh-mem-tag-c: #6fca74; }",
454
568
  "body[data-ds-dark-theme] .dsh-mem-tag-work-method { --dsh-mem-tag-c: #c297ff; }",
569
+ // —— 扩展类别(宿主 29 类 + 兜底桶):类名从真源派生,缺一个类就是“标签无色” ——
570
+ ...EXT_TAG_RULES,
455
571
  // ── pill 边缘流光(品牌蓝族,chat/work/auto 三档共用;off 无):border 区画旋转
456
572
  // conic 光带;内部必须用【不透明】底色盖住光带——半透明内层会让 conic 透进按钮
457
573
  // 内部干扰文字(实测事故)。不透明底 = 主题底混 3% 档位色(--dsh-mem-pill-tint
@@ -561,15 +677,22 @@ var __defProp = Object.defineProperty;
561
677
  var import_react2 = require("react");
562
678
 
563
679
  // client/src/format.ts
564
- var TYPE_LABELS = {
565
- persona: "画像偏好",
566
- episodic: "客观事件",
567
- instruction: "全局指令",
568
- work_fact: "工作事实",
569
- work_task: "工作任务",
570
- work_method: "工作方法",
571
- work_artifact: "工作资产"
572
- };
680
+ var typeLabels = {};
681
+ function registerTypeCatalog(entries) {
682
+ if (!entries || entries.length === 0) return;
683
+ const next = { ...typeLabels };
684
+ for (const e of entries) next[e.id] = e.label;
685
+ typeLabels = next;
686
+ }
687
+ function typeLabel(type) {
688
+ return typeLabels[type] || type;
689
+ }
690
+ function typeCatalogIds() {
691
+ return Object.keys(typeLabels);
692
+ }
693
+ function tagClass(type) {
694
+ return "dsh-mem-tag dsh-mem-tag-" + type.replace(/_/g, "-");
695
+ }
573
696
  function fmtTime(iso) {
574
697
  if (!iso) return "-";
575
698
  try {
@@ -1514,7 +1637,7 @@ var __defProp = Object.defineProperty;
1514
1637
  }
1515
1638
 
1516
1639
  // client/src/tabs/OverviewTab.tsx
1517
- var import_react15 = require("react");
1640
+ var import_react16 = require("react");
1518
1641
 
1519
1642
  // client/src/pill/modes.ts
1520
1643
  var MODES = [
@@ -1533,12 +1656,281 @@ var __defProp = Object.defineProperty;
1533
1656
  return "关闭";
1534
1657
  }
1535
1658
 
1659
+ // client/src/tabs/ArchiveSection.tsx
1660
+ var import_react7 = require("react");
1661
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1662
+ var HINT_STYLE = { fontSize: 12, color: "var(--dsh-mem-text-3)", lineHeight: "18px" };
1663
+ var ROOT_STYLE = { fontSize: 11, color: "var(--dsh-mem-text-3)", wordBreak: "break-all" };
1664
+ async function call(rpc, method, payload) {
1665
+ try {
1666
+ const r = await rpc(method, payload);
1667
+ if (r && r.ok && r.value !== void 0) return { report: r.value };
1668
+ const msg = r && !r.ok ? r.error?.message : void 0;
1669
+ return { error: typeof msg === "string" && msg.length > 0 ? msg : "端点无响应" };
1670
+ } catch (err) {
1671
+ return { error: err instanceof Error ? err.message : String(err) };
1672
+ }
1673
+ }
1674
+ function lineOf(rep) {
1675
+ const head = `已写 ${rep.written} · 未变 ${rep.unchanged} · 跳过 ${rep.skipped}`;
1676
+ const named = rep.named > 0 ? ` · 新起名 ${rep.named} 条` : "";
1677
+ const nameBad = rep.nameFailed > 0 ? ` · 起名失败 ${rep.nameFailed} 条(下轮重试)` : "";
1678
+ const s = rep.suffix;
1679
+ const suffix = s && s.renamed + s.revived + s.both + s.edited > 0 ? ` · 后缀对齐 改名 ${s.renamed}${s.edited > 0 ? `(人改过 ${s.edited})` : ""} 改回 ${s.revived}${s.both > 0 ? ` · 冲突 ${s.both}` : ""}` : "";
1680
+ const suffixMore = s && s.capped && s.remaining > 0 ? ` · 后缀还有 ${s.remaining} 个文件待对齐,再点一次继续` : "";
1681
+ const tail = rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 个文件,再点一次继续` : "";
1682
+ const budget = typeof rep.appliedMaxRecords === "number" && rep.appliedMaxRecords > 0 ? ` · 本次预算 ${rep.appliedMaxRecords} 个文件` : "";
1683
+ const passes = typeof rep.passes === "number" && rep.passes > 1 ? ` · 共滚 ${rep.passes} 轮` : "";
1684
+ return head + named + nameBad + suffix + suffixMore + budget + passes + tail;
1685
+ }
1686
+ function lineOfReconcile(rep) {
1687
+ const parts = [
1688
+ `首次 ${rep.firstTime}`,
1689
+ `一致 ${rep.same}`,
1690
+ `仅库变 ${rep.dbOnly}`,
1691
+ `仅文件变 ${rep.fileOnly}`,
1692
+ `两边都变 ${rep.both}`,
1693
+ `文件缺失 ${rep.missingFile}`
1694
+ ];
1695
+ return parts.join(" · ") + (rep.capped ? `(本次只扫了 ${rep.scanned} 条,未扫全)` : "");
1696
+ }
1697
+ function lineOfSync(rep) {
1698
+ const head = `回灌 ${rep.imported} · 重写文件 ${rep.rendered} · 退场 ${rep.retired} · 一致 ${rep.same}`;
1699
+ const tail = rep.pending > 0 ? ` · 两边都变 ${rep.pending} 条已挂账(两侧都没动)` : "";
1700
+ const extra = rep.newFiles > 0 ? ` · 新文件 ${rep.newFiles} 个未入库(导入须走写入内核)` : "";
1701
+ const links = rep.skippedLinks > 0 ? ` · 防护拦下 ${rep.skippedLinks} 个链接/越界条目(未读)` : "";
1702
+ const stale = rep.staleRootFiles > 0 ? ` · 陈旧根 ${rep.staleRootFiles} 个文件未参与同步(交给孤儿归档)` : "";
1703
+ const multi = rep.multiPath > 0 ? ` · 同记录多路径 ${rep.multiPath} 份未动(先跑孤儿归档再同步)` : "";
1704
+ const hashBad = rep.hashMismatch > 0 ? ` · 自校验不符 ${rep.hashMismatch} 个(文件被外部改动,已按文件侧处理)` : "";
1705
+ const unsigned = rep.unsigned > 0 ? ` · 未签名 ${rep.unsigned} 个(老投射文件无 hash,下轮导出补盖)` : "";
1706
+ return head + tail + extra + links + stale + multi + hashBad + unsigned + (rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 个文件,再点一次继续` : "");
1707
+ }
1708
+ function lineOfOrphans(rep) {
1709
+ const head = rep.dryRun ? `账本共 ${rep.scanned} 条 · 仍被认领 ${rep.claimed} · 无人认领 ${rep.orphans}(未搬任何东西)` : `已搬 ${rep.moved} · 失败 ${rep.failed} · 仍被认领 ${rep.claimed}`;
1710
+ const tail = rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 条,再点一次继续` : "";
1711
+ return head + tail + (rep.dir.length > 0 ? ` · 归档到 ${rep.dir}` : "");
1712
+ }
1713
+ function lineOfCleanup(rep) {
1714
+ if (rep.aborted) return `清理已中止(未删任何记录):${rep.diffs.join(";") || "门禁未通过"}`;
1715
+ if (rep.dryRun) return `待删 ${rep.targets} 条(预览了前 ${rep.items?.length ?? 0} 条)——未删除任何东西`;
1716
+ const f = rep.files ?? { moved: 0, failed: 0, absent: 0 };
1717
+ const head = `已删 ${rep.purged} 条 · 归档正文 ${rep.archiveMd === void 0 || rep.archiveMd === "" ? "未写" : "已写"} · 文件搬家 ${f.moved}(失败 ${f.failed}) · 图索引 ${rep.graphForgotten ?? 0}`;
1718
+ return rep.otherChanged && rep.otherChanged > 0 ? `${head} · 本批之外 ${rep.otherChanged} 条处于漂移(不影响本批)` : head;
1719
+ }
1720
+ function ArchiveSection(props) {
1721
+ const rpc = props.rpc;
1722
+ const [busy, setBusy] = (0, import_react7.useState)(false);
1723
+ const [exported, setExported] = (0, import_react7.useState)(void 0);
1724
+ const [recon, setRecon] = (0, import_react7.useState)(void 0);
1725
+ const [synced, setSynced] = (0, import_react7.useState)(void 0);
1726
+ const [orphans, setOrphans] = (0, import_react7.useState)(void 0);
1727
+ const [cleanup, setCleanup] = (0, import_react7.useState)(void 0);
1728
+ const [orphanArmed, setOrphanArmed] = (0, import_react7.useState)(false);
1729
+ const [armed, setArmed] = (0, import_react7.useState)(false);
1730
+ const [error, setError] = (0, import_react7.useState)(void 0);
1731
+ const [budgetDraft, setBudgetDraft] = (0, import_react7.useState)("");
1732
+ const [budgetNote, setBudgetNote] = (0, import_react7.useState)("");
1733
+ const [prog, setProg] = (0, import_react7.useState)(void 0);
1734
+ const pullProgress = () => {
1735
+ void rpc("dsh-memory/mem-run-status", {}).then((r) => {
1736
+ const v = r && r.ok ? r.value : void 0;
1737
+ if (v !== void 0) setProg(v);
1738
+ }).catch(() => {
1739
+ });
1740
+ };
1741
+ const runExport = () => {
1742
+ if (busy) return;
1743
+ setBusy(true);
1744
+ setError(void 0);
1745
+ const timer = setInterval(pullProgress, 500);
1746
+ pullProgress();
1747
+ void call(rpc, "dsh-memory/mem-export", {}).then((out) => {
1748
+ clearInterval(timer);
1749
+ setBusy(false);
1750
+ if (out.report !== void 0) {
1751
+ setExported(out.report);
1752
+ pullProgress();
1753
+ }
1754
+ if (out.error !== void 0) setError(out.error);
1755
+ });
1756
+ };
1757
+ (0, import_react7.useEffect)(() => {
1758
+ void rpc("dsh-memory/settings-get", {}).then((r) => {
1759
+ const v = r && r.ok ? r.value : void 0;
1760
+ const n = v?.settings?.mdExportMaxRecords;
1761
+ if (typeof n === "number") setBudgetDraft(String(n));
1762
+ }).catch(() => {
1763
+ });
1764
+ }, [rpc]);
1765
+ const commitBudget = () => {
1766
+ const raw = budgetDraft.trim();
1767
+ if (raw === "") return;
1768
+ const n = Math.floor(Number(raw));
1769
+ if (!Number.isFinite(n) || n < 0 || n > 1e4) {
1770
+ setBudgetNote("预算要 0~10000 的整数(0 = 跟随部署默认)");
1771
+ return;
1772
+ }
1773
+ void rpc("dsh-memory/settings-set", { mdExportMaxRecords: n }).then((r) => {
1774
+ setBudgetNote(r && r.ok ? n === 0 ? "已改为跟随部署默认" : `已设为每次最多 ${n} 个文件,下一次点击生效` : "写入失败:预算未改");
1775
+ }).catch(() => {
1776
+ setBudgetNote("写入失败:预算未改");
1777
+ });
1778
+ };
1779
+ const run = (method, sink, payload) => {
1780
+ if (busy) return;
1781
+ setBusy(true);
1782
+ setError(void 0);
1783
+ void call(rpc, method, payload).then((out) => {
1784
+ if (out.report !== void 0) sink(out.report);
1785
+ if (out.error !== void 0) setError(out.error);
1786
+ setBusy(false);
1787
+ });
1788
+ };
1789
+ const root = exported?.root ?? recon?.root;
1790
+ const pct = prog !== void 0 && prog.total > 0 ? Math.min(100, Math.round(prog.done / (prog.total * 2) * 100)) : 0;
1791
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 12, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
1792
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, color: "var(--dsh-mem-text-2)", marginBottom: 6 }, children: "外部存档(markdown 投射)" }),
1793
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: S.flexRow, children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1795
+ NButton,
1796
+ {
1797
+ disabled: busy,
1798
+ title: "把当前全部记忆渲染为 <根>/<类型>/<名称>.memory.md,并记下内容指纹(只写文件,不改库)。一次点完:一轮预算不够时服务端自己续跑下几轮,进度看下方进度条",
1799
+ onClick: runExport,
1800
+ children: "导出为可携存档"
1801
+ }
1802
+ ),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1804
+ NButton,
1805
+ {
1806
+ disabled: busy,
1807
+ title: "按账本基线比对库与磁盘,只出报告:什么都不写,因此不需要高权限",
1808
+ onClick: () => {
1809
+ run("dsh-memory/mem-reconcile", setRecon, {});
1810
+ },
1811
+ children: "与存档对账"
1812
+ }
1813
+ ),
1814
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1815
+ NButton,
1816
+ {
1817
+ disabled: busy,
1818
+ title: "文件 → 库:只有文件变过的回灌入库,`.disable` 后缀的退场;两边都变的那些两侧都不动,只挂账。会写库,因此需要高权限模式",
1819
+ onClick: () => {
1820
+ run("dsh-memory/mem-sync", setSynced, {});
1821
+ },
1822
+ children: "从存档同步回库"
1823
+ }
1824
+ ),
1825
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1826
+ NButton,
1827
+ {
1828
+ disabled: busy,
1829
+ title: "只读预览:扫账本,找出“我们写过但现在没记录认领它”的投射文件(改名/消歧留下的残片)。来路不明的文件一律不动,也不搬任何东西",
1830
+ onClick: () => {
1831
+ setOrphanArmed(false);
1832
+ run("dsh-memory/mem-orphans", setOrphans, { dryRun: true });
1833
+ },
1834
+ children: "孤儿文件预览"
1835
+ }
1836
+ ),
1837
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1838
+ NButton,
1839
+ {
1840
+ disabled: busy || orphans === void 0 || !orphans.dryRun || orphans.orphans === 0,
1841
+ title: orphanArmed ? "再点一次就真的搬——文件会被移出投射目录(不删,进归档目录,可手动搬回)" : "不删只搬:进 <数据目录>/memories-orphans/<批次时间戳>/;需要先跑预览,再点两次确认;服务端还要高权限模式",
1842
+ onClick: () => {
1843
+ if (!orphanArmed) {
1844
+ setOrphanArmed(true);
1845
+ return;
1846
+ }
1847
+ setOrphanArmed(false);
1848
+ run("dsh-memory/mem-orphans", setOrphans, { dryRun: false });
1849
+ },
1850
+ children: orphanArmed ? "确认搬走孤儿文件" : "孤儿文件归档"
1851
+ }
1852
+ ),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1854
+ NButton,
1855
+ {
1856
+ disabled: busy,
1857
+ title: "只读预览:列出将被物理删除的退场记忆(前 50 条)与总数,不删任何东西",
1858
+ onClick: () => {
1859
+ setArmed(false);
1860
+ run("dsh-memory/cleanup-retired", setCleanup, { dryRun: true });
1861
+ },
1862
+ children: "清理预览(干跑)"
1863
+ }
1864
+ ),
1865
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1866
+ NButton,
1867
+ {
1868
+ disabled: busy || cleanup === void 0 || !cleanup.dryRun || cleanup.targets === 0,
1869
+ title: armed ? "再点一次就真的删——物理删除不可逆(但会先落快照与归档正文)" : "不可逆动作:需要先跑预览,再点两次确认;服务端那边还要高权限模式",
1870
+ onClick: () => {
1871
+ if (!armed) {
1872
+ setArmed(true);
1873
+ return;
1874
+ }
1875
+ setArmed(false);
1876
+ run("dsh-memory/cleanup-retired", setCleanup, { dryRun: false });
1877
+ },
1878
+ children: armed ? "确认物理删除" : "清理并归档"
1879
+ }
1880
+ )
1881
+ ] }),
1882
+ prog !== void 0 && prog.total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 8 }, children: [
1883
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }),
1884
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...HINT_STYLE, marginTop: 3 }, children: [
1885
+ prog.detail,
1886
+ prog.notice !== void 0 && prog.notice !== "" ? ` · ${prog.notice}` : ""
1887
+ ] })
1888
+ ] }) : null,
1889
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...S.flexRow, marginTop: 8, alignItems: "center" }, children: [
1890
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: "单次文件更新预算" }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1892
+ NInput,
1893
+ {
1894
+ type: "number",
1895
+ min: 0,
1896
+ max: 1e4,
1897
+ style: { width: 96 },
1898
+ title: "一次点击最多更新多少个投射文件(导出写入 + 后缀改名都占额度)。“没变过”的不占额度。0 = 跟随部署默认(2000);上限 10000。",
1899
+ placeholder: "0",
1900
+ value: budgetDraft,
1901
+ onChange: (e) => {
1902
+ setBudgetDraft(e.target.value);
1903
+ setBudgetNote("");
1904
+ },
1905
+ onBlur: () => {
1906
+ commitBudget();
1907
+ },
1908
+ onKeyDown: (e) => {
1909
+ if (e.key === "Enter") commitBudget();
1910
+ }
1911
+ }
1912
+ ),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: "个文件/次(0 = 默认 2000)" }),
1914
+ budgetNote !== "" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: budgetNote }) : null
1915
+ ] }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...HINT_STYLE, marginTop: 6 }, children: error !== void 0 ? `失败:${error}` : cleanup !== void 0 ? lineOfCleanup(cleanup) : orphans !== void 0 ? lineOfOrphans(orphans) : synced !== void 0 ? lineOfSync(synced) : exported !== void 0 ? lineOf(exported) : recon !== void 0 ? lineOfReconcile(recon) : "导出=库→文件;对账=只读比较;同步=文件→库;孤儿=搬走没人认领的残片;清理=物理删除(不可逆,需高权限模式)。" }),
1917
+ recon !== void 0 && error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: HINT_STYLE, children: [
1918
+ "最近差异样本:",
1919
+ recon.samples.map((s) => `${s.state}:${s.relPath}`).join(",") || "(无)"
1920
+ ] }) : null,
1921
+ root !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: ROOT_STYLE, children: [
1922
+ "投射根:",
1923
+ root
1924
+ ] }) : null
1925
+ ] });
1926
+ }
1927
+
1536
1928
  // client/src/tabs/DistillSettings.tsx
1537
- var import_react11 = require("react");
1929
+ var import_react12 = require("react");
1538
1930
 
1539
1931
  // client/src/tabs/BudgetInputs.tsx
1540
- var import_react7 = require("react");
1541
- var import_jsx_runtime7 = require("react/jsx-runtime");
1932
+ var import_react8 = require("react");
1933
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1542
1934
  var LAYERS = [
1543
1935
  ["extract", "抽取"],
1544
1936
  ["dedup", "去重"],
@@ -1559,7 +1951,7 @@ var __defProp = Object.defineProperty;
1559
1951
  const onError = props.onError;
1560
1952
  const scope = props.scope ?? "all";
1561
1953
  const layers = scope === "all" || scope === "input" ? LAYERS : LAYERS.filter((l) => SCOPE_KEYS[scope].includes(l[0]));
1562
- const [draft, setDraft] = (0, import_react7.useState)(null);
1954
+ const [draft, setDraft] = (0, import_react8.useState)(null);
1563
1955
  if (!data || !data.budgets) return null;
1564
1956
  const cur = data.budgets.current || {};
1565
1957
  const def = data.budgets.defaults || {};
@@ -1655,7 +2047,7 @@ var __defProp = Object.defineProperty;
1655
2047
  return false;
1656
2048
  };
1657
2049
  const inputBox = (key, _label, title, width, placeholder, onCommit) => {
1658
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2050
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1659
2051
  NInput,
1660
2052
  {
1661
2053
  type: "number",
@@ -1687,9 +2079,9 @@ var __defProp = Object.defineProperty;
1687
2079
  const effNote = layers.map((l) => eff[l[0]] || "?").join(" / ");
1688
2080
  const rowLabel = (key) => key === "extract" ? "抽取输出" : key === "dedup" ? "去重输出" : key === "l2" ? "L2 输出" : "L3 输出";
1689
2081
  const rowStyle2 = { display: "flex", alignItems: "center", gap: 8 };
1690
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
1691
- showOutputs ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 12 }, children: [
1692
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2082
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
2083
+ showOutputs ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 12 }, children: [
2084
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1693
2085
  "div",
1694
2086
  {
1695
2087
  style: S.switchLabel,
@@ -1697,8 +2089,8 @@ var __defProp = Object.defineProperty;
1697
2089
  children: "输出预算"
1698
2090
  }
1699
2091
  ),
1700
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: layers.map((l) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowStyle2, children: [
1701
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: rowLabel(l[0]) }),
2092
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: layers.map((l) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: rowStyle2, children: [
2093
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: rowLabel(l[0]) }),
1702
2094
  inputBox(
1703
2095
  l[0],
1704
2096
  l[1],
@@ -1707,11 +2099,11 @@ var __defProp = Object.defineProperty;
1707
2099
  def[l[0]],
1708
2100
  commitOutputs
1709
2101
  ),
1710
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
2102
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
1711
2103
  ] }, l[0])) })
1712
2104
  ] }) : null,
1713
- showInput ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 12 }, children: [
1714
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2105
+ showInput ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 12 }, children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1715
2107
  "div",
1716
2108
  {
1717
2109
  style: S.switchLabel,
@@ -1719,8 +2111,8 @@ var __defProp = Object.defineProperty;
1719
2111
  children: "输入预算"
1720
2112
  }
1721
2113
  ),
1722
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowStyle2, children: [
1723
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: "单次输入" }),
2114
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: rowStyle2, children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: "单次输入" }),
1724
2116
  inputBox(
1725
2117
  "input",
1726
2118
  "输入",
@@ -1729,15 +2121,15 @@ var __defProp = Object.defineProperty;
1729
2121
  ib.fallback,
1730
2122
  commitInput
1731
2123
  ),
1732
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
2124
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
1733
2125
  ] }) })
1734
2126
  ] }) : null
1735
2127
  ] });
1736
2128
  }
1737
2129
 
1738
2130
  // client/src/tabs/ChannelEditor.tsx
1739
- var import_react8 = require("react");
1740
- var import_jsx_runtime8 = require("react/jsx-runtime");
2131
+ var import_react9 = require("react");
2132
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1741
2133
  var STY = {
1742
2134
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
1743
2135
  head: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 6 },
@@ -1768,14 +2160,14 @@ var __defProp = Object.defineProperty;
1768
2160
  ];
1769
2161
  function ChannelEditor(props) {
1770
2162
  const { channel, rpc, disabled } = props;
1771
- const [baseText, setBaseText] = (0, import_react8.useState)(channel.runtimeBaseURL);
1772
- const [keyText, setKeyText] = (0, import_react8.useState)("");
1773
- const baseTimer = (0, import_react8.useRef)(void 0);
1774
- const dirty = (0, import_react8.useRef)(false);
1775
- (0, import_react8.useEffect)(() => {
2163
+ const [baseText, setBaseText] = (0, import_react9.useState)(channel.runtimeBaseURL);
2164
+ const [keyText, setKeyText] = (0, import_react9.useState)("");
2165
+ const baseTimer = (0, import_react9.useRef)(void 0);
2166
+ const dirty = (0, import_react9.useRef)(false);
2167
+ (0, import_react9.useEffect)(() => {
1776
2168
  if (!dirty.current) setBaseText(channel.runtimeBaseURL);
1777
2169
  }, [channel.runtimeBaseURL]);
1778
- (0, import_react8.useEffect)(() => () => clearTimeout(baseTimer.current), []);
2170
+ (0, import_react9.useEffect)(() => () => clearTimeout(baseTimer.current), []);
1779
2171
  const commit2 = (patch) => {
1780
2172
  rpc("dsh-memory/settings-set", patch).catch(() => {
1781
2173
  });
@@ -1804,17 +2196,17 @@ var __defProp = Object.defineProperty;
1804
2196
  const deployedDirect = channel.deployed === "direct";
1805
2197
  const apiKeySet = channel.runtimeApiKeySet || channel.deployedApiKeySet;
1806
2198
  const showWarn = isDirect && !channel.directReady;
1807
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY.block, children: [
1808
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY.head, children: [
1809
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY.title, children: "蒸馏通道" }),
1810
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: isDirect ? STY.chipAccent : STY.chipMuted, children: isDirect ? "直连端点" : "复用宿主" }),
1811
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { title: "direct = 插件原生直连 OpenAI 兼容端点,与付费 API 解耦;失败自动回退宿主路由链。", style: { marginLeft: "auto", fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
2199
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.block, children: [
2200
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.head, children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.title, children: "蒸馏通道" }),
2202
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: isDirect ? STY.chipAccent : STY.chipMuted, children: isDirect ? "直连端点" : "复用宿主" }),
2203
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { title: "direct = 插件原生直连 OpenAI 兼容端点,与付费 API 解耦;失败自动回退宿主路由链。", style: { marginLeft: "auto", fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1812
2204
  "生效:",
1813
2205
  runtime ? runtime === "direct" ? "运行时直连" : "运行时宿主" : "跟随部署配置"
1814
2206
  ] })
1815
2207
  ] }),
1816
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
1817
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2208
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1818
2210
  Segmented,
1819
2211
  {
1820
2212
  value: runtime,
@@ -1823,10 +2215,10 @@ var __defProp = Object.defineProperty;
1823
2215
  onChange: (k) => commit2({ distillMode: k })
1824
2216
  }
1825
2217
  ),
1826
- editing ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1827
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY.fieldRow, children: [
1828
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY.fieldLabel, children: "端点 URL" }),
1829
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2218
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2219
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.fieldRow, children: [
2220
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.fieldLabel, children: "端点 URL" }),
2221
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1830
2222
  NInput,
1831
2223
  {
1832
2224
  style: STY.input,
@@ -1843,14 +2235,14 @@ var __defProp = Object.defineProperty;
1843
2235
  }
1844
2236
  }
1845
2237
  ),
1846
- deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
2238
+ deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1847
2239
  "部署基线:",
1848
2240
  channel.deployedBaseURL || "(空)"
1849
2241
  ] }) : null
1850
2242
  ] }),
1851
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY.fieldRow, children: [
1852
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY.fieldLabel, children: "API Key" }),
1853
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2243
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.fieldRow, children: [
2244
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.fieldLabel, children: "API Key" }),
2245
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1854
2246
  NInput,
1855
2247
  {
1856
2248
  style: STY.input,
@@ -1866,8 +2258,8 @@ var __defProp = Object.defineProperty;
1866
2258
  onBlur: commitKey
1867
2259
  }
1868
2260
  ),
1869
- apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY.chipAccent, children: "已配置" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY.chipMuted, children: "未配置" }),
1870
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2261
+ apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.chipAccent, children: "已配置" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.chipMuted, children: "未配置" }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1871
2263
  NButton,
1872
2264
  {
1873
2265
  disabled,
@@ -1877,30 +2269,30 @@ var __defProp = Object.defineProperty;
1877
2269
  }
1878
2270
  )
1879
2271
  ] }),
1880
- showWarn ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY.warn, children: "⚠ direct 未配置完整:需同时有端点 URL 与模型(llm.model / 全局链主路由),否则会回退宿主路由。" }) : null
1881
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY.preview, children: isDirect ? "当前将直连端点:" + (channel.runtimeBaseURL || channel.deployedBaseURL || "(未配置端点)") + (apiKeySet ? " · 密钥已配置" : " · 未配置密钥") : "当前复用宿主 ctx.llm(" + (runtime === "host" ? "运行时锁定" : "跟随部署配置") + ")" })
2272
+ showWarn ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.warn, children: "⚠ direct 未配置完整:需同时有端点 URL 与模型(llm.model / 全局链主路由),否则会回退宿主路由。" }) : null
2273
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.preview, children: isDirect ? "当前将直连端点:" + (channel.runtimeBaseURL || channel.deployedBaseURL || "(未配置端点)") + (apiKeySet ? " · 密钥已配置" : " · 未配置密钥") : "当前复用宿主 ctx.llm(" + (runtime === "host" ? "运行时锁定" : "跟随部署配置") + ")" })
1882
2274
  ] });
1883
2275
  }
1884
2276
 
1885
2277
  // client/src/tabs/RouteChainEditor.tsx
1886
- var import_react10 = require("react");
2278
+ var import_react11 = require("react");
1887
2279
 
1888
2280
  // client/src/ui/NSel.tsx
1889
- var import_react9 = require("react");
1890
- var import_jsx_runtime9 = require("react/jsx-runtime");
2281
+ var import_react10 = require("react");
2282
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1891
2283
  function NSel(props) {
1892
2284
  const options = props.options || [];
1893
2285
  const value = props.value || "";
1894
2286
  const disabled = !!props.disabled;
1895
- const [open, setOpen] = (0, import_react9.useState)(false);
1896
- const [idx, setIdx] = (0, import_react9.useState)(-1);
1897
- const wrapRef = (0, import_react9.useRef)(null);
1898
- const listRef = (0, import_react9.useRef)(null);
2287
+ const [open, setOpen] = (0, import_react10.useState)(false);
2288
+ const [idx, setIdx] = (0, import_react10.useState)(-1);
2289
+ const wrapRef = (0, import_react10.useRef)(null);
2290
+ const listRef = (0, import_react10.useRef)(null);
1899
2291
  let selectedLabel = "";
1900
2292
  for (let si = 0; si < options.length; si++) {
1901
2293
  if (options[si].id === value) selectedLabel = options[si].label;
1902
2294
  }
1903
- (0, import_react9.useEffect)(() => {
2295
+ (0, import_react10.useEffect)(() => {
1904
2296
  if (!open) return void 0;
1905
2297
  const onDown = (e) => {
1906
2298
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -1910,7 +2302,7 @@ var __defProp = Object.defineProperty;
1910
2302
  document.removeEventListener("mousedown", onDown);
1911
2303
  };
1912
2304
  }, [open]);
1913
- (0, import_react9.useEffect)(() => {
2305
+ (0, import_react10.useEffect)(() => {
1914
2306
  if (!open || !listRef.current) return;
1915
2307
  const el = listRef.current.querySelector('[data-active="1"]');
1916
2308
  if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
@@ -1973,8 +2365,8 @@ var __defProp = Object.defineProperty;
1973
2365
  const to = e.relatedTarget;
1974
2366
  if (!to || wrapRef.current && !wrapRef.current.contains(to)) setOpen(false);
1975
2367
  };
1976
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-mem-sel", style: props.style, ref: wrapRef, onKeyDown: onKey, onBlur, children: [
1977
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2368
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-sel", style: props.style, ref: wrapRef, onKeyDown: onKey, onBlur, children: [
2369
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1978
2370
  "button",
1979
2371
  {
1980
2372
  type: "button",
@@ -1990,13 +2382,13 @@ var __defProp = Object.defineProperty;
1990
2382
  }
1991
2383
  },
1992
2384
  children: [
1993
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-select-label", children: selectedLabel || props.placeholder || "(请选择)" }),
1994
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : ""), "aria-hidden": true })
2385
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-select-label", children: selectedLabel || props.placeholder || "(请选择)" }),
2386
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : ""), "aria-hidden": true })
1995
2387
  ]
1996
2388
  }
1997
2389
  ),
1998
- open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-pop", ref: listRef, role: "listbox", children: options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-pop-empty", children: "无选项" }) : options.map((o, i) => {
1999
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2390
+ open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-pop", ref: listRef, role: "listbox", children: options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-pop-empty", children: "无选项" }) : options.map((o, i) => {
2391
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2000
2392
  "button",
2001
2393
  {
2002
2394
  type: "button",
@@ -2014,8 +2406,8 @@ var __defProp = Object.defineProperty;
2014
2406
  if (idx !== i) setIdx(i);
2015
2407
  },
2016
2408
  children: [
2017
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-pop-opt-label", children: o.label }),
2018
- o.id === value ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-pop-check", children: "✓" }) : null
2409
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-pop-opt-label", children: o.label }),
2410
+ o.id === value ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-pop-check", children: "✓" }) : null
2019
2411
  ]
2020
2412
  },
2021
2413
  o.id
@@ -2025,7 +2417,7 @@ var __defProp = Object.defineProperty;
2025
2417
  }
2026
2418
 
2027
2419
  // client/src/tabs/RouteChainEditor.tsx
2028
- var import_jsx_runtime10 = require("react/jsx-runtime");
2420
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2029
2421
  var modelsCache = {};
2030
2422
  var EFFORT_VOCAB = ["", "off", "none", "minimal", "low", "medium", "high", "xhigh", "max"];
2031
2423
  var STY2 = {
@@ -2054,26 +2446,26 @@ var __defProp = Object.defineProperty;
2054
2446
  const disabled = !!props.disabled;
2055
2447
  const scope = props.scope ?? "global";
2056
2448
  const isLayer = scope !== "global";
2057
- const [info, setInfo] = (0, import_react10.useState)(null);
2058
- const [rows, setRows] = (0, import_react10.useState)(null);
2059
- const [rowErrs, setRowErrs] = (0, import_react10.useState)({});
2060
- const [err, setErr] = (0, import_react10.useState)(null);
2061
- const [manual, setManual] = (0, import_react10.useState)({ idx: -1, text: "" });
2062
- const pendingWrites = (0, import_react10.useRef)(0);
2449
+ const [info, setInfo] = (0, import_react11.useState)(null);
2450
+ const [rows, setRows] = (0, import_react11.useState)(null);
2451
+ const [rowErrs, setRowErrs] = (0, import_react11.useState)({});
2452
+ const [err, setErr] = (0, import_react11.useState)(null);
2453
+ const [manual, setManual] = (0, import_react11.useState)({ idx: -1, text: "" });
2454
+ const pendingWrites = (0, import_react11.useRef)(0);
2063
2455
  function refreshInfo() {
2064
2456
  rpc("dsh-memory/llm-providers", {}).then((r) => {
2065
2457
  if (r && r.ok && pendingWrites.current === 0) setInfo(r.value);
2066
2458
  }).catch(() => {
2067
2459
  });
2068
2460
  }
2069
- (0, import_react10.useEffect)(() => {
2461
+ (0, import_react11.useEffect)(() => {
2070
2462
  refreshInfo();
2071
2463
  const timer = setInterval(refreshInfo, 5e3);
2072
2464
  return () => {
2073
2465
  clearInterval(timer);
2074
2466
  };
2075
2467
  }, [rpc]);
2076
- (0, import_react10.useEffect)(() => {
2468
+ (0, import_react11.useEffect)(() => {
2077
2469
  if (!info || !info.providers) return;
2078
2470
  info.providers.forEach((p) => {
2079
2471
  if (!p.id || modelsCache[p.id]) return;
@@ -2085,7 +2477,7 @@ var __defProp = Object.defineProperty;
2085
2477
  }, [rpc, info]);
2086
2478
  const layerView = isLayer && info && info.layerChains ? info.layerChains[scope] : null;
2087
2479
  const savedRows = isLayer ? layerView?.runtime ?? [] : info && info.chain ? info.chain.current : [];
2088
- (0, import_react10.useEffect)(() => {
2480
+ (0, import_react11.useEffect)(() => {
2089
2481
  if (rows === null && info && savedRows.length) {
2090
2482
  setRows(savedRows.map(copyRow));
2091
2483
  }
@@ -2233,17 +2625,17 @@ var __defProp = Object.defineProperty;
2233
2625
  providersById[p.id] = p;
2234
2626
  });
2235
2627
  function roRow(e, i) {
2236
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.roRow, children: [
2237
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: STY2.badge, children: i === 0 ? "主" : String(i + 1) }),
2238
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { ...STY2.mono, color: "var(--dsh-mem-text-2)" }, children: e.provider + " / " + e.model }),
2239
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { marginLeft: "auto", flexShrink: 0, fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: e.effort ? "档位 " + e.effort : "跟随部署配置" })
2628
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.roRow, children: [
2629
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY2.badge, children: i === 0 ? "主" : String(i + 1) }),
2630
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...STY2.mono, color: "var(--dsh-mem-text-2)" }, children: e.provider + " / " + e.model }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { marginLeft: "auto", flexShrink: 0, fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: e.effort ? "档位 " + e.effort : "跟随部署配置" })
2240
2632
  ] }, "ro" + i);
2241
2633
  }
2242
2634
  if (info.pinned) {
2243
2635
  const effPin = isLayer ? layerView?.effectiveChain ?? [] : info.chain && info.chain.effectiveChain || [];
2244
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2636
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2245
2637
  effPin.map(roRow),
2246
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
2638
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
2247
2639
  ] });
2248
2640
  }
2249
2641
  if (rows === null) {
@@ -2251,21 +2643,21 @@ var __defProp = Object.defineProperty;
2251
2643
  const lv = layerView;
2252
2644
  const src = lv?.source ?? "global";
2253
2645
  if (src === "static" && lv) {
2254
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2646
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2255
2647
  lv.static.map((e, i) => roRow({ provider: e.provider, model: e.model, effort: e.reasoningEffort || "" }, i)),
2256
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2648
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2257
2649
  ] });
2258
2650
  }
2259
2651
  const previewRows = lv?.effectiveChain ?? [];
2260
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2261
- previewRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.switchDesc, children: "本层跟随全局链,暂无可用路由。" }) : previewRows.map(roRow),
2262
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2652
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2653
+ previewRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.switchDesc, children: "本层跟随全局链,暂无可用路由。" }) : previewRows.map(roRow),
2654
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2263
2655
  ] });
2264
2656
  }
2265
2657
  const effFollow = info.chain && info.chain.effectiveChain || [];
2266
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2267
- effFollow.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.switchDesc, children: "蒸馏跟随默认模型,未配置回退链。" }) : effFollow.map(roRow),
2268
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: forkStatic, disabled, children: "编辑为运行时链" }) })
2658
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2659
+ effFollow.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.switchDesc, children: "蒸馏跟随默认模型,未配置回退链。" }) : effFollow.map(roRow),
2660
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "编辑为运行时链" }) })
2269
2661
  ] });
2270
2662
  }
2271
2663
  const capped = rows.length >= 8;
@@ -2306,10 +2698,10 @@ var __defProp = Object.defineProperty;
2306
2698
  const effortOptions = [{ id: "", label: "跟随部署配置" }].concat(
2307
2699
  curEfforts.filter((k) => EFFORT_VOCAB.indexOf(k) >= 0).map((k) => ({ id: k, label: k }))
2308
2700
  );
2309
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { ...STY2.row, ...rowErrs[i] ? STY2.rowErr : null }, children: [
2310
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.line, children: [
2311
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: STY2.badge, children: isPrimary ? "主" : String(i + 1) }),
2312
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2701
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...STY2.row, ...rowErrs[i] ? STY2.rowErr : null }, children: [
2702
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.line, children: [
2703
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY2.badge, children: isPrimary ? "主" : String(i + 1) }),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2313
2705
  NSel,
2314
2706
  {
2315
2707
  style: { flex: 1, minWidth: 150 },
@@ -2322,7 +2714,7 @@ var __defProp = Object.defineProperty;
2322
2714
  }
2323
2715
  }
2324
2716
  ),
2325
- !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2717
+ !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2326
2718
  NInput,
2327
2719
  {
2328
2720
  style: { flex: 1, minWidth: 150 },
@@ -2341,7 +2733,7 @@ var __defProp = Object.defineProperty;
2341
2733
  }
2342
2734
  }
2343
2735
  }
2344
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2736
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2345
2737
  NSel,
2346
2738
  {
2347
2739
  style: { flex: 1, minWidth: 150 },
@@ -2354,7 +2746,7 @@ var __defProp = Object.defineProperty;
2354
2746
  }
2355
2747
  }
2356
2748
  ),
2357
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2749
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2358
2750
  NSel,
2359
2751
  {
2360
2752
  style: { flexShrink: 0, width: 118 },
@@ -2368,8 +2760,8 @@ var __defProp = Object.defineProperty;
2368
2760
  }
2369
2761
  )
2370
2762
  ] }),
2371
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.actions, children: [
2372
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2763
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.actions, children: [
2764
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2373
2765
  NButton,
2374
2766
  {
2375
2767
  style: STY2.ico,
@@ -2381,7 +2773,7 @@ var __defProp = Object.defineProperty;
2381
2773
  children: "↑"
2382
2774
  }
2383
2775
  ),
2384
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2776
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2385
2777
  NButton,
2386
2778
  {
2387
2779
  style: STY2.ico,
@@ -2393,7 +2785,7 @@ var __defProp = Object.defineProperty;
2393
2785
  children: "↓"
2394
2786
  }
2395
2787
  ),
2396
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2788
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2397
2789
  NButton,
2398
2790
  {
2399
2791
  style: STY2.ico,
@@ -2406,14 +2798,14 @@ var __defProp = Object.defineProperty;
2406
2798
  }
2407
2799
  )
2408
2800
  ] }),
2409
- isPrimary && !row2.provider ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: STY2.note, children: "跟随默认模型" + (info.default ? ":" + info.default.provider + " / " + info.default.model : "") + "(档位跟随部署配置,选定模型后可单独设置)" }) : null,
2410
- !known ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: STY2.warn, children: "⚠ 供应商 " + row2.provider + " 已不在已注册路由中:该路由调用会失败并被链跳过(不阻止保存)。" }) : null,
2411
- rowErrs[i] ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: STY2.warn, children: "✕ " + rowErrs[i] }) : null
2801
+ isPrimary && !row2.provider ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.note, children: "跟随默认模型" + (info.default ? ":" + info.default.provider + " / " + info.default.model : "") + "(档位跟随部署配置,选定模型后可单独设置)" }) : null,
2802
+ !known ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.warn, children: "⚠ 供应商 " + row2.provider + " 已不在已注册路由中:该路由调用会失败并被链跳过(不阻止保存)。" }) : null,
2803
+ rowErrs[i] ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.warn, children: "✕ " + rowErrs[i] }) : null
2412
2804
  ] }, "row" + i);
2413
2805
  });
2414
2806
  const effChain = isLayer ? layerView?.effectiveChain ?? [] : info.chain && info.chain.effectiveChain || [];
2415
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2416
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2807
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2808
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2417
2809
  "div",
2418
2810
  {
2419
2811
  style: { ...S.switchDesc, marginBottom: 8 },
@@ -2422,9 +2814,9 @@ var __defProp = Object.defineProperty;
2422
2814
  }
2423
2815
  ),
2424
2816
  rowEls,
2425
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { style: STY2.add, disabled: disabled || capped, onClick: addRow, children: capped ? "已达上限(8 条)" : "+ 添加回退路由" }),
2426
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
2427
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2817
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { style: STY2.add, disabled: disabled || capped, onClick: addRow, children: capped ? "已达上限(8 条)" : "+ 添加回退路由" }),
2818
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
2819
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2428
2820
  NButton,
2429
2821
  {
2430
2822
  style: isLayer ? { ...STY2.ghost, color: "var(--dsh-mem-danger)", border: "1px solid var(--dsh-mem-danger)" } : STY2.ghost,
@@ -2433,13 +2825,13 @@ var __defProp = Object.defineProperty;
2433
2825
  children: isLayer ? "清除自定义 · 跟随全局" : "清空并跟随部署配置"
2434
2826
  }
2435
2827
  ),
2436
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.grow }),
2437
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { variant: "primary", disabled, onClick: save, children: "保存" })
2828
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.grow }),
2829
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { variant: "primary", disabled, onClick: save, children: "保存" })
2438
2830
  ] }),
2439
- err ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { ...STY2.warn, marginTop: 8 }, children: "✕ " + err }) : null,
2440
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
2441
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 4 }, children: "实际链" + (dirty ? "(保存后更新;当前显示已保存值)" : "") }),
2442
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2831
+ err ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { ...STY2.warn, marginTop: 8 }, children: "✕ " + err }) : null,
2832
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
2833
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 4 }, children: "实际链" + (dirty ? "(保存后更新;当前显示已保存值)" : "") }),
2834
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2443
2835
  "div",
2444
2836
  {
2445
2837
  style: { fontSize: 12, color: "var(--dsh-mem-text-2)", wordBreak: "break-all", fontFamily: "ui-monospace, SFMono-Regular, Consolas, monospace" },
@@ -2451,7 +2843,7 @@ var __defProp = Object.defineProperty;
2451
2843
  }
2452
2844
 
2453
2845
  // client/src/tabs/DistillSettings.tsx
2454
- var import_jsx_runtime11 = require("react/jsx-runtime");
2846
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2455
2847
  var STY3 = {
2456
2848
  hint: { fontSize: 11, color: "var(--dsh-mem-text-3)", margin: "0 0 8px" },
2457
2849
  panelHead: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 8 },
@@ -2480,9 +2872,9 @@ var __defProp = Object.defineProperty;
2480
2872
  verticalAlign: "middle",
2481
2873
  flexShrink: 0
2482
2874
  };
2483
- if (props.kind === "runtime") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...base, background: "var(--dsh-mem-accent)" } });
2484
- if (props.kind === "static") return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...base, background: "transparent", border: "1.5px solid var(--dsh-mem-text-3)" } });
2485
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...base, background: "var(--dsh-mem-track)" } });
2875
+ if (props.kind === "runtime") return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...base, background: "var(--dsh-mem-accent)" } });
2876
+ if (props.kind === "static") return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...base, background: "transparent", border: "1.5px solid var(--dsh-mem-text-3)" } });
2877
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...base, background: "var(--dsh-mem-track)" } });
2486
2878
  }
2487
2879
  var LAYER_META = {
2488
2880
  l1: { seg: "L1", title: "L1 · 抽取 / 去重" },
@@ -2492,9 +2884,9 @@ var __defProp = Object.defineProperty;
2492
2884
  function DistillSettings(props) {
2493
2885
  const rpc = props.rpc;
2494
2886
  const disabled = !!props.disabled;
2495
- const [info, setInfo] = (0, import_react11.useState)(null);
2496
- const [tab, setTab] = (0, import_react11.useState)("g");
2497
- (0, import_react11.useEffect)(() => {
2887
+ const [info, setInfo] = (0, import_react12.useState)(null);
2888
+ const [tab, setTab] = (0, import_react12.useState)("g");
2889
+ (0, import_react12.useEffect)(() => {
2498
2890
  let alive = true;
2499
2891
  const refresh = () => {
2500
2892
  rpc("dsh-memory/llm-providers", {}).then((r) => {
@@ -2517,46 +2909,46 @@ var __defProp = Object.defineProperty;
2517
2909
  ...["l1", "l2", "l3"].map((k) => ({
2518
2910
  key: k,
2519
2911
  title: LAYER_META[k].title + " · " + (dotOf(k) === "runtime" ? "运行时自定义" : dotOf(k) === "static" ? "部署 YAML 层链(只读)" : "跟随全局"),
2520
- label: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
2521
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: dotOf(k) }),
2912
+ label: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: dotOf(k) }),
2522
2914
  LAYER_META[k].seg
2523
2915
  ] })
2524
2916
  }))
2525
2917
  ];
2526
2918
  const chipTitle = (k) => dotOf(k) === "runtime" ? "本层走设置页自定义链" : dotOf(k) === "static" ? "本层走部署 YAML 层链(UI 只读,自定义可覆盖)" : "本层未单独配置,走全局默认链";
2527
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2528
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Segmented, { value: tab, options: segOptions, onChange: (k) => setTab(k) }),
2529
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY3.hint, children: [
2530
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: "runtime" }),
2919
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2920
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Segmented, { value: tab, options: segOptions, onChange: (k) => setTab(k) }),
2921
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.hint, children: [
2922
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "runtime" }),
2531
2923
  " 自定义 · ",
2532
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: "static" }),
2924
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "static" }),
2533
2925
  " 部署 YAML · ",
2534
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: "global" }),
2926
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "global" }),
2535
2927
  " 跟随全局",
2536
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2928
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2537
2929
  ] }),
2538
- tab === "g" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2539
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY3.panelHead, children: [
2540
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY3.panelTitle, children: "全局默认链" }),
2541
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...STY3.chip, ...STY3.chipAccent }, children: "运行时 · 可编辑" }),
2542
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...STY3.inUse, marginLeft: "auto" }, children: users.length ? "在用:" + users.map((k) => LAYER_META[k].seg).join("、") : "当前无层使用" })
2930
+ tab === "g" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2931
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.panelHead, children: [
2932
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: STY3.panelTitle, children: "全局默认链" }),
2933
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...STY3.chip, ...STY3.chipAccent }, children: "运行时 · 可编辑" }),
2934
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...STY3.inUse, marginLeft: "auto" }, children: users.length ? "在用:" + users.map((k) => LAYER_META[k].seg).join("、") : "当前无层使用" })
2543
2935
  ] }),
2544
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RouteChainEditor, { rpc, disabled }, "g"),
2545
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: "input" }, "g-budget"),
2546
- info?.channel ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChannelEditor, { channel: info.channel, rpc, disabled }) : null
2547
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2548
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY3.panelHead, children: [
2549
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY3.panelTitle, children: LAYER_META[tab].title }),
2550
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...STY3.chip, ...dotOf(tab) === "runtime" ? STY3.chipAccent : STY3.chipMuted }, title: chipTitle(tab), children: dotOf(tab) === "runtime" ? "运行时自定义" : dotOf(tab) === "static" ? "静态 · YAML" : "跟随全局" })
2936
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RouteChainEditor, { rpc, disabled }, "g"),
2937
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: "input" }, "g-budget"),
2938
+ info?.channel ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChannelEditor, { channel: info.channel, rpc, disabled }) : null
2939
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2940
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.panelHead, children: [
2941
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: STY3.panelTitle, children: LAYER_META[tab].title }),
2942
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...STY3.chip, ...dotOf(tab) === "runtime" ? STY3.chipAccent : STY3.chipMuted }, title: chipTitle(tab), children: dotOf(tab) === "runtime" ? "运行时自定义" : dotOf(tab) === "static" ? "静态 · YAML" : "跟随全局" })
2551
2943
  ] }),
2552
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RouteChainEditor, { rpc, disabled, scope: tab }, tab),
2553
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: tab }, tab + "-budget")
2944
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RouteChainEditor, { rpc, disabled, scope: tab }, tab),
2945
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: tab }, tab + "-budget")
2554
2946
  ] })
2555
2947
  ] });
2556
2948
  }
2557
2949
 
2558
2950
  // client/src/tabs/EmbeddingSection.tsx
2559
- var import_react12 = require("react");
2951
+ var import_react13 = require("react");
2560
2952
 
2561
2953
  // client/src/dimensions.ts
2562
2954
  var DIMS_MIN = 1;
@@ -2604,7 +2996,7 @@ var __defProp = Object.defineProperty;
2604
2996
  }
2605
2997
 
2606
2998
  // client/src/tabs/EmbeddingSection.tsx
2607
- var import_jsx_runtime12 = require("react/jsx-runtime");
2999
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2608
3000
  var RSTY = {
2609
3001
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
2610
3002
  title: { fontSize: 12, fontWeight: 600, color: "var(--dsh-mem-text-3)", margin: "0 0 2px" },
@@ -2628,17 +3020,17 @@ var __defProp = Object.defineProperty;
2628
3020
  function EmbeddingSection(props) {
2629
3021
  const rpc = props.rpc;
2630
3022
  const loose = asLoose(rpc);
2631
- const [st, setSt] = (0, import_react12.useState)(null);
2632
- const [err, setErr] = (0, import_react12.useState)(null);
2633
- const busyPollRef = (0, import_react12.useRef)(null);
2634
- const [rBase, setRBase] = (0, import_react12.useState)("");
2635
- const [rModel, setRModel] = (0, import_react12.useState)("");
2636
- const [rDims, setRDims] = (0, import_react12.useState)("");
2637
- const [rKey, setRKey] = (0, import_react12.useState)("");
2638
- const remoteDirty = (0, import_react12.useRef)({ base: false, model: false, dims: false });
2639
- const baseTimer = (0, import_react12.useRef)(void 0);
2640
- const modelTimer = (0, import_react12.useRef)(void 0);
2641
- const load = (0, import_react12.useCallback)(() => {
3023
+ const [st, setSt] = (0, import_react13.useState)(null);
3024
+ const [err, setErr] = (0, import_react13.useState)(null);
3025
+ const busyPollRef = (0, import_react13.useRef)(null);
3026
+ const [rBase, setRBase] = (0, import_react13.useState)("");
3027
+ const [rModel, setRModel] = (0, import_react13.useState)("");
3028
+ const [rDims, setRDims] = (0, import_react13.useState)("");
3029
+ const [rKey, setRKey] = (0, import_react13.useState)("");
3030
+ const remoteDirty = (0, import_react13.useRef)({ base: false, model: false, dims: false });
3031
+ const baseTimer = (0, import_react13.useRef)(void 0);
3032
+ const modelTimer = (0, import_react13.useRef)(void 0);
3033
+ const load = (0, import_react13.useCallback)(() => {
2642
3034
  rpc("dsh-memory/embedding-state-get", {}).then((r) => {
2643
3035
  if (r && r.ok && r.value && r.value.supported !== false) {
2644
3036
  const v = r.value;
@@ -2657,10 +3049,10 @@ var __defProp = Object.defineProperty;
2657
3049
  setErr(String(e && e.message || e));
2658
3050
  });
2659
3051
  }, [rpc]);
2660
- (0, import_react12.useEffect)(() => {
3052
+ (0, import_react13.useEffect)(() => {
2661
3053
  load();
2662
3054
  }, [load]);
2663
- (0, import_react12.useEffect)(() => {
3055
+ (0, import_react13.useEffect)(() => {
2664
3056
  let stopped = false;
2665
3057
  const busyFlag = { v: false };
2666
3058
  busyPollRef.current = busyFlag;
@@ -2676,11 +3068,11 @@ var __defProp = Object.defineProperty;
2676
3068
  busyPollRef.current = null;
2677
3069
  };
2678
3070
  }, [load]);
2679
- (0, import_react12.useEffect)(() => () => {
3071
+ (0, import_react13.useEffect)(() => () => {
2680
3072
  clearTimeout(baseTimer.current);
2681
3073
  clearTimeout(modelTimer.current);
2682
3074
  }, []);
2683
- (0, import_react12.useEffect)(() => {
3075
+ (0, import_react13.useEffect)(() => {
2684
3076
  if (!st || !st.remote) return;
2685
3077
  if (!remoteDirty.current.base) setRBase(st.remote.baseURL || "");
2686
3078
  if (!remoteDirty.current.model) setRModel(st.remote.model || "");
@@ -2728,7 +3120,7 @@ var __defProp = Object.defineProperty;
2728
3120
  if (v) commitRemote({ embedRemoteApiKey: v });
2729
3121
  setRKey("");
2730
3122
  };
2731
- const call = (endpoint, payload, confirmText) => {
3123
+ const call2 = (endpoint, payload, confirmText) => {
2732
3124
  if (confirmText && !window.confirm(confirmText)) return;
2733
3125
  loose(endpoint, payload).then((r) => {
2734
3126
  if (!r || !r.ok) setErr(r && r.error ? r.error.message : "操作失败");
@@ -2741,15 +3133,15 @@ var __defProp = Object.defineProperty;
2741
3133
  });
2742
3134
  };
2743
3135
  if (err === "__unsupported__") {
2744
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2745
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "语义检索(嵌入)" }),
2746
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", children: "存储处于降级状态,嵌入管理不可用。" })
3136
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3137
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "语义检索(嵌入)" }),
3138
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: "存储处于降级状态,嵌入管理不可用。" })
2747
3139
  ] });
2748
3140
  }
2749
3141
  if (!st) {
2750
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2751
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", children: err ? "嵌入状态读取失败:" + err : "嵌入状态读取中…" }),
2752
- err ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { style: { marginTop: 8 }, onClick: load, children: "重试" }) : null
3142
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3143
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: err ? "嵌入状态读取失败:" + err : "嵌入状态读取中…" }),
3144
+ err ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { style: { marginTop: 8 }, onClick: load, children: "重试" }) : null
2753
3145
  ] });
2754
3146
  }
2755
3147
  const switchConfirm = "切换嵌入源后将按新模型重建向量索引(期间语义检索暂退化为关键词匹配,不影响对话)。确定切换?";
@@ -2762,10 +3154,10 @@ var __defProp = Object.defineProperty;
2762
3154
  return;
2763
3155
  }
2764
3156
  const current = st.activeModel && ready.indexOf(st.activeModel) >= 0 ? st.activeModel : ready[0];
2765
- call("dsh-memory/embedding-source-set", { source: "local", activeModel: current }, switchConfirm);
3157
+ call2("dsh-memory/embedding-source-set", { source: "local", activeModel: current }, switchConfirm);
2766
3158
  return;
2767
3159
  }
2768
- call("dsh-memory/embedding-source-set", { source: key }, key === "remote" ? switchConfirm : null);
3160
+ call2("dsh-memory/embedding-source-set", { source: key }, key === "remote" ? switchConfirm : null);
2769
3161
  };
2770
3162
  const dl = st.download;
2771
3163
  const dlActive = dl && (dl.phase === "downloading" || dl.phase === "verifying");
@@ -2775,40 +3167,40 @@ var __defProp = Object.defineProperty;
2775
3167
  const remote = st.remote;
2776
3168
  let runtimeRow = null;
2777
3169
  if (rt.phase === "installing") {
2778
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { marginTop: 8, fontSize: 12 }, children: [
2779
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2780
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "安装推理运行时中… 已耗时 " + Math.round(rt.elapsedMs / 1e3) + "s(约 100~200MB,视网络)" }),
2781
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.grow }),
2782
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-runtime-cancel", {}), children: "取消" })
3170
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginTop: 8, fontSize: 12 }, children: [
3171
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3172
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "安装推理运行时中… 已耗时 " + Math.round(rt.elapsedMs / 1e3) + "s(约 100~200MB,视网络)" }),
3173
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3174
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-runtime-cancel", {}), children: "取消" })
2783
3175
  ] }),
2784
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { style: { ...S.pre, maxHeight: 68, marginTop: 6, fontSize: 11, opacity: 0.85 }, children: (rt.lastLines || []).join("\n") || "等待 npm 输出…" })
3176
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { style: { ...S.pre, maxHeight: 68, marginTop: 6, fontSize: 11, opacity: 0.85 }, children: (rt.lastLines || []).join("\n") || "等待 npm 输出…" })
2785
3177
  ] });
2786
3178
  } else if (rt.phase === "error") {
2787
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "运行时安装失败:" + (rt.error || "未知") + "(重新切换嵌入源可重试)" });
3179
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "运行时安装失败:" + (rt.error || "未知") + "(重新切换嵌入源可重试)" });
2788
3180
  } else if (rt.phase === "ready") {
2789
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "推理运行时就绪(transformers.js v" + rt.installedVersion + ")" });
3181
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "推理运行时就绪(transformers.js v" + rt.installedVersion + ")" });
2790
3182
  } else if (st.source === "local") {
2791
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "首次启用本地嵌入时会自动安装推理运行时(约 100~200MB)。" });
3183
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "首次启用本地嵌入时会自动安装推理运行时(约 100~200MB)。" });
2792
3184
  }
2793
3185
  let applyRow = null;
2794
3186
  if (ap.phase === "warming") {
2795
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
3187
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
2796
3188
  } else if (ap.phase === "switching") {
2797
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
3189
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
2798
3190
  } else if (ap.phase === "error") {
2799
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "切换失败:" + ap.message + "(已保存的嵌入源不变,重启后仍按原源运行)" });
3191
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "切换失败:" + ap.message + "(已保存的嵌入源不变,重启后仍按原源运行)" });
2800
3192
  } else if (st.reindex && st.reindex.running) {
2801
3193
  const rj = st.reindex;
2802
3194
  const rDone = rj.l1Done + rj.l0Done;
2803
3195
  const rTotal = rj.l1Total + rj.l0Total;
2804
3196
  const rPct = rTotal > 0 ? Math.round(rDone / rTotal * 100) : 0;
2805
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { marginTop: 8 }, children: [
2806
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2807
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-rb-muted", children: "重嵌入中 L1 " + rj.l1Done + "/" + rj.l1Total + " · L0 " + rj.l0Done + "/" + rj.l0Total + "(" + rPct + "%)" }),
2808
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.grow }),
2809
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-reindex-cancel", {}), children: "取消" })
3197
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginTop: 8 }, children: [
3198
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3199
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "重嵌入中 L1 " + rj.l1Done + "/" + rj.l1Total + " · L0 " + rj.l0Done + "/" + rj.l0Total + "(" + rPct + "%)" }),
3200
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3201
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-reindex-cancel", {}), children: "取消" })
2810
3202
  ] }),
2811
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: rPct + "%" } }) }) })
3203
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: rPct + "%" } }) }) })
2812
3204
  ] });
2813
3205
  }
2814
3206
  const modelCards = st.models.map((m) => {
@@ -2817,61 +3209,61 @@ var __defProp = Object.defineProperty;
2817
3209
  const pct = mDl && dl.overallTotal > 0 ? Math.round(dl.overallReceived / dl.overallTotal * 100) : 0;
2818
3210
  let action;
2819
3211
  if (mDl) {
2820
- action = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { flex: 1, minWidth: 200 }, children: [
2821
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2822
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: (dl.phase === "verifying" ? "校验中 " : "") + fmtMB(dl.overallReceived) + " / " + fmtMB(dl.overallTotal) + "(文件 " + dl.fileIndex + "/" + dl.fileCount + "," + pct + "%" + (dl.speedBps > 0 && dl.phase === "downloading" ? "," + fmtMB(dl.speedBps) + "/s" : "") + ")" }),
2823
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.grow }),
2824
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-download-cancel", {}), children: "取消" })
3212
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { flex: 1, minWidth: 200 }, children: [
3213
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3214
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: (dl.phase === "verifying" ? "校验中 " : "") + fmtMB(dl.overallReceived) + " / " + fmtMB(dl.overallTotal) + "(文件 " + dl.fileIndex + "/" + dl.fileCount + "," + pct + "%" + (dl.speedBps > 0 && dl.phase === "downloading" ? "," + fmtMB(dl.speedBps) + "/s" : "") + ")" }),
3215
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3216
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-download-cancel", {}), children: "取消" })
2825
3217
  ] }),
2826
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }) })
3218
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }) })
2827
3219
  ] });
2828
3220
  } else if (isActive) {
2829
- action = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2830
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-task", children: "使用中" }),
2831
- localInfo && localInfo.state === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-rb-muted", children: "模型加载中…" }) : null,
2832
- localInfo && localInfo.state === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "加载失败:" + (localInfo.error || "") }) : null,
2833
- localInfo && localInfo.state === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-rb-muted", children: "已就绪" }) : null
3221
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3222
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-task", children: "使用中" }),
3223
+ localInfo && localInfo.state === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "模型加载中…" }) : null,
3224
+ localInfo && localInfo.state === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "加载失败:" + (localInfo.error || "") }) : null,
3225
+ localInfo && localInfo.state === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "已就绪" }) : null
2834
3226
  ] });
2835
3227
  } else if (m.state === "downloaded") {
2836
- action = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2837
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3228
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3229
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2838
3230
  NButton,
2839
3231
  {
2840
3232
  disabled: ap.busy,
2841
- onClick: () => call("dsh-memory/embedding-source-set", { source: "local", activeModel: m.id }, switchConfirm),
3233
+ onClick: () => call2("dsh-memory/embedding-source-set", { source: "local", activeModel: m.id }, switchConfirm),
2842
3234
  children: "启用"
2843
3235
  }
2844
3236
  ),
2845
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3237
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2846
3238
  NButton,
2847
3239
  {
2848
3240
  disabled: dlActive,
2849
- onClick: () => call("dsh-memory/embedding-model-delete", { modelId: m.id }, "删除已下载的 " + m.name + "(" + fmtMB(m.totalBytes) + ")?"),
3241
+ onClick: () => call2("dsh-memory/embedding-model-delete", { modelId: m.id }, "删除已下载的 " + m.name + "(" + fmtMB(m.totalBytes) + ")?"),
2850
3242
  children: "删除"
2851
3243
  }
2852
3244
  )
2853
3245
  ] });
2854
3246
  } else {
2855
- action = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3247
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2856
3248
  NButton,
2857
3249
  {
2858
3250
  disabled: dlActive || !st.ceilings.local,
2859
3251
  title: !st.ceilings.local ? "部署已禁用本地嵌入模型" : "",
2860
- onClick: () => call("dsh-memory/embedding-download-start", { modelId: m.id }),
3252
+ onClick: () => call2("dsh-memory/embedding-download-start", { modelId: m.id }),
2861
3253
  children: (m.state === "partial" ? "继续下载 " : "下载 ") + fmtMB(m.totalBytes)
2862
3254
  }
2863
3255
  );
2864
3256
  }
2865
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3257
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2866
3258
  "div",
2867
3259
  {
2868
3260
  style: { ...S.flexRow, padding: "8px 0", borderBottom: "1px solid var(--dsh-mem-border)", flexWrap: "wrap" },
2869
3261
  children: [
2870
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { minWidth: 150 }, children: [
2871
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontWeight: 600 }, children: m.name }),
2872
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", children: m.tags.join(" · ") + " · " + m.dims + " 维 · 上下文 " + m.contextTokens })
3262
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { minWidth: 150 }, children: [
3263
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600 }, children: m.name }),
3264
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: m.tags.join(" · ") + " · " + m.dims + " 维 · 上下文 " + m.contextTokens })
2873
3265
  ] }),
2874
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
3266
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
2875
3267
  action
2876
3268
  ]
2877
3269
  },
@@ -2880,15 +3272,17 @@ var __defProp = Object.defineProperty;
2880
3272
  });
2881
3273
  const vec = st.vectors;
2882
3274
  const vecOk = !!vec && vec.l1.embedded >= 0 && vec.l0.embedded >= 0;
2883
- const vecNote = !vec ? "向量索引:宿主版本较旧,未上报计数" : !vecOk ? "向量索引不可用(sqlite-vec 扩展缺失或检索库降级),重建无从谈起" : "已嵌入 L1 " + vec.l1.embedded + "/" + vec.l1.total + " · L0 " + vec.l0.embedded + "/" + vec.l0.total + (vec.l1.missing + vec.l0.missing > 0 ? "(待补 " + (vec.l1.missing + vec.l0.missing) + " 条)" : "") + (vec.l1.skipped + vec.l0.skipped > 0 ? "(" + (vec.l1.skipped + vec.l0.skipped) + " 条内容不可嵌入,已跳过)" : "");
3275
+ const lastRun = st.reindex ? st.reindex.last : void 0;
3276
+ const lastNote = !lastRun ? "" : " · 上次重建:处理 " + lastRun.processed + "/" + lastRun.planned + " 条" + (lastRun.failed > 0 ? "、失败 " + lastRun.failed : "") + (lastRun.cancelled ? "(被取消)" : "") + ",待补 " + (lastRun.missingBefore.l1 + lastRun.missingBefore.l0) + " → " + (lastRun.missingAfter.l1 + lastRun.missingAfter.l0) + ",用时 " + (lastRun.durationMs / 1e3).toFixed(1) + "s";
3277
+ const vecNote = !vec ? "向量索引:宿主版本较旧,未上报计数" : !vecOk ? "向量索引不可用(sqlite-vec 扩展缺失或检索库降级),重建无从谈起" : "已嵌入 L1 " + vec.l1.embedded + "/" + vec.l1.total + " · L0 " + vec.l0.embedded + "/" + vec.l0.total + (vec.l1.missing + vec.l0.missing > 0 ? "(待补 " + (vec.l1.missing + vec.l0.missing) + " 条)" : "") + (vec.l1.skipped + vec.l0.skipped > 0 ? "(" + (vec.l1.skipped + vec.l0.skipped) + " 条内容不可嵌入,已跳过)" : "") + lastNote;
2884
3278
  const reindexRunning = !!(st.reindex && st.reindex.running);
2885
3279
  const canRebuild = vecOk && st.source !== "off" && !reindexRunning && !st.apply.busy;
2886
3280
  const rebuildHint = !vecOk ? "向量能力不可用" : st.source === "off" ? "嵌入源已关闭,请先启用" : reindexRunning ? "重建已在进行中" : st.apply.busy ? "嵌入源切换进行中" : "只补缺失向量;已有向量不动。零向量内容会被跳过(重试无意义)";
2887
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.flexRow, children: [
2889
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "语义检索(嵌入源)" }),
2890
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.grow }),
2891
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3281
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3282
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3283
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "语义检索(嵌入源)" }),
3284
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3285
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2892
3286
  Segmented,
2893
3287
  {
2894
3288
  value: st.source,
@@ -2901,18 +3295,18 @@ var __defProp = Object.defineProperty;
2901
3295
  }
2902
3296
  )
2903
3297
  ] }),
2904
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 4 }, children: st.source === "off" ? "当前:关键词(BM25)检索,不做向量嵌入" : st.source === "remote" ? "当前:远程嵌入(" + (remote.model || "未配置模型") + (remote.baseURL ? " · " + remote.baseURL : "") + ")" : "当前:本地嵌入" + (st.activeModel ? "(" + st.activeModel + ")" : "") }),
2905
- st.activeNote ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 4, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: st.activeNote }) : null,
2906
- err && err !== "__unsupported__" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null,
2907
- dl && dl.phase === "error" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "下载失败:" + (dl.error || "") }) : null,
3298
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 4 }, children: st.source === "off" ? "当前:关键词(BM25)检索,不做向量嵌入" : st.source === "remote" ? "当前:远程嵌入(" + (remote.model || "未配置模型") + (remote.baseURL ? " · " + remote.baseURL : "") + ")" : "当前:本地嵌入" + (st.activeModel ? "(" + st.activeModel + ")" : "") }),
3299
+ st.activeNote ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 4, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: st.activeNote }) : null,
3300
+ err && err !== "__unsupported__" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null,
3301
+ dl && dl.phase === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "下载失败:" + (dl.error || "") }) : null,
2908
3302
  runtimeRow,
2909
3303
  applyRow,
2910
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: RSTY.block, children: [
2911
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: RSTY.title, children: "远程连接(生效值;运行时覆盖优先于部署 YAML)" }),
2912
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: RSTY.note, children: "生效端点 " + (remote.baseURL || "(未配置)") + " · 模型 " + (remote.model || "(未配置)") + " · " + (remote.dimensions > 0 ? remote.dimensions + " 维" : "维度跟随部署") + (remote.apiKeySet ? " · 密钥已设置" : " · 密钥未设置") }),
2913
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: RSTY.row, children: [
2914
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.label, children: "端点 URL" }),
2915
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3304
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.block, children: [
3305
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.title, children: "远程连接(生效值;运行时覆盖优先于部署 YAML)" }),
3306
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.note, children: "生效端点 " + (remote.baseURL || "(未配置)") + " · 模型 " + (remote.model || "(未配置)") + " · " + (remote.dimensions > 0 ? remote.dimensions + " 维" : "维度跟随部署") + (remote.apiKeySet ? " · 密钥已设置" : " · 密钥未设置") }),
3307
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3308
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "端点 URL" }),
3309
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2916
3310
  NInput,
2917
3311
  {
2918
3312
  style: RSTY.input,
@@ -2929,9 +3323,9 @@ var __defProp = Object.defineProperty;
2929
3323
  }
2930
3324
  )
2931
3325
  ] }),
2932
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: RSTY.row, children: [
2933
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.label, children: "模型名" }),
2934
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3326
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3327
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "模型名" }),
3328
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2935
3329
  NInput,
2936
3330
  {
2937
3331
  style: RSTY.input,
@@ -2947,8 +3341,8 @@ var __defProp = Object.defineProperty;
2947
3341
  }
2948
3342
  }
2949
3343
  ),
2950
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.label, children: "维度" }),
2951
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3344
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "维度" }),
3345
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2952
3346
  NInput,
2953
3347
  {
2954
3348
  style: { width: 90, minWidth: 0, flex: "0 1 90px" },
@@ -2968,9 +3362,9 @@ var __defProp = Object.defineProperty;
2968
3362
  }
2969
3363
  )
2970
3364
  ] }),
2971
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: RSTY.row, children: [
2972
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.label, children: "API Key" }),
2973
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3365
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3366
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "API Key" }),
3367
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2974
3368
  NInput,
2975
3369
  {
2976
3370
  style: RSTY.input,
@@ -2985,8 +3379,8 @@ var __defProp = Object.defineProperty;
2985
3379
  onBlur: commitRemoteKey
2986
3380
  }
2987
3381
  ),
2988
- remote.apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.chipAccent, children: "已设置" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.chipMuted, children: "未设置" }),
2989
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3382
+ remote.apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.chipAccent, children: "已设置" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.chipMuted, children: "未设置" }),
3383
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2990
3384
  NButton,
2991
3385
  {
2992
3386
  title: "写入空串清除运行时密钥(部署 YAML 的密钥不受影响)",
@@ -2996,17 +3390,17 @@ var __defProp = Object.defineProperty;
2996
3390
  )
2997
3391
  ] })
2998
3392
  ] }),
2999
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
3393
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
3000
3394
  modelCards,
3001
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: RSTY.block, children: [
3002
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: RSTY.title, children: "向量索引" }),
3003
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: RSTY.note, children: vecNote }),
3004
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: RSTY.row, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3395
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.block, children: [
3396
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.title, children: "向量索引" }),
3397
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.note, children: vecNote }),
3398
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.row, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3005
3399
  NButton,
3006
3400
  {
3007
3401
  disabled: !canRebuild,
3008
3402
  title: rebuildHint,
3009
- onClick: () => call("dsh-memory/embedding-reindex", {}),
3403
+ onClick: () => call2("dsh-memory/embedding-reindex", {}),
3010
3404
  children: "重建索引"
3011
3405
  }
3012
3406
  ) })
@@ -3015,8 +3409,8 @@ var __defProp = Object.defineProperty;
3015
3409
  }
3016
3410
 
3017
3411
  // client/src/tabs/RebuildPanel.tsx
3018
- var import_react13 = require("react");
3019
- var import_jsx_runtime13 = require("react/jsx-runtime");
3412
+ var import_react14 = require("react");
3413
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3020
3414
  var RB_PHASE_LABEL = {
3021
3415
  preparing: "准备中(归档旧数据 · 清空检索库)",
3022
3416
  distilling: "分块蒸馏中",
@@ -3024,21 +3418,21 @@ var __defProp = Object.defineProperty;
3024
3418
  };
3025
3419
  function RebuildPanel(props) {
3026
3420
  const rpc = props.rpc;
3027
- const [rbRaw, setRb] = (0, import_react13.useState)(null);
3028
- const [confirmOpen, setConfirmOpen] = (0, import_react13.useState)(false);
3029
- const [busy, setBusy] = (0, import_react13.useState)(false);
3030
- const [rbError, setRbError] = (0, import_react13.useState)(null);
3031
- const refresh = (0, import_react13.useCallback)(() => {
3421
+ const [rbRaw, setRb] = (0, import_react14.useState)(null);
3422
+ const [confirmOpen, setConfirmOpen] = (0, import_react14.useState)(false);
3423
+ const [busy, setBusy] = (0, import_react14.useState)(false);
3424
+ const [rbError, setRbError] = (0, import_react14.useState)(null);
3425
+ const refresh = (0, import_react14.useCallback)(() => {
3032
3426
  rpc("dsh-memory/rebuild-status", {}).then((r) => {
3033
3427
  if (r && r.ok) setRb(r.value);
3034
3428
  }).catch(() => {
3035
3429
  });
3036
3430
  }, [rpc]);
3037
- (0, import_react13.useEffect)(() => {
3431
+ (0, import_react14.useEffect)(() => {
3038
3432
  refresh();
3039
3433
  }, [refresh]);
3040
3434
  const running = !!(rbRaw && rbRaw.running);
3041
- (0, import_react13.useEffect)(() => {
3435
+ (0, import_react14.useEffect)(() => {
3042
3436
  if (!running) return;
3043
3437
  const timer = setInterval(refresh, 1500);
3044
3438
  return () => {
@@ -3083,11 +3477,11 @@ var __defProp = Object.defineProperty;
3083
3477
  } else if (!running && rb.phase === "failed") {
3084
3478
  lastNote = "上次重建:失败:" + (rb.error || "未知错误");
3085
3479
  }
3086
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3087
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3088
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "重建记忆" }),
3089
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RB_PHASE_LABEL[rb.phase] || rb.phase) + " · " + rb.done + "/" + rb.total + " 会话(" + pct + "%)" : "从 L0 原始对话重新蒸馏 L1/L2/L3;旧数据先归档(不删除)" }),
3090
- running ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { disabled: busy || rb.cancelRequested, onClick: cancel, children: rb.cancelRequested ? "取消中…" : "取消重建" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3480
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3481
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3482
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "重建记忆" }),
3483
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RB_PHASE_LABEL[rb.phase] || rb.phase) + " · " + rb.done + "/" + rb.total + " 会话(" + pct + "%)" : "从 L0 原始对话重新蒸馏 L1/L2/L3;旧数据先归档(不删除)" }),
3484
+ running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { disabled: busy || rb.cancelRequested, onClick: cancel, children: rb.cancelRequested ? "取消中…" : "取消重建" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3091
3485
  NButton,
3092
3486
  {
3093
3487
  disabled: busy || empty,
@@ -3100,13 +3494,13 @@ var __defProp = Object.defineProperty;
3100
3494
  }
3101
3495
  )
3102
3496
  ] }),
3103
- running ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3104
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }),
3105
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
3497
+ running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3498
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }),
3499
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
3106
3500
  ] }) : null,
3107
- lastNote ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3108
- rbError ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rbError }) : null,
3109
- confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3501
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3502
+ rbError ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rbError }) : null,
3503
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3110
3504
  NModal,
3111
3505
  {
3112
3506
  open: true,
@@ -3115,7 +3509,7 @@ var __defProp = Object.defineProperty;
3115
3509
  },
3116
3510
  title: "确认重建全部记忆?",
3117
3511
  footer: [
3118
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3512
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3119
3513
  NButton,
3120
3514
  {
3121
3515
  onClick: () => {
@@ -3125,15 +3519,15 @@ var __defProp = Object.defineProperty;
3125
3519
  },
3126
3520
  "cancel"
3127
3521
  ),
3128
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
3522
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
3129
3523
  ],
3130
3524
  children: [
3131
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3525
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3132
3526
  "将以 L0 原始对话为事实源重新蒸馏:",
3133
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
3527
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
3134
3528
  ",预计 ≥" + rb.estCalls + " 次蒸馏调用。"
3135
3529
  ] }),
3136
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
3530
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
3137
3531
  ]
3138
3532
  }
3139
3533
  ) : null
@@ -3141,8 +3535,8 @@ var __defProp = Object.defineProperty;
3141
3535
  }
3142
3536
 
3143
3537
  // client/src/tabs/RuminatePanel.tsx
3144
- var import_react14 = require("react");
3145
- var import_jsx_runtime14 = require("react/jsx-runtime");
3538
+ var import_react15 = require("react");
3539
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3146
3540
  var RM_PHASE_LABEL = {
3147
3541
  refreshing: "轻量刷新中",
3148
3542
  distilling: "L1 蒸馏中",
@@ -3163,11 +3557,11 @@ var __defProp = Object.defineProperty;
3163
3557
  var RM_IDLE_INTERVAL = 3e4;
3164
3558
  function RuminatePanel(props) {
3165
3559
  const rpc = props.rpc;
3166
- const [rmRaw, setRm] = (0, import_react14.useState)(null);
3167
- const [confirmOpen, setConfirmOpen] = (0, import_react14.useState)(false);
3168
- const [busy, setBusy] = (0, import_react14.useState)(false);
3169
- const [rmError, setRmError] = (0, import_react14.useState)(null);
3170
- const refresh = (0, import_react14.useCallback)(() => {
3560
+ const [rmRaw, setRm] = (0, import_react15.useState)(null);
3561
+ const [confirmOpen, setConfirmOpen] = (0, import_react15.useState)(false);
3562
+ const [busy, setBusy] = (0, import_react15.useState)(false);
3563
+ const [rmError, setRmError] = (0, import_react15.useState)(null);
3564
+ const refresh = (0, import_react15.useCallback)(() => {
3171
3565
  return rpc("dsh-memory/ruminate-status", {}).then((r) => {
3172
3566
  if (r && r.ok) {
3173
3567
  const st = r.value;
@@ -3182,14 +3576,14 @@ var __defProp = Object.defineProperty;
3182
3576
  }).catch(() => {
3183
3577
  });
3184
3578
  }, [rpc]);
3185
- const pollRef = (0, import_react14.useRef)(1500);
3186
- const backoffRef = (0, import_react14.useRef)(1);
3187
- const lastDetailRef = (0, import_react14.useRef)(null);
3188
- (0, import_react14.useEffect)(() => {
3579
+ const pollRef = (0, import_react15.useRef)(1500);
3580
+ const backoffRef = (0, import_react15.useRef)(1);
3581
+ const lastDetailRef = (0, import_react15.useRef)(null);
3582
+ (0, import_react15.useEffect)(() => {
3189
3583
  refresh();
3190
3584
  }, [refresh]);
3191
3585
  const running = !!(rmRaw && (rmRaw.running || RM_RUNNING_PHASES.indexOf(rmRaw.phase) >= 0));
3192
- (0, import_react14.useEffect)(() => {
3586
+ (0, import_react15.useEffect)(() => {
3193
3587
  if (!running) return;
3194
3588
  let alive = true;
3195
3589
  let timer;
@@ -3208,13 +3602,13 @@ var __defProp = Object.defineProperty;
3208
3602
  lastDetailRef.current = null;
3209
3603
  };
3210
3604
  }, [running, refresh]);
3211
- (0, import_react14.useEffect)(() => {
3605
+ (0, import_react15.useEffect)(() => {
3212
3606
  if (running) return;
3213
3607
  const timer = setInterval(refresh, RM_IDLE_INTERVAL);
3214
3608
  return () => clearInterval(timer);
3215
3609
  }, [running, refresh]);
3216
- const [, setTick] = (0, import_react14.useState)(0);
3217
- (0, import_react14.useEffect)(() => {
3610
+ const [, setTick] = (0, import_react15.useState)(0);
3611
+ (0, import_react15.useEffect)(() => {
3218
3612
  if (!running) return;
3219
3613
  const timer = setInterval(() => setTick((n) => n + 1), 1e3);
3220
3614
  return () => clearInterval(timer);
@@ -3265,11 +3659,11 @@ var __defProp = Object.defineProperty;
3265
3659
  }
3266
3660
  const unit = rm.phase === "refreshing" || rm.phase === "relabeling" ? "步" : "会话";
3267
3661
  const progressText = sub ? sub.label + " " + sub.done + "/" + sub.total + "(" + Math.round(sub.done / sub.total * 100) + "%)" : rm.total > 0 ? rm.done + "/" + rm.total + " " + unit + "(" + pct + "%)" : "进行中…";
3268
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3269
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3270
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "反刍整理" }),
3271
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RM_PHASE_LABEL[rm.phase] || rm.phase) + " · " + progressText + (elapsedText ? " · 已用 " + elapsedText : "") : "冲刷未蒸馏缓冲,跑一轮 L1→L2→L3 消化;不清库不改 L0" }),
3272
- running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { disabled: busy || rm.cancelRequested, onClick: cancel, children: rm.cancelRequested ? "取消中…" : "取消整理" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3662
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3663
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3664
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "反刍整理" }),
3665
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RM_PHASE_LABEL[rm.phase] || rm.phase) + " · " + progressText + (elapsedText ? " · 已用 " + elapsedText : "") : "冲刷未蒸馏缓冲,跑一轮 L1→L2→L3 消化;不清库不改 L0" }),
3666
+ running ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { disabled: busy || rm.cancelRequested, onClick: cancel, children: rm.cancelRequested ? "取消中…" : "取消整理" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3273
3667
  NButton,
3274
3668
  {
3275
3669
  disabled: busy,
@@ -3282,27 +3676,27 @@ var __defProp = Object.defineProperty;
3282
3676
  }
3283
3677
  )
3284
3678
  ] }),
3285
- running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3286
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3679
+ running ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3680
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3287
3681
  "div",
3288
3682
  {
3289
3683
  className: "dsh-mem-rb-fill" + (indet ? " dsh-mem-rb-fill-indet" : ""),
3290
3684
  style: { width: indet ? "100%" : barPct + "%" }
3291
3685
  }
3292
3686
  ) }),
3293
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: sub ? sub.label + " " + sub.done + "/" + sub.total : "产出 " + rm.recordsBuilt + " 条" })
3687
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: sub ? sub.label + " " + sub.done + "/" + sub.total : "产出 " + rm.recordsBuilt + " 条" })
3294
3688
  ] }) : null,
3295
- running && rm.detail ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6, whiteSpace: "normal" }, children: "当前:" + rm.detail }) : null,
3296
- lastNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3297
- rmError ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rmError }) : null,
3298
- confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3689
+ running && rm.detail ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6, whiteSpace: "normal" }, children: "当前:" + rm.detail }) : null,
3690
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3691
+ rmError ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rmError }) : null,
3692
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3299
3693
  NModal,
3300
3694
  {
3301
3695
  open: true,
3302
3696
  onClose: () => setConfirmOpen(false),
3303
3697
  title: "确认反刍整理?",
3304
3698
  footer: [
3305
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3699
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3306
3700
  NButton,
3307
3701
  {
3308
3702
  onClick: () => setConfirmOpen(false),
@@ -3310,11 +3704,11 @@ var __defProp = Object.defineProperty;
3310
3704
  },
3311
3705
  "cancel"
3312
3706
  ),
3313
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
3707
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
3314
3708
  ],
3315
3709
  children: [
3316
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { children: "将扫描未蒸馏缓冲,按会话逐个跑蒸馏管线,完成后强制 L2 场景整合与 L3 画像更新。" }),
3317
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8 }, children: "与重建不同:不清空 L1 检索库、不归档旧产物、不改 L0;仅消化攒而未蒸馏的切片,无缓冲时做轻量 L2/L3 刷新。" })
3710
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: "将扫描未蒸馏缓冲,按会话逐个跑蒸馏管线,完成后强制 L2 场景整合与 L3 画像更新。" }),
3711
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: 8 }, children: "与重建不同:不清空 L1 检索库、不归档旧产物、不改 L0;仅消化攒而未蒸馏的切片,无缓冲时做轻量 L2/L3 刷新。" })
3318
3712
  ]
3319
3713
  }
3320
3714
  ) : null
@@ -3322,13 +3716,13 @@ var __defProp = Object.defineProperty;
3322
3716
  }
3323
3717
 
3324
3718
  // client/src/tabs/OverviewTab.tsx
3325
- var import_jsx_runtime15 = require("react/jsx-runtime");
3719
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3326
3720
  function OverviewTab(props) {
3327
3721
  const rpc = props.rpc;
3328
- const [stats, setStats] = (0, import_react15.useState)(null);
3329
- const [settingsData, setSettingsData] = (0, import_react15.useState)(null);
3330
- const [error, setError] = (0, import_react15.useState)(null);
3331
- const load = (0, import_react15.useCallback)(() => {
3722
+ const [stats, setStats] = (0, import_react16.useState)(null);
3723
+ const [settingsData, setSettingsData] = (0, import_react16.useState)(null);
3724
+ const [error, setError] = (0, import_react16.useState)(null);
3725
+ const load = (0, import_react16.useCallback)(() => {
3332
3726
  rpc("dsh-memory/stats", {}).then((r) => {
3333
3727
  if (r && r.ok) setStats(r.value);
3334
3728
  else setError(r && r.error ? r.error.message : "RPC error");
@@ -3340,7 +3734,7 @@ var __defProp = Object.defineProperty;
3340
3734
  }).catch(() => {
3341
3735
  });
3342
3736
  }, [rpc]);
3343
- (0, import_react15.useEffect)(() => {
3737
+ (0, import_react16.useEffect)(() => {
3344
3738
  load();
3345
3739
  const timer = setInterval(load, 5e3);
3346
3740
  return () => {
@@ -3402,10 +3796,10 @@ var __defProp = Object.defineProperty;
3402
3796
  const toolConflict = settingsData && settingsData.settings ? settingsData.settings.toolConflict !== false : true;
3403
3797
  const toolMutate = settingsData && settingsData.settings ? settingsData.settings.toolMutate !== false : true;
3404
3798
  const skillsEnabled = settingsData && settingsData.settings ? settingsData.settings.skillsEnabled === true : false;
3405
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
3406
- settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.switchPanel, children: [
3407
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
3408
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3799
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3800
+ settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: S.switchPanel, children: [
3801
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
3802
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3409
3803
  SwitchRow,
3410
3804
  {
3411
3805
  label: "记忆模式",
@@ -3416,7 +3810,7 @@ var __defProp = Object.defineProperty;
3416
3810
  }
3417
3811
  }
3418
3812
  ),
3419
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3813
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3420
3814
  SwitchRow,
3421
3815
  {
3422
3816
  label: "捕获",
@@ -3428,7 +3822,7 @@ var __defProp = Object.defineProperty;
3428
3822
  }
3429
3823
  }
3430
3824
  ),
3431
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3825
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3432
3826
  SwitchRow,
3433
3827
  {
3434
3828
  label: "蒸馏",
@@ -3440,7 +3834,7 @@ var __defProp = Object.defineProperty;
3440
3834
  }
3441
3835
  }
3442
3836
  ),
3443
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3837
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3444
3838
  SwitchRow,
3445
3839
  {
3446
3840
  label: "召回",
@@ -3452,8 +3846,8 @@ var __defProp = Object.defineProperty;
3452
3846
  }
3453
3847
  }
3454
3848
  ),
3455
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3456
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3849
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3850
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3457
3851
  SwitchRow,
3458
3852
  {
3459
3853
  label: "高权限模式",
@@ -3464,8 +3858,8 @@ var __defProp = Object.defineProperty;
3464
3858
  }
3465
3859
  }
3466
3860
  ),
3467
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3468
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3861
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3862
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3469
3863
  SwitchRow,
3470
3864
  {
3471
3865
  label: "技能(程序性记忆)",
@@ -3476,8 +3870,8 @@ var __defProp = Object.defineProperty;
3476
3870
  }
3477
3871
  }
3478
3872
  ),
3479
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3480
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3873
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3874
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3481
3875
  SwitchRow,
3482
3876
  {
3483
3877
  label: "Room 管理工具",
@@ -3488,7 +3882,7 @@ var __defProp = Object.defineProperty;
3488
3882
  }
3489
3883
  }
3490
3884
  ),
3491
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3885
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3492
3886
  SwitchRow,
3493
3887
  {
3494
3888
  label: "图谱工具",
@@ -3499,7 +3893,7 @@ var __defProp = Object.defineProperty;
3499
3893
  }
3500
3894
  }
3501
3895
  ),
3502
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3896
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3503
3897
  SwitchRow,
3504
3898
  {
3505
3899
  label: "反刍工具",
@@ -3510,7 +3904,7 @@ var __defProp = Object.defineProperty;
3510
3904
  }
3511
3905
  }
3512
3906
  ),
3513
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3907
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3514
3908
  SwitchRow,
3515
3909
  {
3516
3910
  label: "冲突工具",
@@ -3521,7 +3915,7 @@ var __defProp = Object.defineProperty;
3521
3915
  }
3522
3916
  }
3523
3917
  ),
3524
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3918
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3525
3919
  SwitchRow,
3526
3920
  {
3527
3921
  label: "写删工具",
@@ -3532,8 +3926,8 @@ var __defProp = Object.defineProperty;
3532
3926
  }
3533
3927
  }
3534
3928
  ),
3535
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3536
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3929
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3930
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3537
3931
  SwitchRow,
3538
3932
  {
3539
3933
  label: "人工冲突裁决",
@@ -3544,42 +3938,43 @@ var __defProp = Object.defineProperty;
3544
3938
  }
3545
3939
  }
3546
3940
  ),
3547
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
3548
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
3549
- ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3941
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
3942
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
3943
+ ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3550
3944
  ] }) : null,
3551
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(EmbeddingSection, { rpc }),
3552
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RebuildPanel, { rpc }),
3553
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RuminatePanel, { rpc }),
3554
- degraded ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
3555
- error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
3556
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
3557
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
3558
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
3559
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.statNum, children: t.num }),
3560
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.statLabel, children: t.label })
3945
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(EmbeddingSection, { rpc }),
3946
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RebuildPanel, { rpc }),
3947
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RuminatePanel, { rpc }),
3948
+ degraded ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
3949
+ error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3950
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
3951
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
3952
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
3953
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statNum, children: t.num }),
3954
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statLabel, children: t.label })
3561
3955
  ] }, t.label);
3562
3956
  }) }),
3563
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3957
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3564
3958
  infos.map((row2) => {
3565
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.infoRow, children: [
3566
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.infoKey, children: row2[0] }),
3567
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.infoVal, children: row2[1] })
3959
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: S.infoRow, children: [
3960
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoKey, children: row2[0] }),
3961
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoVal, children: row2[1] })
3568
3962
  ] }, row2[0]);
3569
3963
  })
3570
3964
  ] }),
3571
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3965
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArchiveSection, { rpc }),
3966
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3572
3967
  ] });
3573
3968
  }
3574
3969
 
3575
3970
  // client/src/tabs/PersonaTab.tsx
3576
- var import_react16 = require("react");
3577
- var import_jsx_runtime16 = require("react/jsx-runtime");
3971
+ var import_react17 = require("react");
3972
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3578
3973
  function PersonaTab(props) {
3579
3974
  const rpc = props.rpc;
3580
- const [content, setContent] = (0, import_react16.useState)(null);
3581
- const [error, setError] = (0, import_react16.useState)(null);
3582
- const load = (0, import_react16.useCallback)(() => {
3975
+ const [content, setContent] = (0, import_react17.useState)(null);
3976
+ const [error, setError] = (0, import_react17.useState)(null);
3977
+ const load = (0, import_react17.useCallback)(() => {
3583
3978
  setError(null);
3584
3979
  rpc("dsh-memory/persona", {}).then((r) => {
3585
3980
  if (r && r.ok) setContent(r.value.content);
@@ -3588,64 +3983,55 @@ var __defProp = Object.defineProperty;
3588
3983
  setError(String(e && e.message || e));
3589
3984
  });
3590
3985
  }, [rpc]);
3591
- (0, import_react16.useEffect)(() => {
3986
+ (0, import_react17.useEffect)(() => {
3592
3987
  load();
3593
3988
  }, [load]);
3594
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3595
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3596
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
3597
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
3598
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { onClick: load, children: "刷新" })
3989
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3990
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3991
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
3992
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
3993
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: load, children: "刷新" })
3599
3994
  ] }),
3600
- error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
3601
- content ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
3995
+ error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
3996
+ content ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
3602
3997
  ] });
3603
3998
  }
3604
3999
 
3605
4000
  // client/src/tabs/RecordsTab.tsx
3606
- var import_react17 = require("react");
3607
- var import_jsx_runtime17 = require("react/jsx-runtime");
4001
+ var import_react18 = require("react");
4002
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3608
4003
  function retiredSelOf(r) {
3609
4004
  if (r === "active") return false;
3610
4005
  if (r === "retired") return true;
3611
4006
  return void 0;
3612
4007
  }
3613
- var TYPE_CHOICES = [
3614
- "persona",
3615
- "episodic",
3616
- "instruction",
3617
- "work_fact",
3618
- "work_task",
3619
- "work_method",
3620
- "work_artifact"
3621
- ];
3622
4008
  var DELETE_LIMIT = 200;
3623
4009
  function RecordsTab(props) {
3624
4010
  const rpc = props.rpc;
3625
4011
  const limit = 50;
3626
- const [items, setItems] = (0, import_react17.useState)([]);
3627
- const [hasMore, setHasMore] = (0, import_react17.useState)(false);
3628
- const [total, setTotal] = (0, import_react17.useState)(null);
3629
- const [sceneOptions, setSceneOptions] = (0, import_react17.useState)([]);
3630
- const [loading, setLoading] = (0, import_react17.useState)(false);
3631
- const [truncated, setTruncated] = (0, import_react17.useState)(false);
3632
- const [error, setError] = (0, import_react17.useState)(null);
3633
- const [expandedId, setExpandedId] = (0, import_react17.useState)(null);
3634
- const [sel, setSel] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
3635
- const [hiPriv, setHiPriv] = (0, import_react17.useState)(false);
3636
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react17.useState)(false);
3637
- const [query, setQuery] = (0, import_react17.useState)("");
3638
- const [typeFilter, setTypeFilter] = (0, import_react17.useState)("");
3639
- const [sceneFilter, setSceneFilter] = (0, import_react17.useState)("");
3640
- const [hallFilter, setHallFilter] = (0, import_react17.useState)([]);
3641
- const [tagFilter, setTagFilter] = (0, import_react17.useState)("");
3642
- const [untaggedOnly, setUntaggedOnly] = (0, import_react17.useState)(false);
3643
- const [orphanCount, setOrphanCount] = (0, import_react17.useState)(0);
3644
- const [retiredFilter, setRetiredFilter] = (0, import_react17.useState)("");
3645
- const [wingCatalog, setHallCatalog] = (0, import_react17.useState)(null);
3646
- const [last, setLast] = (0, import_react17.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
3647
- const seqRef = (0, import_react17.useRef)(0);
3648
- const fetchPage = (0, import_react17.useCallback)(
4012
+ const [items, setItems] = (0, import_react18.useState)([]);
4013
+ const [hasMore, setHasMore] = (0, import_react18.useState)(false);
4014
+ const [total, setTotal] = (0, import_react18.useState)(null);
4015
+ const [sceneOptions, setSceneOptions] = (0, import_react18.useState)([]);
4016
+ const [loading, setLoading] = (0, import_react18.useState)(false);
4017
+ const [truncated, setTruncated] = (0, import_react18.useState)(false);
4018
+ const [error, setError] = (0, import_react18.useState)(null);
4019
+ const [expandedId, setExpandedId] = (0, import_react18.useState)(null);
4020
+ const [sel, setSel] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
4021
+ const [hiPriv, setHiPriv] = (0, import_react18.useState)(false);
4022
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react18.useState)(false);
4023
+ const [query, setQuery] = (0, import_react18.useState)("");
4024
+ const [typeFilter, setTypeFilter] = (0, import_react18.useState)("");
4025
+ const [sceneFilter, setSceneFilter] = (0, import_react18.useState)("");
4026
+ const [hallFilter, setHallFilter] = (0, import_react18.useState)([]);
4027
+ const [tagFilter, setTagFilter] = (0, import_react18.useState)("");
4028
+ const [untaggedOnly, setUntaggedOnly] = (0, import_react18.useState)(false);
4029
+ const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
4030
+ const [retiredFilter, setRetiredFilter] = (0, import_react18.useState)("");
4031
+ const [wingCatalog, setHallCatalog] = (0, import_react18.useState)(null);
4032
+ const [last, setLast] = (0, import_react18.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
4033
+ const seqRef = (0, import_react18.useRef)(0);
4034
+ const fetchPage = (0, import_react18.useCallback)(
3649
4035
  (conds, offset, append) => {
3650
4036
  setLoading(true);
3651
4037
  setError(null);
@@ -3675,6 +4061,7 @@ var __defProp = Object.defineProperty;
3675
4061
  setTruncated(!!v.truncated);
3676
4062
  if (v.scenes) setSceneOptions(v.scenes);
3677
4063
  if (v.wingCatalog) setHallCatalog(v.wingCatalog);
4064
+ if (v.typeCatalog) registerTypeCatalog(v.typeCatalog);
3678
4065
  }).catch((e) => {
3679
4066
  if (token !== seqRef.current) return;
3680
4067
  setLoading(false);
@@ -3694,23 +4081,23 @@ var __defProp = Object.defineProperty;
3694
4081
  setLast(conds);
3695
4082
  fetchPage(conds, 0, false);
3696
4083
  };
3697
- const loadRooms = (0, import_react17.useCallback)(() => {
4084
+ const loadRooms = (0, import_react18.useCallback)(() => {
3698
4085
  rpc("dsh-memory/rooms-get", {}).then((r) => {
3699
4086
  if (r && r.ok) setOrphanCount(r.value.orphanCount ?? 0);
3700
4087
  }).catch(() => {
3701
4088
  });
3702
4089
  }, [rpc]);
3703
- (0, import_react17.useEffect)(() => {
4090
+ (0, import_react18.useEffect)(() => {
3704
4091
  fetchPage({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" }, 0, false);
3705
4092
  loadRooms();
3706
4093
  }, [fetchPage, loadRooms]);
3707
- const loadHiPriv = (0, import_react17.useCallback)(() => {
4094
+ const loadHiPriv = (0, import_react18.useCallback)(() => {
3708
4095
  rpc("dsh-memory/settings-get", {}).then((r) => {
3709
4096
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
3710
4097
  }).catch(() => {
3711
4098
  });
3712
4099
  }, [rpc]);
3713
- (0, import_react17.useEffect)(() => {
4100
+ (0, import_react18.useEffect)(() => {
3714
4101
  loadHiPriv();
3715
4102
  }, [loadHiPriv]);
3716
4103
  const toggleHiPriv = () => {
@@ -3751,7 +4138,9 @@ var __defProp = Object.defineProperty;
3751
4138
  if (r && r.ok) {
3752
4139
  setSel(/* @__PURE__ */ new Set());
3753
4140
  if (expandedId && ids.indexOf(expandedId) >= 0) setExpandedId(null);
3754
- fetchPage(last, 0, false);
4141
+ const removed = r.value?.deleted ?? ids.length;
4142
+ setItems((prev) => prev.filter((m) => !ids.includes(m.id)));
4143
+ setTotal((t) => t === null ? null : Math.max(0, t - removed));
3755
4144
  if (showRetired) loadRetired();
3756
4145
  } else if (r) setError(r.error ? r.error.message : "退场失败");
3757
4146
  }).catch((e) => setError(String(e && e.message || e)));
@@ -3766,16 +4155,17 @@ var __defProp = Object.defineProperty;
3766
4155
  return next;
3767
4156
  });
3768
4157
  if (expandedId === id) setExpandedId(null);
3769
- fetchPage(last, 0, false);
4158
+ setItems((prev) => prev.filter((m) => m.id !== id));
4159
+ setTotal((t) => t === null ? null : Math.max(0, t - 1));
3770
4160
  if (showRetired) loadRetired();
3771
4161
  } else if (r) setError(r.error ? r.error.message : "退场失败");
3772
4162
  }).catch((e) => setError(String(e && e.message || e)));
3773
4163
  };
3774
- const [retired, setRetired] = (0, import_react17.useState)([]);
3775
- const [retiredTotal, setRetiredTotal] = (0, import_react17.useState)(0);
3776
- const [showRetired, setShowRetired] = (0, import_react17.useState)(false);
3777
- const [retiredBusy, setRetiredBusy] = (0, import_react17.useState)(false);
3778
- const loadRetired = (0, import_react17.useCallback)(() => {
4164
+ const [retired, setRetired] = (0, import_react18.useState)([]);
4165
+ const [retiredTotal, setRetiredTotal] = (0, import_react18.useState)(0);
4166
+ const [showRetired, setShowRetired] = (0, import_react18.useState)(false);
4167
+ const [retiredBusy, setRetiredBusy] = (0, import_react18.useState)(false);
4168
+ const loadRetired = (0, import_react18.useCallback)(() => {
3779
4169
  setRetiredBusy(true);
3780
4170
  rpc("dsh-memory/records-retired", { limit: 100, offset: 0 }).then((r) => {
3781
4171
  if (r && r.ok) {
@@ -3784,7 +4174,7 @@ var __defProp = Object.defineProperty;
3784
4174
  } else if (r) setError(r.error ? r.error.message : "已退场列表加载失败");
3785
4175
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
3786
4176
  }, [rpc]);
3787
- (0, import_react17.useEffect)(() => {
4177
+ (0, import_react18.useEffect)(() => {
3788
4178
  if (showRetired) loadRetired();
3789
4179
  }, [showRetired, loadRetired]);
3790
4180
  const restoreRecords = (ids) => {
@@ -3793,7 +4183,10 @@ var __defProp = Object.defineProperty;
3793
4183
  rpc("dsh-memory/records-restore", { ids }).then((r) => {
3794
4184
  if (r && r.ok) {
3795
4185
  loadRetired();
3796
- fetchPage(last, 0, false);
4186
+ const restored = new Set(ids);
4187
+ setItems(
4188
+ (prev) => prev.map((m) => restored.has(m.id) ? { ...m, retired: false, retiredReason: void 0 } : m)
4189
+ );
3797
4190
  } else if (r) setError(r.error ? r.error.message : "恢复失败");
3798
4191
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
3799
4192
  };
@@ -3801,14 +4194,15 @@ var __defProp = Object.defineProperty;
3801
4194
  conflict: "裁决退场",
3802
4195
  superseded: "被取代",
3803
4196
  manual: "人工退场",
4197
+ obsolete: "声明过时",
3804
4198
  unknown: "已退场"
3805
4199
  };
3806
4200
  const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
3807
- const [usageSummary, setUsageSummary] = (0, import_react17.useState)(null);
4201
+ const [usageSummary, setUsageSummary] = (0, import_react18.useState)(null);
3808
4202
  const selCount = sel.size;
3809
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3810
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.toolbar, children: [
3811
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4203
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4204
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.toolbar, children: [
4205
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3812
4206
  NInput,
3813
4207
  {
3814
4208
  style: { flex: 1, minWidth: 160 },
@@ -3819,23 +4213,32 @@ var __defProp = Object.defineProperty;
3819
4213
  },
3820
4214
  onKeyDown: (e) => {
3821
4215
  if (e.key === "Enter") search();
4216
+ else if (e.key === "Escape" || e.key === "Backspace" && (e.ctrlKey || e.metaKey)) {
4217
+ if (query.length > 0) {
4218
+ e.preventDefault();
4219
+ setQuery("");
4220
+ const conds = { query: "", type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter, untagged: untaggedOnly, retired: retiredFilter };
4221
+ setLast(conds);
4222
+ fetchPage(conds, 0, false);
4223
+ }
4224
+ }
3822
4225
  }
3823
4226
  }
3824
4227
  ),
3825
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4228
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3826
4229
  NSel,
3827
4230
  {
3828
4231
  style: { maxWidth: 200 },
3829
4232
  options: [{ id: "", label: "全部类型" }].concat(
3830
- TYPE_CHOICES.map((t) => {
3831
- return { id: t, label: TYPE_LABELS[t] || t };
4233
+ (typeCatalogIds().length > 0 ? typeCatalogIds() : [...new Set(items.map((m) => m.type))]).map((t) => {
4234
+ return { id: t, label: typeLabel(t) };
3832
4235
  })
3833
4236
  ),
3834
4237
  value: typeFilter,
3835
4238
  onChange: setTypeFilter
3836
4239
  }
3837
4240
  ),
3838
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4241
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3839
4242
  NSel,
3840
4243
  {
3841
4244
  style: { maxWidth: 220 },
@@ -3848,7 +4251,7 @@ var __defProp = Object.defineProperty;
3848
4251
  onChange: setSceneFilter
3849
4252
  }
3850
4253
  ),
3851
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4254
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3852
4255
  WingMultiSelect,
3853
4256
  {
3854
4257
  options: wingCatalog ?? Array.from(new Set(items.map((m) => m.hall).filter((h) => !!h))).map((id) => ({ id, label: id })),
@@ -3856,8 +4259,8 @@ var __defProp = Object.defineProperty;
3856
4259
  onChange: setHallFilter
3857
4260
  }
3858
4261
  ),
3859
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: search, children: "搜索" }),
3860
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4262
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: search, children: "搜索" }),
4263
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3861
4264
  NButton,
3862
4265
  {
3863
4266
  style: {
@@ -3871,8 +4274,8 @@ var __defProp = Object.defineProperty;
3871
4274
  }
3872
4275
  )
3873
4276
  ] }),
3874
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
3875
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4277
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
4278
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3876
4279
  "button",
3877
4280
  {
3878
4281
  type: "button",
@@ -3897,10 +4300,10 @@ var __defProp = Object.defineProperty;
3897
4300
  children: "无绑定 · " + orphanCount
3898
4301
  }
3899
4302
  ),
3900
- (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
4303
+ (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
3901
4304
  "筛选中:",
3902
4305
  untaggedOnly ? "无绑定" : tagFilter,
3903
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4306
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3904
4307
  "button",
3905
4308
  {
3906
4309
  type: "button",
@@ -3917,7 +4320,7 @@ var __defProp = Object.defineProperty;
3917
4320
  }
3918
4321
  )
3919
4322
  ] }),
3920
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4323
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3921
4324
  "button",
3922
4325
  {
3923
4326
  type: "button",
@@ -3946,15 +4349,15 @@ var __defProp = Object.defineProperty;
3946
4349
  children: "导出孤儿"
3947
4350
  }
3948
4351
  ),
3949
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4352
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
3950
4353
  ] }),
3951
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3952
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
3953
- usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
3954
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "退场筛查" }),
4354
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4355
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
4356
+ usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
4357
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "退场筛查" }),
3955
4358
  [["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
3956
4359
  const on = retiredFilter === val;
3957
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4360
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3958
4361
  "button",
3959
4362
  {
3960
4363
  type: "button",
@@ -3974,7 +4377,7 @@ var __defProp = Object.defineProperty;
3974
4377
  val
3975
4378
  );
3976
4379
  }),
3977
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4380
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3978
4381
  NButton,
3979
4382
  {
3980
4383
  style: selCount > 0 ? { color: "var(--dsh-mem-danger)" } : void 0,
@@ -3984,7 +4387,7 @@ var __defProp = Object.defineProperty;
3984
4387
  children: "删除选中" + (selCount > 0 ? "(" + selCount + ")" : "")
3985
4388
  }
3986
4389
  ),
3987
- selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4390
+ selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3988
4391
  NButton,
3989
4392
  {
3990
4393
  onClick: () => {
@@ -3993,8 +4396,8 @@ var __defProp = Object.defineProperty;
3993
4396
  children: "清空选择"
3994
4397
  }
3995
4398
  ) : null,
3996
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
3997
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4399
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4400
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3998
4401
  NButton,
3999
4402
  {
4000
4403
  onClick: () => {
@@ -4005,13 +4408,13 @@ var __defProp = Object.defineProperty;
4005
4408
  }
4006
4409
  )
4007
4410
  ] }),
4008
- !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4009
- error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.error, children: error }) : null,
4010
- truncated ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4011
- items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4411
+ !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4412
+ error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.error, children: error }) : null,
4413
+ truncated ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4414
+ items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4012
4415
  const open = expandedId === m.id;
4013
4416
  const checked = sel.has(m.id);
4014
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4417
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4015
4418
  "div",
4016
4419
  {
4017
4420
  className: "dsh-mem-card dsh-mem-card-hover",
@@ -4020,8 +4423,8 @@ var __defProp = Object.defineProperty;
4020
4423
  setExpandedId(open ? null : m.id);
4021
4424
  },
4022
4425
  children: [
4023
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.cardHead, children: [
4024
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4426
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4427
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4025
4428
  "input",
4026
4429
  {
4027
4430
  type: "checkbox",
@@ -4036,9 +4439,9 @@ var __defProp = Object.defineProperty;
4036
4439
  }
4037
4440
  }
4038
4441
  ),
4039
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + m.type, children: TYPE_LABELS[m.type] || m.type }),
4040
- m.hall ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Wing · " + (wingCatalog?.find((h) => h.id === m.hall)?.label || m.hall) }) : null,
4041
- m.retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4442
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: tagClass(m.type), children: typeLabel(m.type) }),
4443
+ m.hall ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Wing · " + (wingCatalog?.find((h) => h.id === m.hall)?.label || m.hall) }) : null,
4444
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4042
4445
  "span",
4043
4446
  {
4044
4447
  title: "该记忆已退场(软删):移出检索面但仍可恢复,并未真正删除",
@@ -4053,8 +4456,8 @@ var __defProp = Object.defineProperty;
4053
4456
  children: "已退场" + (m.retiredReason ? " · " + (RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason) : "")
4054
4457
  }
4055
4458
  ) : null,
4056
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4057
- m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4459
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4460
+ m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4058
4461
  "span",
4059
4462
  {
4060
4463
  title: "成熟度(优先级 + 被用次数 + 新鲜度合成):" + m.maturity,
@@ -4069,7 +4472,7 @@ var __defProp = Object.defineProperty;
4069
4472
  children: m.maturity === "high" ? "成熟·高" : m.maturity === "mid" ? "成熟·中" : "成熟·低"
4070
4473
  }
4071
4474
  ) : null,
4072
- m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4475
+ m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4073
4476
  "span",
4074
4477
  {
4075
4478
  style: {
@@ -4084,7 +4487,7 @@ var __defProp = Object.defineProperty;
4084
4487
  children: "老化 " + Math.round(m.agingWeight * 100) + "%"
4085
4488
  }
4086
4489
  ) : null,
4087
- m.usage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4490
+ m.usage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4088
4491
  "span",
4089
4492
  {
4090
4493
  style: S.muted,
@@ -4092,10 +4495,10 @@ var __defProp = Object.defineProperty;
4092
4495
  children: "用 " + m.usage.used + "/" + m.usage.attempts
4093
4496
  }
4094
4497
  ) : null,
4095
- m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4096
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
4097
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
4098
- m.retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4498
+ m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4499
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4500
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
4501
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4099
4502
  NButton,
4100
4503
  {
4101
4504
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-accent)" },
@@ -4106,7 +4509,7 @@ var __defProp = Object.defineProperty;
4106
4509
  },
4107
4510
  children: "恢复"
4108
4511
  }
4109
- ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4512
+ ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4110
4513
  NButton,
4111
4514
  {
4112
4515
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-danger)" },
@@ -4119,34 +4522,34 @@ var __defProp = Object.defineProperty;
4119
4522
  }
4120
4523
  ) : null
4121
4524
  ] }),
4122
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.content, children: m.content }),
4123
- open ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n情境: " + (m.scene || "-") + "\n版本: v" + m.version + "(去重合并次数 " + m.version + ")\n创建: " + fmtTime(m.createdAt) + "\n活跃时间: " + (m.timestamps && m.timestamps.length > 0 ? m.timestamps.map(fmtTime).join(" → ") : "-") + "\n" + (m.sourceAnchors && m.sourceAnchors.length > 0 ? "来源锚点: " + m.sourceAnchors.join(", ") : "来源锚点: -") }) : null
4525
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content }),
4526
+ open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n情境: " + (m.scene || "-") + "\n版本: v" + m.version + "(去重合并次数 " + m.version + ")\n创建: " + fmtTime(m.createdAt) + "\n活跃时间: " + (m.timestamps && m.timestamps.length > 0 ? m.timestamps.map(fmtTime).join(" → ") : "-") + "\n" + (m.sourceAnchors && m.sourceAnchors.length > 0 ? "来源锚点: " + m.sourceAnchors.join(", ") : "来源锚点: -") }) : null
4124
4527
  ]
4125
4528
  },
4126
4529
  m.id
4127
4530
  );
4128
4531
  }),
4129
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
4130
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
4131
- showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
4132
- showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4532
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
4533
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
4534
+ showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
4535
+ showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4133
4536
  ] }),
4134
- showRetired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginTop: 8 }, children: retired.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: retiredBusy ? " " : "没有已退场的记忆。" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
4135
- retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
4136
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.cardHead, children: [
4137
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
4138
- m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
4139
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
4140
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
4141
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4537
+ showRetired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginTop: 8 }, children: retired.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.hint, children: retiredBusy ? " " : "没有已退场的记忆。" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4538
+ retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
4539
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
4541
+ m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
4542
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4543
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
4544
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4142
4545
  ] }),
4143
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.content, children: m.content })
4546
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content })
4144
4547
  ] }, m.id)),
4145
- retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4548
+ retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4146
4549
  ] }) }) : null,
4147
- hasMore ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.flexRow, children: [
4148
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
4149
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4550
+ hasMore ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.flexRow, children: [
4551
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4552
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4150
4553
  NButton,
4151
4554
  {
4152
4555
  disabled: loading,
@@ -4160,9 +4563,9 @@ var __defProp = Object.defineProperty;
4160
4563
  ] });
4161
4564
  }
4162
4565
  function WingMultiSelect(props) {
4163
- const [open, setOpen] = (0, import_react17.useState)(false);
4164
- const wrapRef = (0, import_react17.useRef)(null);
4165
- (0, import_react17.useEffect)(() => {
4566
+ const [open, setOpen] = (0, import_react18.useState)(false);
4567
+ const wrapRef = (0, import_react18.useRef)(null);
4568
+ (0, import_react18.useEffect)(() => {
4166
4569
  if (!open) return;
4167
4570
  const onDown = (e) => {
4168
4571
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -4182,8 +4585,8 @@ var __defProp = Object.defineProperty;
4182
4585
  const toggle = (id) => {
4183
4586
  props.onChange(props.selected.includes(id) ? props.selected.filter((x) => x !== id) : [...props.selected, id]);
4184
4587
  };
4185
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4186
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4588
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4589
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4187
4590
  "button",
4188
4591
  {
4189
4592
  type: "button",
@@ -4192,31 +4595,31 @@ var __defProp = Object.defineProperty;
4192
4595
  "aria-expanded": open,
4193
4596
  onClick: () => setOpen(!open),
4194
4597
  children: [
4195
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
4196
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
4598
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
4599
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
4197
4600
  ]
4198
4601
  }
4199
4602
  ),
4200
- open ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
4201
- props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
4603
+ open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
4604
+ props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
4202
4605
  props.options.map((o) => {
4203
4606
  const active = props.selected.includes(o.id);
4204
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
4205
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
4206
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
4607
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
4608
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
4609
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
4207
4610
  ] }, o.id);
4208
4611
  }),
4209
- props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
4210
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-pop-check" }),
4211
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
4612
+ props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
4613
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check" }),
4614
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
4212
4615
  ] }) : null
4213
4616
  ] }) : null
4214
4617
  ] });
4215
4618
  }
4216
4619
 
4217
4620
  // client/src/tabs/RoomsTab.tsx
4218
- var import_react18 = require("react");
4219
- var import_jsx_runtime18 = require("react/jsx-runtime");
4621
+ var import_react19 = require("react");
4622
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4220
4623
  function majorOf(slug) {
4221
4624
  const i = slug.indexOf("/");
4222
4625
  return i === -1 ? slug : slug.slice(0, i);
@@ -4245,26 +4648,26 @@ var __defProp = Object.defineProperty;
4245
4648
  };
4246
4649
  function RoomsTab(props) {
4247
4650
  const rpc = props.rpc;
4248
- const [registry, setRegistry] = (0, import_react18.useState)([]);
4249
- const [rooms, setRooms] = (0, import_react18.useState)([]);
4250
- const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
4251
- const [busy, setBusy] = (0, import_react18.useState)(false);
4252
- const [msg, setMsg] = (0, import_react18.useState)(null);
4253
- const [error, setError] = (0, import_react18.useState)(null);
4254
- const [hiPriv, setHiPriv] = (0, import_react18.useState)(false);
4255
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react18.useState)(false);
4256
- const [regSlug, setRegSlug] = (0, import_react18.useState)("");
4257
- const [regLabel, setRegLabel] = (0, import_react18.useState)("");
4258
- const [regDesc, setRegDesc] = (0, import_react18.useState)("");
4259
- const [form, setForm] = (0, import_react18.useState)(null);
4260
- const [preview, setPreview] = (0, import_react18.useState)(null);
4261
- const [grownOpen, setGrownOpen] = (0, import_react18.useState)(false);
4262
- const [dragOverHall, setDragOverHall] = (0, import_react18.useState)(null);
4263
- const [picking, setPicking] = (0, import_react18.useState)(null);
4264
- const [editing, setEditing] = (0, import_react18.useState)(null);
4265
- const [expandedRooms, setExpandedRooms] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
4266
- const [roomRecords, setRoomRecords] = (0, import_react18.useState)({});
4267
- const [expandedHalls, setExpandedHalls] = (0, import_react18.useState)(() => {
4651
+ const [registry, setRegistry] = (0, import_react19.useState)([]);
4652
+ const [rooms, setRooms] = (0, import_react19.useState)([]);
4653
+ const [orphanCount, setOrphanCount] = (0, import_react19.useState)(0);
4654
+ const [busy, setBusy] = (0, import_react19.useState)(false);
4655
+ const [msg, setMsg] = (0, import_react19.useState)(null);
4656
+ const [error, setError] = (0, import_react19.useState)(null);
4657
+ const [hiPriv, setHiPriv] = (0, import_react19.useState)(false);
4658
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react19.useState)(false);
4659
+ const [regSlug, setRegSlug] = (0, import_react19.useState)("");
4660
+ const [regLabel, setRegLabel] = (0, import_react19.useState)("");
4661
+ const [regDesc, setRegDesc] = (0, import_react19.useState)("");
4662
+ const [form, setForm] = (0, import_react19.useState)(null);
4663
+ const [preview, setPreview] = (0, import_react19.useState)(null);
4664
+ const [grownOpen, setGrownOpen] = (0, import_react19.useState)(false);
4665
+ const [dragOverHall, setDragOverHall] = (0, import_react19.useState)(null);
4666
+ const [picking, setPicking] = (0, import_react19.useState)(null);
4667
+ const [editing, setEditing] = (0, import_react19.useState)(null);
4668
+ const [expandedRooms, setExpandedRooms] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
4669
+ const [roomRecords, setRoomRecords] = (0, import_react19.useState)({});
4670
+ const [expandedHalls, setExpandedHalls] = (0, import_react19.useState)(() => {
4268
4671
  try {
4269
4672
  const v = window.localStorage.getItem("dsh.memory.halls.open");
4270
4673
  return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
@@ -4272,9 +4675,9 @@ var __defProp = Object.defineProperty;
4272
4675
  return /* @__PURE__ */ new Set();
4273
4676
  }
4274
4677
  });
4275
- const [filter, setFilter] = (0, import_react18.useState)("");
4276
- const dragRef = (0, import_react18.useRef)(null);
4277
- const [ghost, setGhost] = (0, import_react18.useState)(null);
4678
+ const [filter, setFilter] = (0, import_react19.useState)("");
4679
+ const dragRef = (0, import_react19.useRef)(null);
4680
+ const [ghost, setGhost] = (0, import_react19.useState)(null);
4278
4681
  const onDragLabelDown = (ev, slug) => {
4279
4682
  if (!hiPriv || busy || ev.button !== 0) return;
4280
4683
  ev.currentTarget.setPointerCapture(ev.pointerId);
@@ -4299,7 +4702,7 @@ var __defProp = Object.defineProperty;
4299
4702
  setDragOverHall(null);
4300
4703
  if (hall) beginReclass(d.from, hall);
4301
4704
  };
4302
- const loadAll = (0, import_react18.useCallback)(() => {
4705
+ const loadAll = (0, import_react19.useCallback)(() => {
4303
4706
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4304
4707
  if (r && r.ok) {
4305
4708
  setRooms(r.value.rooms ?? []);
@@ -4308,13 +4711,13 @@ var __defProp = Object.defineProperty;
4308
4711
  }
4309
4712
  }).catch(() => void 0);
4310
4713
  }, [rpc]);
4311
- const loadHiPriv = (0, import_react18.useCallback)(() => {
4714
+ const loadHiPriv = (0, import_react19.useCallback)(() => {
4312
4715
  rpc("dsh-memory/settings-get", {}).then((r) => {
4313
4716
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4314
4717
  }).catch(() => {
4315
4718
  });
4316
4719
  }, [rpc]);
4317
- (0, import_react18.useEffect)(() => {
4720
+ (0, import_react19.useEffect)(() => {
4318
4721
  loadAll();
4319
4722
  loadHiPriv();
4320
4723
  }, [loadAll, loadHiPriv]);
@@ -4428,7 +4831,10 @@ var __defProp = Object.defineProperty;
4428
4831
  loadAll();
4429
4832
  if (expandedRooms.has(slug)) {
4430
4833
  const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
4431
- if (rr && rr.ok) setRoomRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
4834
+ if (rr && rr.ok) {
4835
+ registerTypeCatalog(rr.value.typeCatalog);
4836
+ setRoomRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
4837
+ }
4432
4838
  }
4433
4839
  } else setError(r && r.error ? r.error.message : "操作失败");
4434
4840
  });
@@ -4450,6 +4856,7 @@ var __defProp = Object.defineProperty;
4450
4856
  }
4451
4857
  const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
4452
4858
  if (r && r.ok) {
4859
+ registerTypeCatalog(r.value.typeCatalog);
4453
4860
  const next = new Set(expandedRooms);
4454
4861
  next.add(slug);
4455
4862
  setExpandedRooms(next);
@@ -4465,7 +4872,7 @@ var __defProp = Object.defineProperty;
4465
4872
  if (r.value.csv) downloadCsv(r.value.csv, `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`);
4466
4873
  else setError("导出为空");
4467
4874
  });
4468
- const groups = (0, import_react18.useMemo)(() => {
4875
+ const groups = (0, import_react19.useMemo)(() => {
4469
4876
  const countOf = new Map(rooms.map((r) => [r.room, r.count]));
4470
4877
  const byHall = /* @__PURE__ */ new Map();
4471
4878
  for (const e of registry) {
@@ -4482,7 +4889,7 @@ var __defProp = Object.defineProperty;
4482
4889
  total: entries.reduce((s2, e) => s2 + (countOf.get(e.slug) ?? 0), 0)
4483
4890
  })).sort((a, b) => a.hall.localeCompare(b.hall));
4484
4891
  }, [registry, rooms]);
4485
- const grownOnly = (0, import_react18.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4892
+ const grownOnly = (0, import_react19.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4486
4893
  const persistHalls = (next) => {
4487
4894
  try {
4488
4895
  window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
@@ -4502,7 +4909,7 @@ var __defProp = Object.defineProperty;
4502
4909
  persistHalls(next);
4503
4910
  };
4504
4911
  const normFilter = filter.trim().toLowerCase();
4505
- const visibleGroups = (0, import_react18.useMemo)(() => {
4912
+ const visibleGroups = (0, import_react19.useMemo)(() => {
4506
4913
  if (!normFilter) return groups;
4507
4914
  return groups.map((g) => {
4508
4915
  const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
@@ -4512,15 +4919,15 @@ var __defProp = Object.defineProperty;
4512
4919
  return { ...g, entries };
4513
4920
  }).filter((g) => g.entries.length > 0);
4514
4921
  }, [groups, normFilter]);
4515
- const visibleGrown = (0, import_react18.useMemo)(
4922
+ const visibleGrown = (0, import_react19.useMemo)(
4516
4923
  () => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
4517
4924
  [grownOnly, normFilter]
4518
4925
  );
4519
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4520
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
4521
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
4522
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4523
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4926
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4927
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
4928
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
4929
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4930
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4524
4931
  "button",
4525
4932
  {
4526
4933
  type: "button",
@@ -4537,7 +4944,7 @@ var __defProp = Object.defineProperty;
4537
4944
  children: "导出词表"
4538
4945
  }
4539
4946
  ),
4540
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4947
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4541
4948
  "button",
4542
4949
  {
4543
4950
  type: "button",
@@ -4557,7 +4964,7 @@ var __defProp = Object.defineProperty;
4557
4964
  ]
4558
4965
  }
4559
4966
  ),
4560
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4967
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4561
4968
  "button",
4562
4969
  {
4563
4970
  type: "button",
@@ -4572,10 +4979,10 @@ var __defProp = Object.defineProperty;
4572
4979
  children: hiPriv ? "高权限:开" : "高权限:关"
4573
4980
  }
4574
4981
  ),
4575
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
4982
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
4576
4983
  ] }),
4577
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
4578
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4984
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
4985
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4579
4986
  "input",
4580
4987
  {
4581
4988
  value: filter,
@@ -4584,14 +4991,14 @@ var __defProp = Object.defineProperty;
4584
4991
  style: { ...S.input, width: 250, fontSize: 12 }
4585
4992
  }
4586
4993
  ),
4587
- filter ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
4588
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
4589
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4590
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
4994
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
4995
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
4996
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4997
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
4998
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
4592
4999
  ] }),
4593
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
4594
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5000
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5001
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4595
5002
  "input",
4596
5003
  {
4597
5004
  value: regSlug,
@@ -4601,7 +5008,7 @@ var __defProp = Object.defineProperty;
4601
5008
  style: { ...S.input, width: 210, fontSize: 12 }
4602
5009
  }
4603
5010
  ),
4604
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5011
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4605
5012
  "input",
4606
5013
  {
4607
5014
  value: regLabel,
@@ -4611,7 +5018,7 @@ var __defProp = Object.defineProperty;
4611
5018
  style: { ...S.input, width: 110, fontSize: 12 }
4612
5019
  }
4613
5020
  ),
4614
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5021
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4615
5022
  "input",
4616
5023
  {
4617
5024
  value: regDesc,
@@ -4621,7 +5028,7 @@ var __defProp = Object.defineProperty;
4621
5028
  style: { ...S.input, width: 170, fontSize: 12 }
4622
5029
  }
4623
5030
  ),
4624
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5031
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4625
5032
  "button",
4626
5033
  {
4627
5034
  type: "button",
@@ -4631,26 +5038,26 @@ var __defProp = Object.defineProperty;
4631
5038
  children: "注册"
4632
5039
  }
4633
5040
  ),
4634
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5041
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
4635
5042
  ] }),
4636
- editing ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
4637
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
5043
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5044
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4638
5045
  "编辑 ",
4639
5046
  editing.slug
4640
5047
  ] }),
4641
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { value: editing.label, onChange: (ev) => setEditing({ ...editing, label: ev.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
4642
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { value: editing.description, onChange: (ev) => setEditing({ ...editing, description: ev.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
4643
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
4644
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
5048
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: editing.label, onChange: (ev) => setEditing({ ...editing, label: ev.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
5049
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: editing.description, onChange: (ev) => setEditing({ ...editing, description: ev.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5050
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
5051
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
4645
5052
  ] }) : null,
4646
- form ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
4647
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
5053
+ form ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5054
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4648
5055
  form.action === "merge" ? "合并" : "归类/改名",
4649
5056
  " ",
4650
5057
  form.from,
4651
5058
  " →"
4652
5059
  ] }),
4653
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5060
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4654
5061
  "input",
4655
5062
  {
4656
5063
  value: form.to,
@@ -4660,7 +5067,7 @@ var __defProp = Object.defineProperty;
4660
5067
  style: { ...S.input, width: 190, fontSize: 12 }
4661
5068
  }
4662
5069
  ),
4663
- form.action === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { display: "inline-flex", gap: 4, flexWrap: "wrap" }, children: groups.filter((gg) => gg.hall !== majorOf(form.from)).map((gg) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5070
+ form.action === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { display: "inline-flex", gap: 4, flexWrap: "wrap" }, children: groups.filter((gg) => gg.hall !== majorOf(form.from)).map((gg) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4664
5071
  "button",
4665
5072
  {
4666
5073
  type: "button",
@@ -4671,32 +5078,32 @@ var __defProp = Object.defineProperty;
4671
5078
  },
4672
5079
  gg.hall
4673
5080
  )) }) : null,
4674
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: () => previewMerge(), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
4675
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: () => {
5081
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => previewMerge(), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
5082
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => {
4676
5083
  setForm(null);
4677
5084
  setPreview(null);
4678
5085
  setPicking(null);
4679
5086
  }, style: btn, children: "取消" }),
4680
- picking ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
4681
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5087
+ picking ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
5088
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
4682
5089
  ] }) : null,
4683
- preview ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", marginBottom: 8, padding: "6px 8px", border: "1px solid var(--dsh-mem-danger)", borderRadius: 8, fontSize: 12 }, children: [
4684
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { children: preview.notice }),
4685
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
4686
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", disabled: busy, onClick: execMerge, style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: [
5090
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", marginBottom: 8, padding: "6px 8px", border: "1px solid var(--dsh-mem-danger)", borderRadius: 8, fontSize: 12 }, children: [
5091
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { children: preview.notice }),
5092
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
5093
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", disabled: busy, onClick: execMerge, style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: [
4687
5094
  "确认执行",
4688
5095
  preview.action === "merge" ? "合并" : "归类/改名"
4689
5096
  ] }),
4690
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5097
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
4691
5098
  ] })
4692
5099
  ] }) : null,
4693
- msg ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: msg }) : null,
4694
- error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.error, children: error }) : null,
4695
- ghost ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { position: "fixed", left: ghost.x + 12, top: ghost.y + 12, zIndex: 9999, pointerEvents: "none", fontSize: 12, padding: "2px 10px", borderRadius: 999, border: "1px solid var(--dsh-mem-accent)", background: "var(--dsh-mem-bg-inset)", color: "var(--dsh-mem-accent)" }, children: ghost.text }) : null,
4696
- visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: normFilter ? "无匹配的 hall/room。" : "注册表为空。在上方注册 Hall/Room(如 dsh-plugin),或把自生长 slug「收编」进词表 —— 之后候选标注器会优先把相关记忆挂到这些 slug 上。" }) : visibleGroups.map((g) => {
5100
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: msg }) : null,
5101
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
5102
+ ghost ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { position: "fixed", left: ghost.x + 12, top: ghost.y + 12, zIndex: 9999, pointerEvents: "none", fontSize: 12, padding: "2px 10px", borderRadius: 999, border: "1px solid var(--dsh-mem-accent)", background: "var(--dsh-mem-bg-inset)", color: "var(--dsh-mem-accent)" }, children: ghost.text }) : null,
5103
+ visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: normFilter ? "无匹配的 hall/room。" : "注册表为空。在上方注册 Hall/Room(如 dsh-plugin),或把自生长 slug「收编」进词表 —— 之后候选标注器会优先把相关记忆挂到这些 slug 上。" }) : visibleGroups.map((g) => {
4697
5104
  const hallOpen = !!normFilter || expandedHalls.has(g.hall);
4698
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
4699
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5105
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
5106
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4700
5107
  "div",
4701
5108
  {
4702
5109
  "data-hall": g.hall,
@@ -4737,7 +5144,7 @@ var __defProp = Object.defineProperty;
4737
5144
  },
4738
5145
  title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
4739
5146
  children: [
4740
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5147
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4741
5148
  "button",
4742
5149
  {
4743
5150
  type: "button",
@@ -4750,13 +5157,13 @@ var __defProp = Object.defineProperty;
4750
5157
  children: hallOpen ? "▾" : "▸"
4751
5158
  }
4752
5159
  ),
4753
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5160
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
4754
5161
  g.hall,
4755
- g.label ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5162
+ g.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
4756
5163
  ] }),
4757
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
4758
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4759
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5164
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
5165
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5166
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4760
5167
  "button",
4761
5168
  {
4762
5169
  type: "button",
@@ -4777,10 +5184,10 @@ var __defProp = Object.defineProperty;
4777
5184
  const standalone = e.slug === g.hall;
4778
5185
  const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
4779
5186
  const retired = e.status === "retired";
4780
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "4px 10px", borderTop: "1px solid var(--dsh-mem-border)", opacity: retired ? 0.55 : 1 }, children: [
4781
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
4782
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
4783
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5187
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { padding: "4px 10px", borderTop: "1px solid var(--dsh-mem-border)", opacity: retired ? 0.55 : 1 }, children: [
5188
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5189
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5190
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4784
5191
  "button",
4785
5192
  {
4786
5193
  type: "button",
@@ -4790,7 +5197,7 @@ var __defProp = Object.defineProperty;
4790
5197
  children: expandedRooms.has(e.slug) ? "▾" : "▸"
4791
5198
  }
4792
5199
  ),
4793
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5200
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4794
5201
  "span",
4795
5202
  {
4796
5203
  style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
@@ -4804,20 +5211,20 @@ var __defProp = Object.defineProperty;
4804
5211
  ]
4805
5212
  }
4806
5213
  ),
4807
- e.label ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: e.label }) : null,
4808
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: count + " 条" }),
4809
- retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
4810
- (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
5214
+ e.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: e.label }) : null,
5215
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: count + " 条" }),
5216
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5217
+ (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
4811
5218
  ] }),
4812
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
4813
- !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4814
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5219
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5220
+ !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5221
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
4815
5222
  setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
4816
5223
  setForm(null);
4817
5224
  setPreview(null);
4818
5225
  setPicking(null);
4819
5226
  }, style: btn, children: "编辑" }),
4820
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5227
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4821
5228
  "button",
4822
5229
  {
4823
5230
  type: "button",
@@ -4838,43 +5245,43 @@ var __defProp = Object.defineProperty;
4838
5245
  children: picking === e.slug ? "选 hall…" : "归类"
4839
5246
  }
4840
5247
  ),
4841
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5248
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
4842
5249
  setForm({ action: "rename", from: e.slug, to: "" });
4843
5250
  setPreview(null);
4844
5251
  }, style: btn, children: "改名" }),
4845
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5252
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
4846
5253
  setForm({ action: "merge", from: e.slug, to: "" });
4847
5254
  setPreview(null);
4848
5255
  }, style: btn, children: "合并" }),
4849
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: retired ? "恢复该 Room 到词表" : "退役该 Room(存量 tags 不动)", onClick: () => retire(e.slug, retired), style: { ...btn, ...retired ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : { color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" } }, children: retired ? "恢复" : "退役" }),
4850
- !retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(e.slug, false, true), style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
5256
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: retired ? "恢复该 Room 到词表" : "退役该 Room(存量 tags 不动)", onClick: () => retire(e.slug, retired), style: { ...btn, ...retired ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : { color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" } }, children: retired ? "恢复" : "退役" }),
5257
+ !retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(e.slug, false, true), style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
4851
5258
  ] }),
4852
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5259
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
4853
5260
  ] })
4854
5261
  ] }),
4855
- expandedRooms.has(e.slug) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { margin: "4px 0 2px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
4856
- (roomRecords[e.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
4857
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
5262
+ expandedRooms.has(e.slug) ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { margin: "4px 0 2px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
5263
+ (roomRecords[e.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
5264
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
4858
5265
  " ",
4859
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
4860
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)" }, children: it.content.length > 120 ? it.content.slice(0, 120) + "…" : it.content })
5266
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5267
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)" }, children: it.content.length > 120 ? it.content.slice(0, 120) + "…" : it.content })
4861
5268
  ] }, it.id)),
4862
- (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
4863
- (roomRecords[e.slug]?.total ?? 0) > (roomRecords[e.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + roomRecords[e.slug].total + " 条,仅显示前 " + roomRecords[e.slug].items.length + " 条" }) : null
5269
+ (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
5270
+ (roomRecords[e.slug]?.total ?? 0) > (roomRecords[e.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + roomRecords[e.slug].total + " 条,仅显示前 " + roomRecords[e.slug].items.length + " 条" }) : null
4864
5271
  ] }) : null
4865
5272
  ] }, e.slug);
4866
5273
  }) : null
4867
5274
  ] }, g.hall);
4868
5275
  }),
4869
- visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginTop: 4 }, children: [
4870
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
5276
+ visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: 4 }, children: [
5277
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
4871
5278
  grownOpen ? "▾" : "▸",
4872
5279
  " 自生长未注册 · 共 ",
4873
5280
  visibleGrown.length
4874
5281
  ] }),
4875
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
4876
- grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children: visibleGrown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
4877
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5282
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
5283
+ grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children: visibleGrown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
5284
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4878
5285
  "span",
4879
5286
  {
4880
5287
  style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
@@ -4885,8 +5292,8 @@ var __defProp = Object.defineProperty;
4885
5292
  children: r.room + " · " + r.count
4886
5293
  }
4887
5294
  ),
4888
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown,原地)", onClick: () => adopt(r.room), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
4889
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5295
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown,原地)", onClick: () => adopt(r.room), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
5296
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4890
5297
  "button",
4891
5298
  {
4892
5299
  type: "button",
@@ -4913,8 +5320,8 @@ var __defProp = Object.defineProperty;
4913
5320
  }
4914
5321
 
4915
5322
  // client/src/tabs/RoomTab.tsx
4916
- var import_react19 = require("react");
4917
- var import_jsx_runtime19 = require("react/jsx-runtime");
5323
+ var import_react20 = require("react");
5324
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4918
5325
  var btn2 = {
4919
5326
  cursor: "pointer",
4920
5327
  fontSize: 12,
@@ -4935,22 +5342,22 @@ var __defProp = Object.defineProperty;
4935
5342
  }
4936
5343
  function RoomTab(props) {
4937
5344
  const rpc = props.rpc;
4938
- const [registry, setRegistry] = (0, import_react19.useState)([]);
4939
- const [counts, setCounts] = (0, import_react19.useState)([]);
4940
- const [orphanCount, setOrphanCount] = (0, import_react19.useState)(0);
4941
- const [busy, setBusy] = (0, import_react19.useState)(false);
4942
- const [msg, setMsg] = (0, import_react19.useState)(null);
4943
- const [error, setError] = (0, import_react19.useState)(null);
4944
- const [hiPriv, setHiPriv] = (0, import_react19.useState)(false);
4945
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react19.useState)(false);
4946
- const [reg, setReg] = (0, import_react19.useState)({ slug: "", label: "", description: "" });
4947
- const [editing, setEditing] = (0, import_react19.useState)(null);
4948
- const [renaming, setRenaming] = (0, import_react19.useState)(null);
4949
- const [expanded, setExpanded] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
4950
- const [retiredFilter, setRetiredFilter] = (0, import_react19.useState)("");
4951
- const [filter, setFilter] = (0, import_react19.useState)("");
4952
- const [records, setRecords] = (0, import_react19.useState)({});
4953
- const loadAll = (0, import_react19.useCallback)(() => {
5345
+ const [registry, setRegistry] = (0, import_react20.useState)([]);
5346
+ const [counts, setCounts] = (0, import_react20.useState)([]);
5347
+ const [orphanCount, setOrphanCount] = (0, import_react20.useState)(0);
5348
+ const [busy, setBusy] = (0, import_react20.useState)(false);
5349
+ const [msg, setMsg] = (0, import_react20.useState)(null);
5350
+ const [error, setError] = (0, import_react20.useState)(null);
5351
+ const [hiPriv, setHiPriv] = (0, import_react20.useState)(false);
5352
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react20.useState)(false);
5353
+ const [reg, setReg] = (0, import_react20.useState)({ slug: "", label: "", description: "" });
5354
+ const [editing, setEditing] = (0, import_react20.useState)(null);
5355
+ const [renaming, setRenaming] = (0, import_react20.useState)(null);
5356
+ const [expanded, setExpanded] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
5357
+ const [retiredFilter, setRetiredFilter] = (0, import_react20.useState)("");
5358
+ const [filter, setFilter] = (0, import_react20.useState)("");
5359
+ const [records, setRecords] = (0, import_react20.useState)({});
5360
+ const loadAll = (0, import_react20.useCallback)(() => {
4954
5361
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4955
5362
  if (r && r.ok) {
4956
5363
  setCounts(r.value.rooms ?? []);
@@ -4959,13 +5366,13 @@ var __defProp = Object.defineProperty;
4959
5366
  }
4960
5367
  }).catch(() => void 0);
4961
5368
  }, [rpc]);
4962
- const loadHiPriv = (0, import_react19.useCallback)(() => {
5369
+ const loadHiPriv = (0, import_react20.useCallback)(() => {
4963
5370
  rpc("dsh-memory/settings-get", {}).then((r) => {
4964
5371
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4965
5372
  }).catch(() => {
4966
5373
  });
4967
5374
  }, [rpc]);
4968
- (0, import_react19.useEffect)(() => {
5375
+ (0, import_react20.useEffect)(() => {
4969
5376
  loadAll();
4970
5377
  loadHiPriv();
4971
5378
  }, [loadAll, loadHiPriv]);
@@ -5055,7 +5462,10 @@ var __defProp = Object.defineProperty;
5055
5462
  loadAll();
5056
5463
  if (expanded.has(slug)) {
5057
5464
  const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
5058
- if (rr && rr.ok) setRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
5465
+ if (rr && rr.ok) {
5466
+ registerTypeCatalog(rr.value.typeCatalog);
5467
+ setRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
5468
+ }
5059
5469
  }
5060
5470
  } else setError(r && r.error ? r.error.message : "操作失败");
5061
5471
  });
@@ -5084,6 +5494,7 @@ var __defProp = Object.defineProperty;
5084
5494
  }
5085
5495
  const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
5086
5496
  if (r && r.ok) {
5497
+ registerTypeCatalog(r.value.typeCatalog);
5087
5498
  const next = new Set(expanded);
5088
5499
  next.add(slug);
5089
5500
  setExpanded(next);
@@ -5103,11 +5514,11 @@ var __defProp = Object.defineProperty;
5103
5514
  const visibleRows = normFilter ? rows.filter(
5104
5515
  (row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
5105
5516
  ) : rows;
5106
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
5107
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
5108
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
5109
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5110
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5517
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5518
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
5519
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
5520
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5521
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5111
5522
  const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
5112
5523
  if (!r.ok) {
5113
5524
  setError(r.error.message);
@@ -5118,7 +5529,7 @@ var __defProp = Object.defineProperty;
5118
5529
  "导出孤儿 · ",
5119
5530
  orphanCount
5120
5531
  ] }),
5121
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5532
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5122
5533
  "button",
5123
5534
  {
5124
5535
  type: "button",
@@ -5129,35 +5540,35 @@ var __defProp = Object.defineProperty;
5129
5540
  children: hiPriv ? "高权限:开" : "高权限:关"
5130
5541
  }
5131
5542
  ),
5132
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5543
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5133
5544
  ] }),
5134
- editing ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5135
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
5545
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5546
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5136
5547
  "编辑 ",
5137
5548
  editing.slug
5138
5549
  ] }),
5139
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: editing.label, onChange: (e) => setEditing({ ...editing, label: e.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
5140
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: editing.description, onChange: (e) => setEditing({ ...editing, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5141
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
5142
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5550
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: editing.label, onChange: (e) => setEditing({ ...editing, label: e.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
5551
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: editing.description, onChange: (e) => setEditing({ ...editing, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5552
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
5553
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5143
5554
  ] }) : null,
5144
- renaming ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5145
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
5555
+ renaming ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
5556
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5146
5557
  "改名 ",
5147
5558
  renaming.slug,
5148
5559
  " →"
5149
5560
  ] }),
5150
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: renaming.to, onChange: (e) => setRenaming({ ...renaming, to: e.target.value }), placeholder: "新 slug(可两级:hall/子类)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5151
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: previewRename, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
5152
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: execRename, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "确认执行" }),
5153
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
5154
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5561
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: renaming.to, onChange: (e) => setRenaming({ ...renaming, to: e.target.value }), placeholder: "新 slug(可两级:hall/子类)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5562
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: previewRename, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
5563
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: execRename, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "确认执行" }),
5564
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
5565
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5155
5566
  ] }) : null,
5156
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
5157
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "退场筛选" }),
5567
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
5568
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "退场筛选" }),
5158
5569
  [["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
5159
5570
  const on = retiredFilter === val;
5160
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5571
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5161
5572
  "button",
5162
5573
  {
5163
5574
  type: "button",
@@ -5177,8 +5588,8 @@ var __defProp = Object.defineProperty;
5177
5588
  val
5178
5589
  );
5179
5590
  }),
5180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5181
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5591
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5592
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5182
5593
  "input",
5183
5594
  {
5184
5595
  value: filter,
@@ -5187,24 +5598,24 @@ var __defProp = Object.defineProperty;
5187
5598
  style: { ...S.input, width: 230, fontSize: 12 }
5188
5599
  }
5189
5600
  ),
5190
- filter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5601
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5191
5602
  ] }),
5192
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5193
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: reg.slug, onChange: (e) => setReg({ ...reg, slug: e.target.value }), placeholder: "slug(如 dsh-plugin 或 dsh-plugin/merge)", disabled: !hiPriv || busy, style: { ...S.input, width: 210, fontSize: 12 } }),
5194
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: reg.label, onChange: (e) => setReg({ ...reg, label: e.target.value }), placeholder: "名称(可中文)", disabled: !hiPriv || busy, style: { ...S.input, width: 110, fontSize: 12 } }),
5195
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { value: reg.description, onChange: (e) => setReg({ ...reg, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: !hiPriv || busy, style: { ...S.input, width: 170, fontSize: 12 } }),
5196
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: !hiPriv || busy || !reg.slug.trim(), onClick: register, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy || !reg.slug.trim() ? 0.5 : 1 }, children: "注册" }),
5197
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5603
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5604
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: reg.slug, onChange: (e) => setReg({ ...reg, slug: e.target.value }), placeholder: "slug(如 dsh-plugin 或 dsh-plugin/merge)", disabled: !hiPriv || busy, style: { ...S.input, width: 210, fontSize: 12 } }),
5605
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: reg.label, onChange: (e) => setReg({ ...reg, label: e.target.value }), placeholder: "名称(可中文)", disabled: !hiPriv || busy, style: { ...S.input, width: 110, fontSize: 12 } }),
5606
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: reg.description, onChange: (e) => setReg({ ...reg, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: !hiPriv || busy, style: { ...S.input, width: 170, fontSize: 12 } }),
5607
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: !hiPriv || busy || !reg.slug.trim(), onClick: register, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy || !reg.slug.trim() ? 0.5 : 1 }, children: "注册" }),
5608
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5198
5609
  ] }),
5199
- msg ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: msg }) : null,
5200
- error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
5201
- visibleRows.length === 0 ? normFilter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: "无匹配的 Room。" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: "暂无 Room:对话/反刍会从标签涌现,或在上方注册。" }) : visibleRows.map((row2) => {
5610
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.hint, children: msg }) : null,
5611
+ error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5612
+ visibleRows.length === 0 ? normFilter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: S.intro, children: "无匹配的 Room。" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: S.intro, children: "暂无 Room:对话/反刍会从标签涌现,或在上方注册。" }) : visibleRows.map((row2) => {
5202
5613
  const e = row2.entry;
5203
5614
  const retired = e?.status === "retired";
5204
5615
  const grownOnly = !e;
5205
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
5206
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
5207
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5616
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
5617
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
5618
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5208
5619
  "button",
5209
5620
  {
5210
5621
  type: "button",
@@ -5214,28 +5625,28 @@ var __defProp = Object.defineProperty;
5214
5625
  children: expanded.has(row2.slug) ? "▾" : "▸"
5215
5626
  }
5216
5627
  ),
5217
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5218
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
5628
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5629
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
5219
5630
  row2.slug,
5220
5631
  e?.source === "pre-registered" ? " ⭐" : ""
5221
5632
  ] }),
5222
- e?.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: e.label }) : null,
5223
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
5224
- grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
5225
- retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5226
- (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
5633
+ e?.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: e.label }) : null,
5634
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
5635
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
5636
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5637
+ (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
5227
5638
  ] }),
5228
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5229
- !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5230
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5639
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5640
+ !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5641
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5231
5642
  setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
5232
5643
  setRenaming(null);
5233
5644
  }, style: btn2, children: "编辑" }),
5234
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5645
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5235
5646
  setRenaming({ slug: row2.slug, to: "" });
5236
5647
  setEditing(null);
5237
5648
  }, style: btn2, children: "改名" }),
5238
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5649
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5239
5650
  "button",
5240
5651
  {
5241
5652
  type: "button",
@@ -5246,29 +5657,29 @@ var __defProp = Object.defineProperty;
5246
5657
  children: retired ? "恢复" : "退役"
5247
5658
  }
5248
5659
  ),
5249
- !retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(row2.slug, false, true), style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
5660
+ !retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(row2.slug, false, true), style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
5250
5661
  ] }),
5251
- grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5252
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown)", onClick: () => adopt(row2.slug), style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
5253
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
5662
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5663
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown)", onClick: () => adopt(row2.slug), style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
5664
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
5254
5665
  setRenaming(null);
5255
5666
  retire(row2.slug, false, true);
5256
5667
  }, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
5257
5668
  ] }) : null,
5258
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5669
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5259
5670
  ] })
5260
5671
  ] }),
5261
- expanded.has(row2.slug) ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { margin: "0 10px 6px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
5262
- (records[row2.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
5263
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
5672
+ expanded.has(row2.slug) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { margin: "0 10px 6px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
5673
+ (records[row2.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
5674
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5264
5675
  " ",
5265
- it.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5676
+ it.retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5266
5677
  " ",
5267
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5268
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)", opacity: it.retired ? 0.55 : 1 }, children: it.content.length > 140 ? it.content.slice(0, 140) + "…" : it.content })
5678
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5679
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)", opacity: it.retired ? 0.55 : 1 }, children: it.content.length > 140 ? it.content.slice(0, 140) + "…" : it.content })
5269
5680
  ] }, it.id)),
5270
- (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
5271
- (records[row2.slug]?.total ?? 0) > (records[row2.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + records[row2.slug].total + " 条,仅显示前 " + records[row2.slug].items.length + " 条" }) : null
5681
+ (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
5682
+ (records[row2.slug]?.total ?? 0) > (records[row2.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + records[row2.slug].total + " 条,仅显示前 " + records[row2.slug].items.length + " 条" }) : null
5272
5683
  ] }) : null
5273
5684
  ] }, row2.slug);
5274
5685
  })
@@ -5276,13 +5687,13 @@ var __defProp = Object.defineProperty;
5276
5687
  }
5277
5688
 
5278
5689
  // client/src/tabs/ScenesTab.tsx
5279
- var import_react20 = require("react");
5280
- var import_jsx_runtime20 = require("react/jsx-runtime");
5690
+ var import_react21 = require("react");
5691
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5281
5692
  function SceneCard(props) {
5282
5693
  const s = props.s;
5283
- const [open, setOpen] = (0, import_react20.useState)(false);
5284
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
5285
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5694
+ const [open, setOpen] = (0, import_react21.useState)(false);
5695
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
5696
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5286
5697
  "div",
5287
5698
  {
5288
5699
  style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
@@ -5290,23 +5701,23 @@ var __defProp = Object.defineProperty;
5290
5701
  setOpen(!open);
5291
5702
  },
5292
5703
  children: [
5293
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
5294
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.sceneTitle, children: s.path }),
5295
- s.heat ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
5296
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5297
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
5704
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
5705
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.sceneTitle, children: s.path }),
5706
+ s.heat ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
5707
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5708
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
5298
5709
  ]
5299
5710
  }
5300
5711
  ),
5301
- s.summary ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
5302
- open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
5712
+ s.summary ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
5713
+ open ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
5303
5714
  ] });
5304
5715
  }
5305
5716
  function ScenesTab(props) {
5306
5717
  const rpc = props.rpc;
5307
- const [items, setItems] = (0, import_react20.useState)(null);
5308
- const [error, setError] = (0, import_react20.useState)(null);
5309
- const load = (0, import_react20.useCallback)(() => {
5718
+ const [items, setItems] = (0, import_react21.useState)(null);
5719
+ const [error, setError] = (0, import_react21.useState)(null);
5720
+ const load = (0, import_react21.useCallback)(() => {
5310
5721
  rpc("dsh-memory/scenes", {}).then((r) => {
5311
5722
  if (r && r.ok) {
5312
5723
  setItems(r.value.items);
@@ -5316,25 +5727,25 @@ var __defProp = Object.defineProperty;
5316
5727
  setError(String(e && e.message || e));
5317
5728
  });
5318
5729
  }, [rpc]);
5319
- (0, import_react20.useEffect)(() => {
5730
+ (0, import_react21.useEffect)(() => {
5320
5731
  load();
5321
5732
  }, [load]);
5322
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5323
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
5324
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
5325
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5326
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(NButton, { onClick: load, children: "刷新" })
5733
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
5734
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
5735
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
5736
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5737
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(NButton, { onClick: load, children: "刷新" })
5327
5738
  ] }),
5328
- error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5329
- items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
5739
+ error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.error, children: error }) : null,
5740
+ items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
5330
5741
  (items || []).map((s) => {
5331
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SceneCard, { s }, s.path);
5742
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SceneCard, { s }, s.path);
5332
5743
  })
5333
5744
  ] });
5334
5745
  }
5335
5746
 
5336
5747
  // client/src/panel.tsx
5337
- var import_jsx_runtime21 = require("react/jsx-runtime");
5748
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5338
5749
  var TABS = [
5339
5750
  ["overview", "概览"],
5340
5751
  ["records", "记忆"],
@@ -5355,10 +5766,10 @@ var __defProp = Object.defineProperty;
5355
5766
  ];
5356
5767
  function MemoryPanel(props) {
5357
5768
  const rpc = props.rpc;
5358
- const [tab, setTab] = (0, import_react21.useState)("overview");
5359
- const [skin, setSkinState] = (0, import_react21.useState)(() => getSkin());
5769
+ const [tab, setTab] = (0, import_react22.useState)("overview");
5770
+ const [skin, setSkinState] = (0, import_react22.useState)(() => getSkin());
5360
5771
  ensureThemeStyle(skin);
5361
- (0, import_react21.useEffect)(() => {
5772
+ (0, import_react22.useEffect)(() => {
5362
5773
  applySkin(skin);
5363
5774
  watchSidebarIcon();
5364
5775
  }, [skin]);
@@ -5367,21 +5778,21 @@ var __defProp = Object.defineProperty;
5367
5778
  setSkinState(next);
5368
5779
  };
5369
5780
  let body;
5370
- if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OverviewTab, { rpc });
5371
- else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RecordsTab, { rpc });
5372
- else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ConflictsTab, { rpc });
5373
- else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ScenesTab, { rpc });
5374
- else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RoomsTab, { rpc });
5375
- else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RoomTab, { rpc });
5376
- else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PersonaTab, { rpc });
5377
- else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CostTab, { rpc });
5378
- else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ConnectTab, { rpc });
5379
- else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SkillsTab, { rpc });
5380
- else body = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LogTab, { rpc });
5381
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
5382
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
5383
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
5384
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5781
+ if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(OverviewTab, { rpc });
5782
+ else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RecordsTab, { rpc });
5783
+ else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConflictsTab, { rpc });
5784
+ else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenesTab, { rpc });
5785
+ else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomsTab, { rpc });
5786
+ else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomTab, { rpc });
5787
+ else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PersonaTab, { rpc });
5788
+ else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CostTab, { rpc });
5789
+ else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConnectTab, { rpc });
5790
+ else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SkillsTab, { rpc });
5791
+ else body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LogTab, { rpc });
5792
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
5793
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
5794
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
5795
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5385
5796
  "div",
5386
5797
  {
5387
5798
  style: {
@@ -5393,8 +5804,8 @@ var __defProp = Object.defineProperty;
5393
5804
  marginBottom: 10
5394
5805
  },
5395
5806
  children: [
5396
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
5397
- SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5807
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
5808
+ SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5398
5809
  "button",
5399
5810
  {
5400
5811
  className: skin === s[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5407,8 +5818,8 @@ var __defProp = Object.defineProperty;
5407
5818
  ]
5408
5819
  }
5409
5820
  ),
5410
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5411
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5821
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5822
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5412
5823
  "button",
5413
5824
  {
5414
5825
  className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5425,7 +5836,7 @@ var __defProp = Object.defineProperty;
5425
5836
  }
5426
5837
 
5427
5838
  // client/src/pill/MemoryModePill.tsx
5428
- var import_react25 = require("react");
5839
+ var import_react26 = require("react");
5429
5840
 
5430
5841
  // src/util/context-occupancy.ts
5431
5842
  var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
@@ -5450,8 +5861,8 @@ var __defProp = Object.defineProperty;
5450
5861
  var panelListeners = /* @__PURE__ */ new Set();
5451
5862
  var panelWasOpen = false;
5452
5863
  var snapshotListeners = /* @__PURE__ */ new Set();
5453
- function initOccupancyIndicator(call) {
5454
- statsCall = call;
5864
+ function initOccupancyIndicator(call2) {
5865
+ statsCall = call2;
5455
5866
  }
5456
5867
  function noteOccupancySession(sessionId) {
5457
5868
  if (sessionId === activeSessionId) return;
@@ -5741,23 +6152,23 @@ var __defProp = Object.defineProperty;
5741
6152
  }
5742
6153
 
5743
6154
  // client/src/pill/WingWheel.tsx
5744
- var import_react24 = require("react");
6155
+ var import_react25 = require("react");
5745
6156
 
5746
6157
  // client/src/pill/SessionInfoArea.tsx
5747
- var import_react22 = require("react");
5748
- var import_jsx_runtime22 = require("react/jsx-runtime");
6158
+ var import_react23 = require("react");
6159
+ var import_jsx_runtime23 = require("react/jsx-runtime");
5749
6160
  function sinfoCell(val, label, title) {
5750
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { title: title || void 0, children: [
5751
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
5752
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
6161
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { title: title || void 0, children: [
6162
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
6163
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
5753
6164
  ] });
5754
6165
  }
5755
6166
  function SessionInfoArea(props) {
5756
6167
  const rpc = props.rpc;
5757
6168
  const sessionId = props.sessionId;
5758
- const [stats, setStats] = (0, import_react22.useState)(void 0);
5759
- const busyRef = (0, import_react22.useRef)(false);
5760
- (0, import_react22.useEffect)(() => {
6169
+ const [stats, setStats] = (0, import_react23.useState)(void 0);
6170
+ const busyRef = (0, import_react23.useRef)(false);
6171
+ (0, import_react23.useEffect)(() => {
5761
6172
  if (!rpc || !sessionId) return void 0;
5762
6173
  let alive = true;
5763
6174
  let timer = null;
@@ -5790,7 +6201,7 @@ var __defProp = Object.defineProperty;
5790
6201
  }, [rpc, sessionId]);
5791
6202
  if (stats === null) return null;
5792
6203
  if (stats === void 0) {
5793
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6204
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
5794
6205
  sinfoCell("…", "召回命中"),
5795
6206
  sinfoCell("…", "攒批进度"),
5796
6207
  sinfoCell("…", "本会话记忆"),
@@ -5839,30 +6250,30 @@ var __defProp = Object.defineProperty;
5839
6250
  else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
5840
6251
  }
5841
6252
  const ago = fmtAgo(gl.lastExtractAt);
5842
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-sinfo", children: [
5843
- warn ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
5844
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6253
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6254
+ warn ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
6255
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
5845
6256
  sinfoCell(rcVal, rcLabel, rcTitle),
5846
6257
  sinfoCell(dVal, dLabel, dTitle),
5847
6258
  sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
5848
6259
  sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
5849
6260
  ] }),
5850
- note ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
5851
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
6261
+ note ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
6262
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
5852
6263
  ] });
5853
6264
  }
5854
6265
 
5855
6266
  // client/src/pill/SessionRecalledArea.tsx
5856
- var import_react23 = require("react");
5857
- var import_jsx_runtime23 = require("react/jsx-runtime");
6267
+ var import_react24 = require("react");
6268
+ var import_jsx_runtime24 = require("react/jsx-runtime");
5858
6269
  var SHOW_CAP = 6;
5859
6270
  var POLL_MS2 = 4e3;
5860
6271
  var MATURITY_LABEL = { high: "成熟·高", mid: "成熟·中", low: "成熟·低" };
5861
6272
  function SessionRecalledArea(props) {
5862
6273
  const rpc = props.rpc;
5863
6274
  const sessionId = props.sessionId;
5864
- const [records, setRecords] = (0, import_react23.useState)(void 0);
5865
- (0, import_react23.useEffect)(() => {
6275
+ const [records, setRecords] = (0, import_react24.useState)(void 0);
6276
+ (0, import_react24.useEffect)(() => {
5866
6277
  if (!rpc || !sessionId) return void 0;
5867
6278
  let alive = true;
5868
6279
  let timer = null;
@@ -5871,7 +6282,10 @@ var __defProp = Object.defineProperty;
5871
6282
  const token = ++seq;
5872
6283
  rpc("dsh-memory/session-recalled", { sessionId }).then((r) => {
5873
6284
  if (!alive || token !== seq) return;
5874
- if (r && r.ok && r.value) setRecords(r.value.records);
6285
+ if (r && r.ok && r.value) {
6286
+ registerTypeCatalog(r.value.typeCatalog);
6287
+ setRecords(r.value.records);
6288
+ }
5875
6289
  }).catch(() => {
5876
6290
  }).then(() => {
5877
6291
  if (alive) timer = setTimeout(tick, POLL_MS2);
@@ -5884,32 +6298,38 @@ var __defProp = Object.defineProperty;
5884
6298
  };
5885
6299
  }, [rpc, sessionId]);
5886
6300
  if (records === void 0) return null;
5887
- const recentFirst = [...records].reverse();
6301
+ const rows = records.filter((r) => r.superseded !== true || r.retired === true);
6302
+ const recentFirst = [...rows].reverse();
5888
6303
  const shown = recentFirst.slice(0, SHOW_CAP);
5889
6304
  const hidden = recentFirst.length - shown.length;
5890
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo", children: [
5891
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6305
+ const allSuperseded = rows.length === 0 && records.length > 0;
6306
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6307
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5892
6308
  "div",
5893
6309
  {
5894
6310
  style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 6 },
5895
- title: "本会话召回注入、且目前仍在上下文里的记忆(压缩/清空后自动消失,不是常驻)",
5896
- children: "本会话召回 " + records.length + " 条"
6311
+ title: "本会话召回、且正文仍在上下文里的记忆(正文被摘要顶掉的已折叠不显示;清空会话才清除;不是常驻注入)",
6312
+ children: "本会话召回 " + rows.length + " 条"
5897
6313
  }
5898
6314
  ),
5899
- records.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", lineHeight: "16px" }, children: "还没召回到记忆(聊几轮后按相关性自动浮现)" }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
5900
- shown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: rowStyle, title: rowTitle(r), children: [
5901
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6315
+ allSuperseded ? (
6316
+ // 不是“还没召回到”——那批确实注入过,只是正文已被摘要顶掉。说谎的空态比不显示更糟。
6317
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", lineHeight: "16px" }, children: "本会话注入过的 " + records.length + " 条记忆正文已被摘要取代" })
6318
+ ) : records.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", lineHeight: "16px" }, children: "还没召回到记忆(聊几轮后按相关性自动浮现)" }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
6319
+ shown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: rowStyle, title: rowTitle(r), children: [
6320
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5902
6321
  "span",
5903
6322
  {
5904
- className: "dsh-mem-tag dsh-mem-tag-" + r.type,
6323
+ className: tagClass(r.type),
5905
6324
  style: { flexShrink: 0, whiteSpace: "nowrap" },
5906
- children: TYPE_LABELS[r.type] || r.type
6325
+ children: typeLabel(r.type)
5907
6326
  }
5908
6327
  ),
5909
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "dsh-mem-sinfo-val", style: textStyle, children: r.content }),
5910
- r.maturity ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: 10, color: "var(--dsh-mem-text-3)", whiteSpace: "nowrap", flexShrink: 0 }, children: MATURITY_LABEL[r.maturity] }) : null
6328
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "dsh-mem-sinfo-val", style: r.retired === true ? STALE_TEXT_STYLE : textStyle, children: r.content }),
6329
+ r.retired === true ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 10, color: "var(--dsh-mem-text-3)", whiteSpace: "nowrap", flexShrink: 0 }, children: "已判过时" }) : null,
6330
+ r.maturity ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 10, color: "var(--dsh-mem-text-3)", whiteSpace: "nowrap", flexShrink: 0 }, children: MATURITY_LABEL[r.maturity] }) : null
5911
6331
  ] }, r.id)),
5912
- hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "+ " + hidden + " 条更早召回(详见面板「记忆」页)" }) : null
6332
+ hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "+ " + hidden + " 条更早召回(详见面板「记忆」页)" }) : null
5913
6333
  ] })
5914
6334
  ] });
5915
6335
  }
@@ -5929,14 +6349,15 @@ var __defProp = Object.defineProperty;
5929
6349
  WebkitBoxOrient: "vertical",
5930
6350
  overflow: "hidden"
5931
6351
  };
6352
+ var STALE_TEXT_STYLE = { ...textStyle, textDecoration: "line-through" };
5932
6353
  function rowTitle(r) {
5933
- const head = "[" + (TYPE_LABELS[r.type] || r.type) + "] " + r.content;
6354
+ const head = "[" + typeLabel(r.type) + "] " + r.content;
5934
6355
  const sc = r.usageScenario && r.usageScenario.length > 0 ? "\n使用场景:" + r.usageScenario.join(";") : "";
5935
6356
  return head + sc;
5936
6357
  }
5937
6358
 
5938
6359
  // client/src/pill/WingWheel.tsx
5939
- var import_jsx_runtime24 = require("react/jsx-runtime");
6360
+ var import_jsx_runtime25 = require("react/jsx-runtime");
5940
6361
  var SIZE = 196;
5941
6362
  var CENTER = SIZE / 2;
5942
6363
  var R = 64;
@@ -5979,17 +6400,17 @@ var __defProp = Object.defineProperty;
5979
6400
  function WingWheel(props) {
5980
6401
  ensureThemeStyle();
5981
6402
  const isOff = props.mode === "off";
5982
- const [overview, setOverview] = (0, import_react24.useState)(null);
5983
- const [backfillBusy, setBackfillBusy] = (0, import_react24.useState)(false);
5984
- const [localError, setLocalError] = (0, import_react24.useState)(null);
5985
- const timersRef = (0, import_react24.useRef)([]);
5986
- (0, import_react24.useEffect)(
6403
+ const [overview, setOverview] = (0, import_react25.useState)(null);
6404
+ const [backfillBusy, setBackfillBusy] = (0, import_react25.useState)(false);
6405
+ const [localError, setLocalError] = (0, import_react25.useState)(null);
6406
+ const timersRef = (0, import_react25.useRef)([]);
6407
+ (0, import_react25.useEffect)(
5987
6408
  () => () => {
5988
6409
  for (const t of timersRef.current) window.clearTimeout(t);
5989
6410
  },
5990
6411
  []
5991
6412
  );
5992
- (0, import_react24.useEffect)(() => {
6413
+ (0, import_react25.useEffect)(() => {
5993
6414
  let alive = true;
5994
6415
  props.rpc("dsh-memory/wing-overview", {}).then((r) => {
5995
6416
  if (!alive) return;
@@ -6035,28 +6456,28 @@ var __defProp = Object.defineProperty;
6035
6456
  finish();
6036
6457
  });
6037
6458
  };
6038
- const boxRef = (0, import_react24.useRef)(null);
6039
- const startRef = (0, import_react24.useRef)(null);
6040
- const movedRef = (0, import_react24.useRef)(false);
6041
- const downIndexRef = (0, import_react24.useRef)(null);
6042
- const dragTargetRef = (0, import_react24.useRef)(null);
6043
- const [drag, setDrag] = (0, import_react24.useState)(null);
6459
+ const boxRef = (0, import_react25.useRef)(null);
6460
+ const startRef = (0, import_react25.useRef)(null);
6461
+ const movedRef = (0, import_react25.useRef)(false);
6462
+ const downIndexRef = (0, import_react25.useRef)(null);
6463
+ const dragTargetRef = (0, import_react25.useRef)(null);
6464
+ const [drag, setDrag] = (0, import_react25.useState)(null);
6044
6465
  const lockedIndex = (() => {
6045
6466
  if (props.halls.length !== 1 || !overview) return null;
6046
6467
  const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
6047
6468
  return i >= 0 ? i : null;
6048
6469
  })();
6049
6470
  const activeCorner = drag ? drag.index : lockedIndex;
6050
- const blockPosRef = (0, import_react24.useRef)(
6471
+ const blockPosRef = (0, import_react25.useRef)(
6051
6472
  activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
6052
6473
  );
6053
- const blockTargetRef = (0, import_react24.useRef)(blockPosRef.current);
6054
- const [blockPos, setBlockPos] = (0, import_react24.useState)(blockPosRef.current);
6055
- (0, import_react24.useEffect)(() => {
6474
+ const blockTargetRef = (0, import_react25.useRef)(blockPosRef.current);
6475
+ const [blockPos, setBlockPos] = (0, import_react25.useState)(blockPosRef.current);
6476
+ (0, import_react25.useEffect)(() => {
6056
6477
  blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
6057
6478
  }, [activeCorner]);
6058
- const reducedMotionRef = (0, import_react24.useRef)(false);
6059
- (0, import_react24.useEffect)(() => {
6479
+ const reducedMotionRef = (0, import_react25.useRef)(false);
6480
+ (0, import_react25.useEffect)(() => {
6060
6481
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
6061
6482
  const apply2 = () => {
6062
6483
  reducedMotionRef.current = mq.matches;
@@ -6065,7 +6486,7 @@ var __defProp = Object.defineProperty;
6065
6486
  mq.addEventListener("change", apply2);
6066
6487
  return () => mq.removeEventListener("change", apply2);
6067
6488
  }, []);
6068
- (0, import_react24.useEffect)(() => {
6489
+ (0, import_react25.useEffect)(() => {
6069
6490
  let raf = 0;
6070
6491
  const loop = () => {
6071
6492
  const cur = blockPosRef.current;
@@ -6154,8 +6575,8 @@ var __defProp = Object.defineProperty;
6154
6575
  }).join(" ");
6155
6576
  const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
6156
6577
  const boundariesDisabled = props.halls.length === 0 || isOff;
6157
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { width: SIZE }, children: [
6158
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6578
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { width: SIZE }, children: [
6579
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6159
6580
  "div",
6160
6581
  {
6161
6582
  ref: boxRef,
@@ -6165,7 +6586,7 @@ var __defProp = Object.defineProperty;
6165
6586
  onPointerUp: onBoxUp,
6166
6587
  onPointerCancel: onBoxUp,
6167
6588
  children: [
6168
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6589
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6169
6590
  "svg",
6170
6591
  {
6171
6592
  width: SIZE,
@@ -6173,7 +6594,7 @@ var __defProp = Object.defineProperty;
6173
6594
  style: { position: "absolute", inset: 0, pointerEvents: "none" },
6174
6595
  "aria-hidden": "true",
6175
6596
  children: [
6176
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6597
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6177
6598
  "polygon",
6178
6599
  {
6179
6600
  points: polyPoints,
@@ -6184,7 +6605,7 @@ var __defProp = Object.defineProperty;
6184
6605
  opacity: 0.45
6185
6606
  }
6186
6607
  ),
6187
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6608
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6188
6609
  "polygon",
6189
6610
  {
6190
6611
  points: polyPoints,
@@ -6195,7 +6616,7 @@ var __defProp = Object.defineProperty;
6195
6616
  ),
6196
6617
  [0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
6197
6618
  const p = cornerPos(i);
6198
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6619
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6199
6620
  "line",
6200
6621
  {
6201
6622
  x1: CENTER,
@@ -6211,7 +6632,7 @@ var __defProp = Object.defineProperty;
6211
6632
  ]
6212
6633
  }
6213
6634
  ),
6214
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6635
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6215
6636
  "div",
6216
6637
  {
6217
6638
  "aria-hidden": "true",
@@ -6230,7 +6651,7 @@ var __defProp = Object.defineProperty;
6230
6651
  }
6231
6652
  }
6232
6653
  ),
6233
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6654
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6234
6655
  "button",
6235
6656
  {
6236
6657
  type: "button",
@@ -6264,7 +6685,7 @@ var __defProp = Object.defineProperty;
6264
6685
  const dim = activeCorner != null && !active;
6265
6686
  const empty = count === 0;
6266
6687
  const p = cornerPos(i);
6267
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6688
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6268
6689
  "div",
6269
6690
  {
6270
6691
  title: id ? `「${label}」${count ?? 0} 条
@@ -6293,8 +6714,8 @@ var __defProp = Object.defineProperty;
6293
6714
  zIndex: 2
6294
6715
  },
6295
6716
  children: [
6296
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: label }),
6297
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
6717
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }),
6718
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
6298
6719
  ]
6299
6720
  },
6300
6721
  id ?? i
@@ -6303,7 +6724,7 @@ var __defProp = Object.defineProperty;
6303
6724
  ]
6304
6725
  }
6305
6726
  ),
6306
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6727
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6307
6728
  "div",
6308
6729
  {
6309
6730
  title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
@@ -6317,9 +6738,9 @@ var __defProp = Object.defineProperty;
6317
6738
  pointerEvents: boundariesDisabled ? "none" : void 0
6318
6739
  },
6319
6740
  children: [
6320
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
6321
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
6322
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6741
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
6742
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
6743
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6323
6744
  Segmented,
6324
6745
  {
6325
6746
  value: props.hallIncludeUnlabeled ? "in" : "ex",
@@ -6330,7 +6751,7 @@ var __defProp = Object.defineProperty;
6330
6751
  onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
6331
6752
  }
6332
6753
  ),
6333
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6754
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6334
6755
  Segmented,
6335
6756
  {
6336
6757
  value: props.hallIncludeGeneral ? "in" : "ex",
@@ -6345,7 +6766,7 @@ var __defProp = Object.defineProperty;
6345
6766
  ]
6346
6767
  }
6347
6768
  ),
6348
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6769
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6349
6770
  Segmented,
6350
6771
  {
6351
6772
  value: isOff ? "off" : "on",
@@ -6360,7 +6781,7 @@ var __defProp = Object.defineProperty;
6360
6781
  onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
6361
6782
  }
6362
6783
  ) }),
6363
- props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6784
+ props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6364
6785
  Segmented,
6365
6786
  {
6366
6787
  value: props.recall === null ? "follow" : props.recall ? "on" : "off",
@@ -6373,7 +6794,7 @@ var __defProp = Object.defineProperty;
6373
6794
  onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
6374
6795
  }
6375
6796
  ) }) : null,
6376
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6797
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6377
6798
  "div",
6378
6799
  {
6379
6800
  style: {
@@ -6384,8 +6805,8 @@ var __defProp = Object.defineProperty;
6384
6805
  marginTop: 10
6385
6806
  },
6386
6807
  children: [
6387
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
6388
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6808
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
6809
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6389
6810
  ActionButton,
6390
6811
  {
6391
6812
  label: backfillBusy ? "回填中…" : "回填",
@@ -6397,13 +6818,13 @@ var __defProp = Object.defineProperty;
6397
6818
  ]
6398
6819
  }
6399
6820
  ),
6400
- props.error || localError ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error || localError }) : null,
6401
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SessionRecalledArea, { rpc: props.rpc, sessionId: props.sessionId }),
6402
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
6821
+ props.error || localError ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error || localError }) : null,
6822
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionRecalledArea, { rpc: props.rpc, sessionId: props.sessionId }),
6823
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
6403
6824
  ] });
6404
6825
  }
6405
6826
  function Row(props) {
6406
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6827
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6407
6828
  "div",
6408
6829
  {
6409
6830
  style: {
@@ -6413,7 +6834,7 @@ var __defProp = Object.defineProperty;
6413
6834
  marginTop: 10
6414
6835
  },
6415
6836
  children: [
6416
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6837
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6417
6838
  props.children
6418
6839
  ]
6419
6840
  }
@@ -6421,9 +6842,9 @@ var __defProp = Object.defineProperty;
6421
6842
  }
6422
6843
  var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
6423
6844
  function useViewportClamp(popRef) {
6424
- const shiftRef = (0, import_react24.useRef)(0);
6425
- const [shiftX, setShiftX] = (0, import_react24.useState)(0);
6426
- (0, import_react24.useEffect)(() => {
6845
+ const shiftRef = (0, import_react25.useRef)(0);
6846
+ const [shiftX, setShiftX] = (0, import_react25.useState)(0);
6847
+ (0, import_react25.useEffect)(() => {
6427
6848
  const clamp = () => {
6428
6849
  const el = popRef.current;
6429
6850
  if (!el) return;
@@ -6453,24 +6874,24 @@ var __defProp = Object.defineProperty;
6453
6874
  }
6454
6875
 
6455
6876
  // client/src/pill/MemoryModePill.tsx
6456
- var import_jsx_runtime25 = require("react/jsx-runtime");
6877
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6457
6878
  function MemoryModePill(props) {
6458
6879
  const rpc = props.rpc;
6459
6880
  const sessionId = props.sessionId || props.session && props.session.sessionId;
6460
- const [mode, setMode] = (0, import_react25.useState)(null);
6461
- const [recall, setRecall] = (0, import_react25.useState)(null);
6462
- const [recallResolved, setRecallResolved] = (0, import_react25.useState)(true);
6463
- const [halls, setWings] = (0, import_react25.useState)([]);
6464
- const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react25.useState)(true);
6465
- const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react25.useState)(false);
6466
- const [wingLabels, setHallLabels] = (0, import_react25.useState)({});
6467
- const [error, setError] = (0, import_react25.useState)(null);
6468
- const [open, setOpen] = (0, import_react25.useState)(false);
6469
- const wrapRef = (0, import_react25.useRef)(null);
6470
- const popRef = (0, import_react25.useRef)(null);
6881
+ const [mode, setMode] = (0, import_react26.useState)(null);
6882
+ const [recall, setRecall] = (0, import_react26.useState)(null);
6883
+ const [recallResolved, setRecallResolved] = (0, import_react26.useState)(true);
6884
+ const [halls, setWings] = (0, import_react26.useState)([]);
6885
+ const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react26.useState)(true);
6886
+ const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react26.useState)(false);
6887
+ const [wingLabels, setHallLabels] = (0, import_react26.useState)({});
6888
+ const [error, setError] = (0, import_react26.useState)(null);
6889
+ const [open, setOpen] = (0, import_react26.useState)(false);
6890
+ const wrapRef = (0, import_react26.useRef)(null);
6891
+ const popRef = (0, import_react26.useRef)(null);
6471
6892
  const shiftX = useViewportClamp(popRef);
6472
- const seqRef = (0, import_react25.useRef)(0);
6473
- const load = (0, import_react25.useCallback)(() => {
6893
+ const seqRef = (0, import_react26.useRef)(0);
6894
+ const load = (0, import_react26.useCallback)(() => {
6474
6895
  if (!sessionId || !rpc) return;
6475
6896
  const token = ++seqRef.current;
6476
6897
  setError(null);
@@ -6495,13 +6916,13 @@ var __defProp = Object.defineProperty;
6495
6916
  }).catch(() => {
6496
6917
  });
6497
6918
  }, [sessionId, rpc]);
6498
- (0, import_react25.useEffect)(() => {
6919
+ (0, import_react26.useEffect)(() => {
6499
6920
  load();
6500
6921
  }, [load]);
6501
- (0, import_react25.useEffect)(() => {
6922
+ (0, import_react26.useEffect)(() => {
6502
6923
  watchSidebarIcon();
6503
6924
  }, []);
6504
- (0, import_react25.useEffect)(() => {
6925
+ (0, import_react26.useEffect)(() => {
6505
6926
  initOccupancyIndicator(
6506
6927
  (endpoint, payload) => rpc(endpoint, payload)
6507
6928
  );
@@ -6509,7 +6930,7 @@ var __defProp = Object.defineProperty;
6509
6930
  watchContextMeter();
6510
6931
  noteOccupancySession(sessionId ?? null);
6511
6932
  }, [sessionId, rpc]);
6512
- (0, import_react25.useEffect)(() => {
6933
+ (0, import_react26.useEffect)(() => {
6513
6934
  if (!open) return;
6514
6935
  const onDown = (e) => {
6515
6936
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -6649,8 +7070,8 @@ var __defProp = Object.defineProperty;
6649
7070
  pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
6650
7071
  pillStyle["--dsh-mem-pill-tint"] = info.color;
6651
7072
  }
6652
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
6653
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
7073
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
7074
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6654
7075
  "button",
6655
7076
  {
6656
7077
  type: "button",
@@ -6663,11 +7084,11 @@ var __defProp = Object.defineProperty;
6663
7084
  style: pillStyle,
6664
7085
  children: [
6665
7086
  "记忆 · ",
6666
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: faceLabel })
7087
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: faceLabel })
6667
7088
  ]
6668
7089
  }
6669
7090
  ),
6670
- open ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7091
+ open ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6671
7092
  "div",
6672
7093
  {
6673
7094
  ref: popRef,
@@ -6678,12 +7099,12 @@ var __defProp = Object.defineProperty;
6678
7099
  transform: "translateX(calc(-50% + " + shiftX + "px))",
6679
7100
  zIndex: 1e3
6680
7101
  },
6681
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7102
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6682
7103
  "div",
6683
7104
  {
6684
7105
  className: "dsh-mem-popover",
6685
7106
  style: { position: "relative", padding: "10px 12px" },
6686
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7107
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6687
7108
  WingWheel,
6688
7109
  {
6689
7110
  mode: mode || "auto",