dsh-prime-memory 0.22.2 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.en.md +401 -0
  2. package/CHANGELOG.ja.md +401 -0
  3. package/CHANGELOG.ko.md +401 -0
  4. package/CHANGELOG.md +100 -0
  5. package/dist/client.js +1180 -845
  6. package/dist/config.d.ts +128 -1341
  7. package/dist/config.js +80 -4
  8. package/dist/conflict-service.d.ts +4 -0
  9. package/dist/conflict-service.js +6 -1
  10. package/dist/contract.d.ts +196 -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 +30 -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 +43 -1
  28. package/dist/pipeline/ruminate.js +100 -0
  29. package/dist/pipeline/runner.d.ts +10 -0
  30. package/dist/pipeline/runner.js +7 -1
  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 +12 -1
  43. package/dist/stats.d.ts +12 -0
  44. package/dist/stats.js +327 -15
  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 +75 -3
  54. package/dist/store/l1.js +124 -3
  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 +23 -0
  58. package/dist/store/memory-md-disable.js +106 -0
  59. package/dist/store/memory-md-export.d.ts +50 -0
  60. package/dist/store/memory-md-export.js +200 -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-skeleton.d.ts +18 -0
  68. package/dist/store/memory-md-skeleton.js +61 -0
  69. package/dist/store/memory-md-types.d.ts +174 -0
  70. package/dist/store/memory-md-types.js +10 -0
  71. package/dist/store/memory-md.d.ts +108 -0
  72. package/dist/store/memory-md.js +219 -0
  73. package/dist/store/obsolete-notices.d.ts +39 -0
  74. package/dist/store/obsolete-notices.js +153 -0
  75. package/dist/store/recall-feedback.d.ts +75 -0
  76. package/dist/store/recall-feedback.js +213 -0
  77. package/dist/store/recall-usage.d.ts +11 -0
  78. package/dist/store/recall-usage.js +29 -0
  79. package/dist/store/session-recalled.d.ts +38 -3
  80. package/dist/store/session-recalled.js +156 -9
  81. package/dist/store/sqlite.d.ts +66 -0
  82. package/dist/store/sqlite.js +233 -15
  83. package/dist/store/supersede.d.ts +1 -1
  84. package/dist/store/supersede.js +1 -1
  85. package/dist/tools/index.d.ts +4 -0
  86. package/dist/tools/index.js +23 -6
  87. package/dist/types.d.ts +24 -7
  88. package/dist/types.js +10 -2
  89. package/dist/util/maturity.d.ts +20 -3
  90. package/dist/util/maturity.js +18 -1
  91. package/dist/util/md-name.d.ts +129 -0
  92. package/dist/util/md-name.js +366 -0
  93. package/dist/util/md-normalize.d.ts +23 -0
  94. package/dist/util/md-normalize.js +131 -0
  95. package/dist/workspace-route.d.ts +22 -0
  96. package/dist/workspace-route.js +66 -0
  97. package/dsh.plugin.json +1 -1
  98. 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,195 @@ 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 tail = rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 条,再点一次继续` : "";
1679
+ return head + named + nameBad + tail;
1680
+ }
1681
+ function lineOfReconcile(rep) {
1682
+ const parts = [
1683
+ `首次 ${rep.firstTime}`,
1684
+ `一致 ${rep.same}`,
1685
+ `仅库变 ${rep.dbOnly}`,
1686
+ `仅文件变 ${rep.fileOnly}`,
1687
+ `两边都变 ${rep.both}`,
1688
+ `文件缺失 ${rep.missingFile}`
1689
+ ];
1690
+ return parts.join(" · ") + (rep.capped ? `(本次只扫了 ${rep.scanned} 条,未扫全)` : "");
1691
+ }
1692
+ function lineOfSync(rep) {
1693
+ const head = `回灌 ${rep.imported} · 重写文件 ${rep.rendered} · 退场 ${rep.retired} · 一致 ${rep.same}`;
1694
+ const tail = rep.pending > 0 ? ` · 两边都变 ${rep.pending} 条已挂账(两侧都没动)` : "";
1695
+ const extra = rep.newFiles > 0 ? ` · 新文件 ${rep.newFiles} 个未入库(导入须走写入内核)` : "";
1696
+ const links = rep.skippedLinks > 0 ? ` · 防护拦下 ${rep.skippedLinks} 个链接/越界条目(未读)` : "";
1697
+ const stale = rep.staleRootFiles > 0 ? ` · 陈旧根 ${rep.staleRootFiles} 个文件未参与同步(交给孤儿归档)` : "";
1698
+ const multi = rep.multiPath > 0 ? ` · 同记录多路径 ${rep.multiPath} 份未动(先跑孤儿归档再同步)` : "";
1699
+ const hashBad = rep.hashMismatch > 0 ? ` · 自校验不符 ${rep.hashMismatch} 个(文件被外部改动,已按文件侧处理)` : "";
1700
+ const unsigned = rep.unsigned > 0 ? ` · 未签名 ${rep.unsigned} 个(老投射文件无 hash,下轮导出补盖)` : "";
1701
+ return head + tail + extra + links + stale + multi + hashBad + unsigned + (rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 个文件,再点一次继续` : "");
1702
+ }
1703
+ function lineOfOrphans(rep) {
1704
+ const head = rep.dryRun ? `账本共 ${rep.scanned} 条 · 仍被认领 ${rep.claimed} · 无人认领 ${rep.orphans}(未搬任何东西)` : `已搬 ${rep.moved} · 失败 ${rep.failed} · 仍被认领 ${rep.claimed}`;
1705
+ const tail = rep.remaining > 0 ? ` · 剩余 ${rep.remaining} 条,再点一次继续` : "";
1706
+ return head + tail + (rep.dir.length > 0 ? ` · 归档到 ${rep.dir}` : "");
1707
+ }
1708
+ function lineOfCleanup(rep) {
1709
+ if (rep.aborted) return `清理已中止(未删任何记录):${rep.diffs.join(";") || "门禁未通过"}`;
1710
+ if (rep.dryRun) return `待删 ${rep.targets} 条(预览了前 ${rep.items?.length ?? 0} 条)——未删除任何东西`;
1711
+ const f = rep.files ?? { moved: 0, failed: 0, absent: 0 };
1712
+ const head = `已删 ${rep.purged} 条 · 归档正文 ${rep.archiveMd === void 0 || rep.archiveMd === "" ? "未写" : "已写"} · 文件搬家 ${f.moved}(失败 ${f.failed}) · 图索引 ${rep.graphForgotten ?? 0}`;
1713
+ return rep.otherChanged && rep.otherChanged > 0 ? `${head} · 本批之外 ${rep.otherChanged} 条处于漂移(不影响本批)` : head;
1714
+ }
1715
+ function ArchiveSection(props) {
1716
+ const rpc = props.rpc;
1717
+ const [busy, setBusy] = (0, import_react7.useState)(false);
1718
+ const [exported, setExported] = (0, import_react7.useState)(void 0);
1719
+ const [recon, setRecon] = (0, import_react7.useState)(void 0);
1720
+ const [synced, setSynced] = (0, import_react7.useState)(void 0);
1721
+ const [orphans, setOrphans] = (0, import_react7.useState)(void 0);
1722
+ const [cleanup, setCleanup] = (0, import_react7.useState)(void 0);
1723
+ const [orphanArmed, setOrphanArmed] = (0, import_react7.useState)(false);
1724
+ const [armed, setArmed] = (0, import_react7.useState)(false);
1725
+ const [error, setError] = (0, import_react7.useState)(void 0);
1726
+ const run = (method, sink, payload) => {
1727
+ if (busy) return;
1728
+ setBusy(true);
1729
+ setError(void 0);
1730
+ void call(rpc, method, payload).then((out) => {
1731
+ if (out.report !== void 0) sink(out.report);
1732
+ if (out.error !== void 0) setError(out.error);
1733
+ setBusy(false);
1734
+ });
1735
+ };
1736
+ const root = exported?.root ?? recon?.root;
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 12, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, color: "var(--dsh-mem-text-2)", marginBottom: 6 }, children: "外部存档(markdown 投射)" }),
1739
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: S.flexRow, children: [
1740
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1741
+ NButton,
1742
+ {
1743
+ disabled: busy,
1744
+ title: "把当前全部记忆渲染为 <根>/<类型>/<名称>.memory.md,并记下内容指纹(只写文件,不改库)",
1745
+ onClick: () => {
1746
+ run("dsh-memory/mem-export", setExported, {});
1747
+ },
1748
+ children: "导出为可携存档"
1749
+ }
1750
+ ),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1752
+ NButton,
1753
+ {
1754
+ disabled: busy,
1755
+ title: "按账本基线比对库与磁盘,只出报告:什么都不写,因此不需要高权限",
1756
+ onClick: () => {
1757
+ run("dsh-memory/mem-reconcile", setRecon, {});
1758
+ },
1759
+ children: "与存档对账"
1760
+ }
1761
+ ),
1762
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1763
+ NButton,
1764
+ {
1765
+ disabled: busy,
1766
+ title: "文件 → 库:只有文件变过的回灌入库,`.disable` 后缀的退场;两边都变的那些两侧都不动,只挂账。会写库,因此需要高权限模式",
1767
+ onClick: () => {
1768
+ run("dsh-memory/mem-sync", setSynced, {});
1769
+ },
1770
+ children: "从存档同步回库"
1771
+ }
1772
+ ),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1774
+ NButton,
1775
+ {
1776
+ disabled: busy,
1777
+ title: "只读预览:扫账本,找出“我们写过但现在没记录认领它”的投射文件(改名/消歧留下的残片)。来路不明的文件一律不动,也不搬任何东西",
1778
+ onClick: () => {
1779
+ setOrphanArmed(false);
1780
+ run("dsh-memory/mem-orphans", setOrphans, { dryRun: true });
1781
+ },
1782
+ children: "孤儿文件预览"
1783
+ }
1784
+ ),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1786
+ NButton,
1787
+ {
1788
+ disabled: busy || orphans === void 0 || !orphans.dryRun || orphans.orphans === 0,
1789
+ title: orphanArmed ? "再点一次就真的搬——文件会被移出投射目录(不删,进归档目录,可手动搬回)" : "不删只搬:进 <数据目录>/memories-orphans/<批次时间戳>/;需要先跑预览,再点两次确认;服务端还要高权限模式",
1790
+ onClick: () => {
1791
+ if (!orphanArmed) {
1792
+ setOrphanArmed(true);
1793
+ return;
1794
+ }
1795
+ setOrphanArmed(false);
1796
+ run("dsh-memory/mem-orphans", setOrphans, { dryRun: false });
1797
+ },
1798
+ children: orphanArmed ? "确认搬走孤儿文件" : "孤儿文件归档"
1799
+ }
1800
+ ),
1801
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1802
+ NButton,
1803
+ {
1804
+ disabled: busy,
1805
+ title: "只读预览:列出将被物理删除的退场记忆(前 50 条)与总数,不删任何东西",
1806
+ onClick: () => {
1807
+ setArmed(false);
1808
+ run("dsh-memory/cleanup-retired", setCleanup, { dryRun: true });
1809
+ },
1810
+ children: "清理预览(干跑)"
1811
+ }
1812
+ ),
1813
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1814
+ NButton,
1815
+ {
1816
+ disabled: busy || cleanup === void 0 || !cleanup.dryRun || cleanup.targets === 0,
1817
+ title: armed ? "再点一次就真的删——物理删除不可逆(但会先落快照与归档正文)" : "不可逆动作:需要先跑预览,再点两次确认;服务端那边还要高权限模式",
1818
+ onClick: () => {
1819
+ if (!armed) {
1820
+ setArmed(true);
1821
+ return;
1822
+ }
1823
+ setArmed(false);
1824
+ run("dsh-memory/cleanup-retired", setCleanup, { dryRun: false });
1825
+ },
1826
+ children: armed ? "确认物理删除" : "清理并归档"
1827
+ }
1828
+ )
1829
+ ] }),
1830
+ /* @__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) : "导出=库→文件;对账=只读比较;同步=文件→库;孤儿=搬走没人认领的残片;清理=物理删除(不可逆,需高权限模式)。" }),
1831
+ recon !== void 0 && error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: HINT_STYLE, children: [
1832
+ "最近差异样本:",
1833
+ recon.samples.map((s) => `${s.state}:${s.relPath}`).join(",") || "(无)"
1834
+ ] }) : null,
1835
+ root !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: ROOT_STYLE, children: [
1836
+ "投射根:",
1837
+ root
1838
+ ] }) : null
1839
+ ] });
1840
+ }
1841
+
1536
1842
  // client/src/tabs/DistillSettings.tsx
1537
- var import_react11 = require("react");
1843
+ var import_react12 = require("react");
1538
1844
 
1539
1845
  // client/src/tabs/BudgetInputs.tsx
1540
- var import_react7 = require("react");
1541
- var import_jsx_runtime7 = require("react/jsx-runtime");
1846
+ var import_react8 = require("react");
1847
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1542
1848
  var LAYERS = [
1543
1849
  ["extract", "抽取"],
1544
1850
  ["dedup", "去重"],
@@ -1559,7 +1865,7 @@ var __defProp = Object.defineProperty;
1559
1865
  const onError = props.onError;
1560
1866
  const scope = props.scope ?? "all";
1561
1867
  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);
1868
+ const [draft, setDraft] = (0, import_react8.useState)(null);
1563
1869
  if (!data || !data.budgets) return null;
1564
1870
  const cur = data.budgets.current || {};
1565
1871
  const def = data.budgets.defaults || {};
@@ -1655,7 +1961,7 @@ var __defProp = Object.defineProperty;
1655
1961
  return false;
1656
1962
  };
1657
1963
  const inputBox = (key, _label, title, width, placeholder, onCommit) => {
1658
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1659
1965
  NInput,
1660
1966
  {
1661
1967
  type: "number",
@@ -1687,9 +1993,9 @@ var __defProp = Object.defineProperty;
1687
1993
  const effNote = layers.map((l) => eff[l[0]] || "?").join(" / ");
1688
1994
  const rowLabel = (key) => key === "extract" ? "抽取输出" : key === "dedup" ? "去重输出" : key === "l2" ? "L2 输出" : "L3 输出";
1689
1995
  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)(
1996
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1997
+ showOutputs ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 12 }, children: [
1998
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1693
1999
  "div",
1694
2000
  {
1695
2001
  style: S.switchLabel,
@@ -1697,8 +2003,8 @@ var __defProp = Object.defineProperty;
1697
2003
  children: "输出预算"
1698
2004
  }
1699
2005
  ),
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]) }),
2006
+ /* @__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: [
2007
+ /* @__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
2008
  inputBox(
1703
2009
  l[0],
1704
2010
  l[1],
@@ -1707,11 +2013,11 @@ var __defProp = Object.defineProperty;
1707
2013
  def[l[0]],
1708
2014
  commitOutputs
1709
2015
  ),
1710
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
2016
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
1711
2017
  ] }, l[0])) })
1712
2018
  ] }) : null,
1713
- showInput ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 12 }, children: [
1714
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2019
+ showInput ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 12 }, children: [
2020
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1715
2021
  "div",
1716
2022
  {
1717
2023
  style: S.switchLabel,
@@ -1719,8 +2025,8 @@ var __defProp = Object.defineProperty;
1719
2025
  children: "输入预算"
1720
2026
  }
1721
2027
  ),
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: "单次输入" }),
2028
+ /* @__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: [
2029
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: "单次输入" }),
1724
2030
  inputBox(
1725
2031
  "input",
1726
2032
  "输入",
@@ -1729,15 +2035,15 @@ var __defProp = Object.defineProperty;
1729
2035
  ib.fallback,
1730
2036
  commitInput
1731
2037
  ),
1732
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
2038
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
1733
2039
  ] }) })
1734
2040
  ] }) : null
1735
2041
  ] });
1736
2042
  }
1737
2043
 
1738
2044
  // client/src/tabs/ChannelEditor.tsx
1739
- var import_react8 = require("react");
1740
- var import_jsx_runtime8 = require("react/jsx-runtime");
2045
+ var import_react9 = require("react");
2046
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1741
2047
  var STY = {
1742
2048
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
1743
2049
  head: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 6 },
@@ -1768,14 +2074,14 @@ var __defProp = Object.defineProperty;
1768
2074
  ];
1769
2075
  function ChannelEditor(props) {
1770
2076
  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)(() => {
2077
+ const [baseText, setBaseText] = (0, import_react9.useState)(channel.runtimeBaseURL);
2078
+ const [keyText, setKeyText] = (0, import_react9.useState)("");
2079
+ const baseTimer = (0, import_react9.useRef)(void 0);
2080
+ const dirty = (0, import_react9.useRef)(false);
2081
+ (0, import_react9.useEffect)(() => {
1776
2082
  if (!dirty.current) setBaseText(channel.runtimeBaseURL);
1777
2083
  }, [channel.runtimeBaseURL]);
1778
- (0, import_react8.useEffect)(() => () => clearTimeout(baseTimer.current), []);
2084
+ (0, import_react9.useEffect)(() => () => clearTimeout(baseTimer.current), []);
1779
2085
  const commit2 = (patch) => {
1780
2086
  rpc("dsh-memory/settings-set", patch).catch(() => {
1781
2087
  });
@@ -1804,17 +2110,17 @@ var __defProp = Object.defineProperty;
1804
2110
  const deployedDirect = channel.deployed === "direct";
1805
2111
  const apiKeySet = channel.runtimeApiKeySet || channel.deployedApiKeySet;
1806
2112
  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: [
2113
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.block, children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.head, children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.title, children: "蒸馏通道" }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: isDirect ? STY.chipAccent : STY.chipMuted, children: isDirect ? "直连端点" : "复用宿主" }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { title: "direct = 插件原生直连 OpenAI 兼容端点,与付费 API 解耦;失败自动回退宿主路由链。", style: { marginLeft: "auto", fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1812
2118
  "生效:",
1813
2119
  runtime ? runtime === "direct" ? "运行时直连" : "运行时宿主" : "跟随部署配置"
1814
2120
  ] })
1815
2121
  ] }),
1816
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
1817
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2122
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
2123
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1818
2124
  Segmented,
1819
2125
  {
1820
2126
  value: runtime,
@@ -1823,10 +2129,10 @@ var __defProp = Object.defineProperty;
1823
2129
  onChange: (k) => commit2({ distillMode: k })
1824
2130
  }
1825
2131
  ),
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)(
2132
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2133
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.fieldRow, children: [
2134
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.fieldLabel, children: "端点 URL" }),
2135
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1830
2136
  NInput,
1831
2137
  {
1832
2138
  style: STY.input,
@@ -1843,14 +2149,14 @@ var __defProp = Object.defineProperty;
1843
2149
  }
1844
2150
  }
1845
2151
  ),
1846
- deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
2152
+ deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1847
2153
  "部署基线:",
1848
2154
  channel.deployedBaseURL || "(空)"
1849
2155
  ] }) : null
1850
2156
  ] }),
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)(
2157
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY.fieldRow, children: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.fieldLabel, children: "API Key" }),
2159
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1854
2160
  NInput,
1855
2161
  {
1856
2162
  style: STY.input,
@@ -1866,8 +2172,8 @@ var __defProp = Object.defineProperty;
1866
2172
  onBlur: commitKey
1867
2173
  }
1868
2174
  ),
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)(
2175
+ apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.chipAccent, children: "已配置" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY.chipMuted, children: "未配置" }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1871
2177
  NButton,
1872
2178
  {
1873
2179
  disabled,
@@ -1877,30 +2183,30 @@ var __defProp = Object.defineProperty;
1877
2183
  }
1878
2184
  )
1879
2185
  ] }),
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" ? "运行时锁定" : "跟随部署配置") + ")" })
2186
+ showWarn ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.warn, children: "⚠ direct 未配置完整:需同时有端点 URL 与模型(llm.model / 全局链主路由),否则会回退宿主路由。" }) : null
2187
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: STY.preview, children: isDirect ? "当前将直连端点:" + (channel.runtimeBaseURL || channel.deployedBaseURL || "(未配置端点)") + (apiKeySet ? " · 密钥已配置" : " · 未配置密钥") : "当前复用宿主 ctx.llm(" + (runtime === "host" ? "运行时锁定" : "跟随部署配置") + ")" })
1882
2188
  ] });
1883
2189
  }
1884
2190
 
1885
2191
  // client/src/tabs/RouteChainEditor.tsx
1886
- var import_react10 = require("react");
2192
+ var import_react11 = require("react");
1887
2193
 
1888
2194
  // client/src/ui/NSel.tsx
1889
- var import_react9 = require("react");
1890
- var import_jsx_runtime9 = require("react/jsx-runtime");
2195
+ var import_react10 = require("react");
2196
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1891
2197
  function NSel(props) {
1892
2198
  const options = props.options || [];
1893
2199
  const value = props.value || "";
1894
2200
  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);
2201
+ const [open, setOpen] = (0, import_react10.useState)(false);
2202
+ const [idx, setIdx] = (0, import_react10.useState)(-1);
2203
+ const wrapRef = (0, import_react10.useRef)(null);
2204
+ const listRef = (0, import_react10.useRef)(null);
1899
2205
  let selectedLabel = "";
1900
2206
  for (let si = 0; si < options.length; si++) {
1901
2207
  if (options[si].id === value) selectedLabel = options[si].label;
1902
2208
  }
1903
- (0, import_react9.useEffect)(() => {
2209
+ (0, import_react10.useEffect)(() => {
1904
2210
  if (!open) return void 0;
1905
2211
  const onDown = (e) => {
1906
2212
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -1910,7 +2216,7 @@ var __defProp = Object.defineProperty;
1910
2216
  document.removeEventListener("mousedown", onDown);
1911
2217
  };
1912
2218
  }, [open]);
1913
- (0, import_react9.useEffect)(() => {
2219
+ (0, import_react10.useEffect)(() => {
1914
2220
  if (!open || !listRef.current) return;
1915
2221
  const el = listRef.current.querySelector('[data-active="1"]');
1916
2222
  if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
@@ -1973,8 +2279,8 @@ var __defProp = Object.defineProperty;
1973
2279
  const to = e.relatedTarget;
1974
2280
  if (!to || wrapRef.current && !wrapRef.current.contains(to)) setOpen(false);
1975
2281
  };
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)(
2282
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-sel", style: props.style, ref: wrapRef, onKeyDown: onKey, onBlur, children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1978
2284
  "button",
1979
2285
  {
1980
2286
  type: "button",
@@ -1990,13 +2296,13 @@ var __defProp = Object.defineProperty;
1990
2296
  }
1991
2297
  },
1992
2298
  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 })
2299
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-select-label", children: selectedLabel || props.placeholder || "(请选择)" }),
2300
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : ""), "aria-hidden": true })
1995
2301
  ]
1996
2302
  }
1997
2303
  ),
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)(
2304
+ 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) => {
2305
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2000
2306
  "button",
2001
2307
  {
2002
2308
  type: "button",
@@ -2014,8 +2320,8 @@ var __defProp = Object.defineProperty;
2014
2320
  if (idx !== i) setIdx(i);
2015
2321
  },
2016
2322
  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
2323
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-pop-opt-label", children: o.label }),
2324
+ o.id === value ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-pop-check", children: "✓" }) : null
2019
2325
  ]
2020
2326
  },
2021
2327
  o.id
@@ -2025,7 +2331,7 @@ var __defProp = Object.defineProperty;
2025
2331
  }
2026
2332
 
2027
2333
  // client/src/tabs/RouteChainEditor.tsx
2028
- var import_jsx_runtime10 = require("react/jsx-runtime");
2334
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2029
2335
  var modelsCache = {};
2030
2336
  var EFFORT_VOCAB = ["", "off", "none", "minimal", "low", "medium", "high", "xhigh", "max"];
2031
2337
  var STY2 = {
@@ -2054,26 +2360,26 @@ var __defProp = Object.defineProperty;
2054
2360
  const disabled = !!props.disabled;
2055
2361
  const scope = props.scope ?? "global";
2056
2362
  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);
2363
+ const [info, setInfo] = (0, import_react11.useState)(null);
2364
+ const [rows, setRows] = (0, import_react11.useState)(null);
2365
+ const [rowErrs, setRowErrs] = (0, import_react11.useState)({});
2366
+ const [err, setErr] = (0, import_react11.useState)(null);
2367
+ const [manual, setManual] = (0, import_react11.useState)({ idx: -1, text: "" });
2368
+ const pendingWrites = (0, import_react11.useRef)(0);
2063
2369
  function refreshInfo() {
2064
2370
  rpc("dsh-memory/llm-providers", {}).then((r) => {
2065
2371
  if (r && r.ok && pendingWrites.current === 0) setInfo(r.value);
2066
2372
  }).catch(() => {
2067
2373
  });
2068
2374
  }
2069
- (0, import_react10.useEffect)(() => {
2375
+ (0, import_react11.useEffect)(() => {
2070
2376
  refreshInfo();
2071
2377
  const timer = setInterval(refreshInfo, 5e3);
2072
2378
  return () => {
2073
2379
  clearInterval(timer);
2074
2380
  };
2075
2381
  }, [rpc]);
2076
- (0, import_react10.useEffect)(() => {
2382
+ (0, import_react11.useEffect)(() => {
2077
2383
  if (!info || !info.providers) return;
2078
2384
  info.providers.forEach((p) => {
2079
2385
  if (!p.id || modelsCache[p.id]) return;
@@ -2085,7 +2391,7 @@ var __defProp = Object.defineProperty;
2085
2391
  }, [rpc, info]);
2086
2392
  const layerView = isLayer && info && info.layerChains ? info.layerChains[scope] : null;
2087
2393
  const savedRows = isLayer ? layerView?.runtime ?? [] : info && info.chain ? info.chain.current : [];
2088
- (0, import_react10.useEffect)(() => {
2394
+ (0, import_react11.useEffect)(() => {
2089
2395
  if (rows === null && info && savedRows.length) {
2090
2396
  setRows(savedRows.map(copyRow));
2091
2397
  }
@@ -2233,17 +2539,17 @@ var __defProp = Object.defineProperty;
2233
2539
  providersById[p.id] = p;
2234
2540
  });
2235
2541
  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 : "跟随部署配置" })
2542
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.roRow, children: [
2543
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY2.badge, children: i === 0 ? "主" : String(i + 1) }),
2544
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { ...STY2.mono, color: "var(--dsh-mem-text-2)" }, children: e.provider + " / " + e.model }),
2545
+ /* @__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
2546
  ] }, "ro" + i);
2241
2547
  }
2242
2548
  if (info.pinned) {
2243
2549
  const effPin = isLayer ? layerView?.effectiveChain ?? [] : info.chain && info.chain.effectiveChain || [];
2244
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2550
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2245
2551
  effPin.map(roRow),
2246
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
2552
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
2247
2553
  ] });
2248
2554
  }
2249
2555
  if (rows === null) {
@@ -2251,21 +2557,21 @@ var __defProp = Object.defineProperty;
2251
2557
  const lv = layerView;
2252
2558
  const src = lv?.source ?? "global";
2253
2559
  if (src === "static" && lv) {
2254
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.wrap, children: [
2560
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2255
2561
  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: "自定义本层链" }) })
2562
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2257
2563
  ] });
2258
2564
  }
2259
2565
  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: "自定义本层链" }) })
2566
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2567
+ previewRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.switchDesc, children: "本层跟随全局链,暂无可用路由。" }) : previewRows.map(roRow),
2568
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
2263
2569
  ] });
2264
2570
  }
2265
2571
  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: "编辑为运行时链" }) })
2572
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2573
+ effFollow.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.switchDesc, children: "蒸馏跟随默认模型,未配置回退链。" }) : effFollow.map(roRow),
2574
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { onClick: forkStatic, disabled, children: "编辑为运行时链" }) })
2269
2575
  ] });
2270
2576
  }
2271
2577
  const capped = rows.length >= 8;
@@ -2306,10 +2612,10 @@ var __defProp = Object.defineProperty;
2306
2612
  const effortOptions = [{ id: "", label: "跟随部署配置" }].concat(
2307
2613
  curEfforts.filter((k) => EFFORT_VOCAB.indexOf(k) >= 0).map((k) => ({ id: k, label: k }))
2308
2614
  );
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)(
2615
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...STY2.row, ...rowErrs[i] ? STY2.rowErr : null }, children: [
2616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.line, children: [
2617
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: STY2.badge, children: isPrimary ? "主" : String(i + 1) }),
2618
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2313
2619
  NSel,
2314
2620
  {
2315
2621
  style: { flex: 1, minWidth: 150 },
@@ -2322,7 +2628,7 @@ var __defProp = Object.defineProperty;
2322
2628
  }
2323
2629
  }
2324
2630
  ),
2325
- !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2631
+ !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2326
2632
  NInput,
2327
2633
  {
2328
2634
  style: { flex: 1, minWidth: 150 },
@@ -2341,7 +2647,7 @@ var __defProp = Object.defineProperty;
2341
2647
  }
2342
2648
  }
2343
2649
  }
2344
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2650
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2345
2651
  NSel,
2346
2652
  {
2347
2653
  style: { flex: 1, minWidth: 150 },
@@ -2354,7 +2660,7 @@ var __defProp = Object.defineProperty;
2354
2660
  }
2355
2661
  }
2356
2662
  ),
2357
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2663
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2358
2664
  NSel,
2359
2665
  {
2360
2666
  style: { flexShrink: 0, width: 118 },
@@ -2368,8 +2674,8 @@ var __defProp = Object.defineProperty;
2368
2674
  }
2369
2675
  )
2370
2676
  ] }),
2371
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: STY2.actions, children: [
2372
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2677
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.actions, children: [
2678
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2373
2679
  NButton,
2374
2680
  {
2375
2681
  style: STY2.ico,
@@ -2381,7 +2687,7 @@ var __defProp = Object.defineProperty;
2381
2687
  children: "↑"
2382
2688
  }
2383
2689
  ),
2384
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2385
2691
  NButton,
2386
2692
  {
2387
2693
  style: STY2.ico,
@@ -2393,7 +2699,7 @@ var __defProp = Object.defineProperty;
2393
2699
  children: "↓"
2394
2700
  }
2395
2701
  ),
2396
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2702
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2397
2703
  NButton,
2398
2704
  {
2399
2705
  style: STY2.ico,
@@ -2406,14 +2712,14 @@ var __defProp = Object.defineProperty;
2406
2712
  }
2407
2713
  )
2408
2714
  ] }),
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
2715
+ isPrimary && !row2.provider ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.note, children: "跟随默认模型" + (info.default ? ":" + info.default.provider + " / " + info.default.model : "") + "(档位跟随部署配置,选定模型后可单独设置)" }) : null,
2716
+ !known ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.warn, children: "⚠ 供应商 " + row2.provider + " 已不在已注册路由中:该路由调用会失败并被链跳过(不阻止保存)。" }) : null,
2717
+ rowErrs[i] ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: STY2.warn, children: "✕ " + rowErrs[i] }) : null
2412
2718
  ] }, "row" + i);
2413
2719
  });
2414
2720
  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)(
2721
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: STY2.wrap, children: [
2722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2417
2723
  "div",
2418
2724
  {
2419
2725
  style: { ...S.switchDesc, marginBottom: 8 },
@@ -2422,9 +2728,9 @@ var __defProp = Object.defineProperty;
2422
2728
  }
2423
2729
  ),
2424
2730
  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)(
2731
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { style: STY2.add, disabled: disabled || capped, onClick: addRow, children: capped ? "已达上限(8 条)" : "+ 添加回退路由" }),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
2733
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2428
2734
  NButton,
2429
2735
  {
2430
2736
  style: isLayer ? { ...STY2.ghost, color: "var(--dsh-mem-danger)", border: "1px solid var(--dsh-mem-danger)" } : STY2.ghost,
@@ -2433,13 +2739,13 @@ var __defProp = Object.defineProperty;
2433
2739
  children: isLayer ? "清除自定义 · 跟随全局" : "清空并跟随部署配置"
2434
2740
  }
2435
2741
  ),
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: "保存" })
2742
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: S.grow }),
2743
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { variant: "primary", disabled, onClick: save, children: "保存" })
2438
2744
  ] }),
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)(
2745
+ err ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { ...STY2.warn, marginTop: 8 }, children: "✕ " + err }) : null,
2746
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
2747
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 4 }, children: "实际链" + (dirty ? "(保存后更新;当前显示已保存值)" : "") }),
2748
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2443
2749
  "div",
2444
2750
  {
2445
2751
  style: { fontSize: 12, color: "var(--dsh-mem-text-2)", wordBreak: "break-all", fontFamily: "ui-monospace, SFMono-Regular, Consolas, monospace" },
@@ -2451,7 +2757,7 @@ var __defProp = Object.defineProperty;
2451
2757
  }
2452
2758
 
2453
2759
  // client/src/tabs/DistillSettings.tsx
2454
- var import_jsx_runtime11 = require("react/jsx-runtime");
2760
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2455
2761
  var STY3 = {
2456
2762
  hint: { fontSize: 11, color: "var(--dsh-mem-text-3)", margin: "0 0 8px" },
2457
2763
  panelHead: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 8 },
@@ -2480,9 +2786,9 @@ var __defProp = Object.defineProperty;
2480
2786
  verticalAlign: "middle",
2481
2787
  flexShrink: 0
2482
2788
  };
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)" } });
2789
+ if (props.kind === "runtime") return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...base, background: "var(--dsh-mem-accent)" } });
2790
+ 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)" } });
2791
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...base, background: "var(--dsh-mem-track)" } });
2486
2792
  }
2487
2793
  var LAYER_META = {
2488
2794
  l1: { seg: "L1", title: "L1 · 抽取 / 去重" },
@@ -2492,9 +2798,9 @@ var __defProp = Object.defineProperty;
2492
2798
  function DistillSettings(props) {
2493
2799
  const rpc = props.rpc;
2494
2800
  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)(() => {
2801
+ const [info, setInfo] = (0, import_react12.useState)(null);
2802
+ const [tab, setTab] = (0, import_react12.useState)("g");
2803
+ (0, import_react12.useEffect)(() => {
2498
2804
  let alive = true;
2499
2805
  const refresh = () => {
2500
2806
  rpc("dsh-memory/llm-providers", {}).then((r) => {
@@ -2517,46 +2823,46 @@ var __defProp = Object.defineProperty;
2517
2823
  ...["l1", "l2", "l3"].map((k) => ({
2518
2824
  key: k,
2519
2825
  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) }),
2826
+ label: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { children: [
2827
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: dotOf(k) }),
2522
2828
  LAYER_META[k].seg
2523
2829
  ] })
2524
2830
  }))
2525
2831
  ];
2526
2832
  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" }),
2833
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2834
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Segmented, { value: tab, options: segOptions, onChange: (k) => setTab(k) }),
2835
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.hint, children: [
2836
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "runtime" }),
2531
2837
  " 自定义 · ",
2532
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: "static" }),
2838
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "static" }),
2533
2839
  " 部署 YAML · ",
2534
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Dot, { kind: "global" }),
2840
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Dot, { kind: "global" }),
2535
2841
  " 跟随全局",
2536
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2842
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2537
2843
  ] }),
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("、") : "当前无层使用" })
2844
+ tab === "g" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2845
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.panelHead, children: [
2846
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: STY3.panelTitle, children: "全局默认链" }),
2847
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...STY3.chip, ...STY3.chipAccent }, children: "运行时 · 可编辑" }),
2848
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { ...STY3.inUse, marginLeft: "auto" }, children: users.length ? "在用:" + users.map((k) => LAYER_META[k].seg).join("、") : "当前无层使用" })
2543
2849
  ] }),
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" : "跟随全局" })
2850
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RouteChainEditor, { rpc, disabled }, "g"),
2851
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: "input" }, "g-budget"),
2852
+ info?.channel ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChannelEditor, { channel: info.channel, rpc, disabled }) : null
2853
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2854
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: STY3.panelHead, children: [
2855
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: STY3.panelTitle, children: LAYER_META[tab].title }),
2856
+ /* @__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
2857
  ] }),
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")
2858
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RouteChainEditor, { rpc, disabled, scope: tab }, tab),
2859
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: tab }, tab + "-budget")
2554
2860
  ] })
2555
2861
  ] });
2556
2862
  }
2557
2863
 
2558
2864
  // client/src/tabs/EmbeddingSection.tsx
2559
- var import_react12 = require("react");
2865
+ var import_react13 = require("react");
2560
2866
 
2561
2867
  // client/src/dimensions.ts
2562
2868
  var DIMS_MIN = 1;
@@ -2604,7 +2910,7 @@ var __defProp = Object.defineProperty;
2604
2910
  }
2605
2911
 
2606
2912
  // client/src/tabs/EmbeddingSection.tsx
2607
- var import_jsx_runtime12 = require("react/jsx-runtime");
2913
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2608
2914
  var RSTY = {
2609
2915
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
2610
2916
  title: { fontSize: 12, fontWeight: 600, color: "var(--dsh-mem-text-3)", margin: "0 0 2px" },
@@ -2628,17 +2934,17 @@ var __defProp = Object.defineProperty;
2628
2934
  function EmbeddingSection(props) {
2629
2935
  const rpc = props.rpc;
2630
2936
  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)(() => {
2937
+ const [st, setSt] = (0, import_react13.useState)(null);
2938
+ const [err, setErr] = (0, import_react13.useState)(null);
2939
+ const busyPollRef = (0, import_react13.useRef)(null);
2940
+ const [rBase, setRBase] = (0, import_react13.useState)("");
2941
+ const [rModel, setRModel] = (0, import_react13.useState)("");
2942
+ const [rDims, setRDims] = (0, import_react13.useState)("");
2943
+ const [rKey, setRKey] = (0, import_react13.useState)("");
2944
+ const remoteDirty = (0, import_react13.useRef)({ base: false, model: false, dims: false });
2945
+ const baseTimer = (0, import_react13.useRef)(void 0);
2946
+ const modelTimer = (0, import_react13.useRef)(void 0);
2947
+ const load = (0, import_react13.useCallback)(() => {
2642
2948
  rpc("dsh-memory/embedding-state-get", {}).then((r) => {
2643
2949
  if (r && r.ok && r.value && r.value.supported !== false) {
2644
2950
  const v = r.value;
@@ -2657,10 +2963,10 @@ var __defProp = Object.defineProperty;
2657
2963
  setErr(String(e && e.message || e));
2658
2964
  });
2659
2965
  }, [rpc]);
2660
- (0, import_react12.useEffect)(() => {
2966
+ (0, import_react13.useEffect)(() => {
2661
2967
  load();
2662
2968
  }, [load]);
2663
- (0, import_react12.useEffect)(() => {
2969
+ (0, import_react13.useEffect)(() => {
2664
2970
  let stopped = false;
2665
2971
  const busyFlag = { v: false };
2666
2972
  busyPollRef.current = busyFlag;
@@ -2676,11 +2982,11 @@ var __defProp = Object.defineProperty;
2676
2982
  busyPollRef.current = null;
2677
2983
  };
2678
2984
  }, [load]);
2679
- (0, import_react12.useEffect)(() => () => {
2985
+ (0, import_react13.useEffect)(() => () => {
2680
2986
  clearTimeout(baseTimer.current);
2681
2987
  clearTimeout(modelTimer.current);
2682
2988
  }, []);
2683
- (0, import_react12.useEffect)(() => {
2989
+ (0, import_react13.useEffect)(() => {
2684
2990
  if (!st || !st.remote) return;
2685
2991
  if (!remoteDirty.current.base) setRBase(st.remote.baseURL || "");
2686
2992
  if (!remoteDirty.current.model) setRModel(st.remote.model || "");
@@ -2728,7 +3034,7 @@ var __defProp = Object.defineProperty;
2728
3034
  if (v) commitRemote({ embedRemoteApiKey: v });
2729
3035
  setRKey("");
2730
3036
  };
2731
- const call = (endpoint, payload, confirmText) => {
3037
+ const call2 = (endpoint, payload, confirmText) => {
2732
3038
  if (confirmText && !window.confirm(confirmText)) return;
2733
3039
  loose(endpoint, payload).then((r) => {
2734
3040
  if (!r || !r.ok) setErr(r && r.error ? r.error.message : "操作失败");
@@ -2741,15 +3047,15 @@ var __defProp = Object.defineProperty;
2741
3047
  });
2742
3048
  };
2743
3049
  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: "存储处于降级状态,嵌入管理不可用。" })
3050
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3051
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "语义检索(嵌入)" }),
3052
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: "存储处于降级状态,嵌入管理不可用。" })
2747
3053
  ] });
2748
3054
  }
2749
3055
  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
3056
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3057
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: err ? "嵌入状态读取失败:" + err : "嵌入状态读取中…" }),
3058
+ err ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { style: { marginTop: 8 }, onClick: load, children: "重试" }) : null
2753
3059
  ] });
2754
3060
  }
2755
3061
  const switchConfirm = "切换嵌入源后将按新模型重建向量索引(期间语义检索暂退化为关键词匹配,不影响对话)。确定切换?";
@@ -2762,10 +3068,10 @@ var __defProp = Object.defineProperty;
2762
3068
  return;
2763
3069
  }
2764
3070
  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);
3071
+ call2("dsh-memory/embedding-source-set", { source: "local", activeModel: current }, switchConfirm);
2766
3072
  return;
2767
3073
  }
2768
- call("dsh-memory/embedding-source-set", { source: key }, key === "remote" ? switchConfirm : null);
3074
+ call2("dsh-memory/embedding-source-set", { source: key }, key === "remote" ? switchConfirm : null);
2769
3075
  };
2770
3076
  const dl = st.download;
2771
3077
  const dlActive = dl && (dl.phase === "downloading" || dl.phase === "verifying");
@@ -2775,40 +3081,40 @@ var __defProp = Object.defineProperty;
2775
3081
  const remote = st.remote;
2776
3082
  let runtimeRow = null;
2777
3083
  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: "取消" })
3084
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginTop: 8, fontSize: 12 }, children: [
3085
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3086
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "安装推理运行时中… 已耗时 " + Math.round(rt.elapsedMs / 1e3) + "s(约 100~200MB,视网络)" }),
3087
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3088
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-runtime-cancel", {}), children: "取消" })
2783
3089
  ] }),
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 输出…" })
3090
+ /* @__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
3091
  ] });
2786
3092
  } 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 || "未知") + "(重新切换嵌入源可重试)" });
3093
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "运行时安装失败:" + (rt.error || "未知") + "(重新切换嵌入源可重试)" });
2788
3094
  } 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 + ")" });
3095
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "推理运行时就绪(transformers.js v" + rt.installedVersion + ")" });
2790
3096
  } 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)。" });
3097
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "首次启用本地嵌入时会自动安装推理运行时(约 100~200MB)。" });
2792
3098
  }
2793
3099
  let applyRow = null;
2794
3100
  if (ap.phase === "warming") {
2795
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
3101
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
2796
3102
  } else if (ap.phase === "switching") {
2797
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
3103
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
2798
3104
  } 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 + "(已保存的嵌入源不变,重启后仍按原源运行)" });
3105
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "切换失败:" + ap.message + "(已保存的嵌入源不变,重启后仍按原源运行)" });
2800
3106
  } else if (st.reindex && st.reindex.running) {
2801
3107
  const rj = st.reindex;
2802
3108
  const rDone = rj.l1Done + rj.l0Done;
2803
3109
  const rTotal = rj.l1Total + rj.l0Total;
2804
3110
  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: "取消" })
3111
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginTop: 8 }, children: [
3112
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3113
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "重嵌入中 L1 " + rj.l1Done + "/" + rj.l1Total + " · L0 " + rj.l0Done + "/" + rj.l0Total + "(" + rPct + "%)" }),
3114
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3115
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-reindex-cancel", {}), children: "取消" })
2810
3116
  ] }),
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 + "%" } }) }) })
3117
+ /* @__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
3118
  ] });
2813
3119
  }
2814
3120
  const modelCards = st.models.map((m) => {
@@ -2817,61 +3123,61 @@ var __defProp = Object.defineProperty;
2817
3123
  const pct = mDl && dl.overallTotal > 0 ? Math.round(dl.overallReceived / dl.overallTotal * 100) : 0;
2818
3124
  let action;
2819
3125
  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: "取消" })
3126
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { flex: 1, minWidth: 200 }, children: [
3127
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3128
+ /* @__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" : "") + ")" }),
3129
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3130
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: () => call2("dsh-memory/embedding-download-cancel", {}), children: "取消" })
2825
3131
  ] }),
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 + "%" } }) }) })
3132
+ /* @__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
3133
  ] });
2828
3134
  } 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
3135
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3136
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-task", children: "使用中" }),
3137
+ localInfo && localInfo.state === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "模型加载中…" }) : null,
3138
+ localInfo && localInfo.state === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "加载失败:" + (localInfo.error || "") }) : null,
3139
+ localInfo && localInfo.state === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "dsh-mem-rb-muted", children: "已就绪" }) : null
2834
3140
  ] });
2835
3141
  } 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)(
3142
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3143
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2838
3144
  NButton,
2839
3145
  {
2840
3146
  disabled: ap.busy,
2841
- onClick: () => call("dsh-memory/embedding-source-set", { source: "local", activeModel: m.id }, switchConfirm),
3147
+ onClick: () => call2("dsh-memory/embedding-source-set", { source: "local", activeModel: m.id }, switchConfirm),
2842
3148
  children: "启用"
2843
3149
  }
2844
3150
  ),
2845
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3151
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2846
3152
  NButton,
2847
3153
  {
2848
3154
  disabled: dlActive,
2849
- onClick: () => call("dsh-memory/embedding-model-delete", { modelId: m.id }, "删除已下载的 " + m.name + "(" + fmtMB(m.totalBytes) + ")?"),
3155
+ onClick: () => call2("dsh-memory/embedding-model-delete", { modelId: m.id }, "删除已下载的 " + m.name + "(" + fmtMB(m.totalBytes) + ")?"),
2850
3156
  children: "删除"
2851
3157
  }
2852
3158
  )
2853
3159
  ] });
2854
3160
  } else {
2855
- action = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3161
+ action = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2856
3162
  NButton,
2857
3163
  {
2858
3164
  disabled: dlActive || !st.ceilings.local,
2859
3165
  title: !st.ceilings.local ? "部署已禁用本地嵌入模型" : "",
2860
- onClick: () => call("dsh-memory/embedding-download-start", { modelId: m.id }),
3166
+ onClick: () => call2("dsh-memory/embedding-download-start", { modelId: m.id }),
2861
3167
  children: (m.state === "partial" ? "继续下载 " : "下载 ") + fmtMB(m.totalBytes)
2862
3168
  }
2863
3169
  );
2864
3170
  }
2865
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3171
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2866
3172
  "div",
2867
3173
  {
2868
3174
  style: { ...S.flexRow, padding: "8px 0", borderBottom: "1px solid var(--dsh-mem-border)", flexWrap: "wrap" },
2869
3175
  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 })
3176
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { minWidth: 150 }, children: [
3177
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600 }, children: m.name }),
3178
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dsh-mem-rb-muted", children: m.tags.join(" · ") + " · " + m.dims + " 维 · 上下文 " + m.contextTokens })
2873
3179
  ] }),
2874
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
3180
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
2875
3181
  action
2876
3182
  ]
2877
3183
  },
@@ -2880,15 +3186,17 @@ var __defProp = Object.defineProperty;
2880
3186
  });
2881
3187
  const vec = st.vectors;
2882
3188
  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) + " 条内容不可嵌入,已跳过)" : "");
3189
+ const lastRun = st.reindex ? st.reindex.last : void 0;
3190
+ 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";
3191
+ 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
3192
  const reindexRunning = !!(st.reindex && st.reindex.running);
2885
3193
  const canRebuild = vecOk && st.source !== "off" && !reindexRunning && !st.apply.busy;
2886
3194
  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)(
3195
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3196
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.flexRow, children: [
3197
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "语义检索(嵌入源)" }),
3198
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2892
3200
  Segmented,
2893
3201
  {
2894
3202
  value: st.source,
@@ -2901,18 +3209,18 @@ var __defProp = Object.defineProperty;
2901
3209
  }
2902
3210
  )
2903
3211
  ] }),
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,
3212
+ /* @__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 + ")" : "") }),
3213
+ st.activeNote ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 4, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: st.activeNote }) : null,
3214
+ err && err !== "__unsupported__" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null,
3215
+ 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
3216
  runtimeRow,
2909
3217
  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)(
3218
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.block, children: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.title, children: "远程连接(生效值;运行时覆盖优先于部署 YAML)" }),
3220
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.note, children: "生效端点 " + (remote.baseURL || "(未配置)") + " · 模型 " + (remote.model || "(未配置)") + " · " + (remote.dimensions > 0 ? remote.dimensions + " 维" : "维度跟随部署") + (remote.apiKeySet ? " · 密钥已设置" : " · 密钥未设置") }),
3221
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3222
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "端点 URL" }),
3223
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2916
3224
  NInput,
2917
3225
  {
2918
3226
  style: RSTY.input,
@@ -2929,9 +3237,9 @@ var __defProp = Object.defineProperty;
2929
3237
  }
2930
3238
  )
2931
3239
  ] }),
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)(
3240
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3241
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "模型名" }),
3242
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2935
3243
  NInput,
2936
3244
  {
2937
3245
  style: RSTY.input,
@@ -2947,8 +3255,8 @@ var __defProp = Object.defineProperty;
2947
3255
  }
2948
3256
  }
2949
3257
  ),
2950
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: RSTY.label, children: "维度" }),
2951
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3258
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "维度" }),
3259
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2952
3260
  NInput,
2953
3261
  {
2954
3262
  style: { width: 90, minWidth: 0, flex: "0 1 90px" },
@@ -2968,9 +3276,9 @@ var __defProp = Object.defineProperty;
2968
3276
  }
2969
3277
  )
2970
3278
  ] }),
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)(
3279
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.row, children: [
3280
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.label, children: "API Key" }),
3281
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2974
3282
  NInput,
2975
3283
  {
2976
3284
  style: RSTY.input,
@@ -2985,8 +3293,8 @@ var __defProp = Object.defineProperty;
2985
3293
  onBlur: commitRemoteKey
2986
3294
  }
2987
3295
  ),
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)(
3296
+ remote.apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.chipAccent, children: "已设置" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: RSTY.chipMuted, children: "未设置" }),
3297
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2990
3298
  NButton,
2991
3299
  {
2992
3300
  title: "写入空串清除运行时密钥(部署 YAML 的密钥不受影响)",
@@ -2996,17 +3304,17 @@ var __defProp = Object.defineProperty;
2996
3304
  )
2997
3305
  ] })
2998
3306
  ] }),
2999
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
3307
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
3000
3308
  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)(
3309
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RSTY.block, children: [
3310
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.title, children: "向量索引" }),
3311
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.note, children: vecNote }),
3312
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RSTY.row, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3005
3313
  NButton,
3006
3314
  {
3007
3315
  disabled: !canRebuild,
3008
3316
  title: rebuildHint,
3009
- onClick: () => call("dsh-memory/embedding-reindex", {}),
3317
+ onClick: () => call2("dsh-memory/embedding-reindex", {}),
3010
3318
  children: "重建索引"
3011
3319
  }
3012
3320
  ) })
@@ -3015,8 +3323,8 @@ var __defProp = Object.defineProperty;
3015
3323
  }
3016
3324
 
3017
3325
  // client/src/tabs/RebuildPanel.tsx
3018
- var import_react13 = require("react");
3019
- var import_jsx_runtime13 = require("react/jsx-runtime");
3326
+ var import_react14 = require("react");
3327
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3020
3328
  var RB_PHASE_LABEL = {
3021
3329
  preparing: "准备中(归档旧数据 · 清空检索库)",
3022
3330
  distilling: "分块蒸馏中",
@@ -3024,21 +3332,21 @@ var __defProp = Object.defineProperty;
3024
3332
  };
3025
3333
  function RebuildPanel(props) {
3026
3334
  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)(() => {
3335
+ const [rbRaw, setRb] = (0, import_react14.useState)(null);
3336
+ const [confirmOpen, setConfirmOpen] = (0, import_react14.useState)(false);
3337
+ const [busy, setBusy] = (0, import_react14.useState)(false);
3338
+ const [rbError, setRbError] = (0, import_react14.useState)(null);
3339
+ const refresh = (0, import_react14.useCallback)(() => {
3032
3340
  rpc("dsh-memory/rebuild-status", {}).then((r) => {
3033
3341
  if (r && r.ok) setRb(r.value);
3034
3342
  }).catch(() => {
3035
3343
  });
3036
3344
  }, [rpc]);
3037
- (0, import_react13.useEffect)(() => {
3345
+ (0, import_react14.useEffect)(() => {
3038
3346
  refresh();
3039
3347
  }, [refresh]);
3040
3348
  const running = !!(rbRaw && rbRaw.running);
3041
- (0, import_react13.useEffect)(() => {
3349
+ (0, import_react14.useEffect)(() => {
3042
3350
  if (!running) return;
3043
3351
  const timer = setInterval(refresh, 1500);
3044
3352
  return () => {
@@ -3083,11 +3391,11 @@ var __defProp = Object.defineProperty;
3083
3391
  } else if (!running && rb.phase === "failed") {
3084
3392
  lastNote = "上次重建:失败:" + (rb.error || "未知错误");
3085
3393
  }
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)(
3394
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3395
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3396
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "重建记忆" }),
3397
+ /* @__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;旧数据先归档(不删除)" }),
3398
+ running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { disabled: busy || rb.cancelRequested, onClick: cancel, children: rb.cancelRequested ? "取消中…" : "取消重建" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3091
3399
  NButton,
3092
3400
  {
3093
3401
  disabled: busy || empty,
@@ -3100,13 +3408,13 @@ var __defProp = Object.defineProperty;
3100
3408
  }
3101
3409
  )
3102
3410
  ] }),
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 + " 条" })
3411
+ running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3412
+ /* @__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 + "%" } }) }),
3413
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
3106
3414
  ] }) : 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)(
3415
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3416
+ rbError ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rbError }) : null,
3417
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3110
3418
  NModal,
3111
3419
  {
3112
3420
  open: true,
@@ -3115,7 +3423,7 @@ var __defProp = Object.defineProperty;
3115
3423
  },
3116
3424
  title: "确认重建全部记忆?",
3117
3425
  footer: [
3118
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3426
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3119
3427
  NButton,
3120
3428
  {
3121
3429
  onClick: () => {
@@ -3125,15 +3433,15 @@ var __defProp = Object.defineProperty;
3125
3433
  },
3126
3434
  "cancel"
3127
3435
  ),
3128
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
3436
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
3129
3437
  ],
3130
3438
  children: [
3131
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3439
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3132
3440
  "将以 L0 原始对话为事实源重新蒸馏:",
3133
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
3441
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
3134
3442
  ",预计 ≥" + rb.estCalls + " 次蒸馏调用。"
3135
3443
  ] }),
3136
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
3444
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
3137
3445
  ]
3138
3446
  }
3139
3447
  ) : null
@@ -3141,8 +3449,8 @@ var __defProp = Object.defineProperty;
3141
3449
  }
3142
3450
 
3143
3451
  // client/src/tabs/RuminatePanel.tsx
3144
- var import_react14 = require("react");
3145
- var import_jsx_runtime14 = require("react/jsx-runtime");
3452
+ var import_react15 = require("react");
3453
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3146
3454
  var RM_PHASE_LABEL = {
3147
3455
  refreshing: "轻量刷新中",
3148
3456
  distilling: "L1 蒸馏中",
@@ -3163,11 +3471,11 @@ var __defProp = Object.defineProperty;
3163
3471
  var RM_IDLE_INTERVAL = 3e4;
3164
3472
  function RuminatePanel(props) {
3165
3473
  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)(() => {
3474
+ const [rmRaw, setRm] = (0, import_react15.useState)(null);
3475
+ const [confirmOpen, setConfirmOpen] = (0, import_react15.useState)(false);
3476
+ const [busy, setBusy] = (0, import_react15.useState)(false);
3477
+ const [rmError, setRmError] = (0, import_react15.useState)(null);
3478
+ const refresh = (0, import_react15.useCallback)(() => {
3171
3479
  return rpc("dsh-memory/ruminate-status", {}).then((r) => {
3172
3480
  if (r && r.ok) {
3173
3481
  const st = r.value;
@@ -3182,14 +3490,14 @@ var __defProp = Object.defineProperty;
3182
3490
  }).catch(() => {
3183
3491
  });
3184
3492
  }, [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)(() => {
3493
+ const pollRef = (0, import_react15.useRef)(1500);
3494
+ const backoffRef = (0, import_react15.useRef)(1);
3495
+ const lastDetailRef = (0, import_react15.useRef)(null);
3496
+ (0, import_react15.useEffect)(() => {
3189
3497
  refresh();
3190
3498
  }, [refresh]);
3191
3499
  const running = !!(rmRaw && (rmRaw.running || RM_RUNNING_PHASES.indexOf(rmRaw.phase) >= 0));
3192
- (0, import_react14.useEffect)(() => {
3500
+ (0, import_react15.useEffect)(() => {
3193
3501
  if (!running) return;
3194
3502
  let alive = true;
3195
3503
  let timer;
@@ -3208,13 +3516,13 @@ var __defProp = Object.defineProperty;
3208
3516
  lastDetailRef.current = null;
3209
3517
  };
3210
3518
  }, [running, refresh]);
3211
- (0, import_react14.useEffect)(() => {
3519
+ (0, import_react15.useEffect)(() => {
3212
3520
  if (running) return;
3213
3521
  const timer = setInterval(refresh, RM_IDLE_INTERVAL);
3214
3522
  return () => clearInterval(timer);
3215
3523
  }, [running, refresh]);
3216
- const [, setTick] = (0, import_react14.useState)(0);
3217
- (0, import_react14.useEffect)(() => {
3524
+ const [, setTick] = (0, import_react15.useState)(0);
3525
+ (0, import_react15.useEffect)(() => {
3218
3526
  if (!running) return;
3219
3527
  const timer = setInterval(() => setTick((n) => n + 1), 1e3);
3220
3528
  return () => clearInterval(timer);
@@ -3265,11 +3573,11 @@ var __defProp = Object.defineProperty;
3265
3573
  }
3266
3574
  const unit = rm.phase === "refreshing" || rm.phase === "relabeling" ? "步" : "会话";
3267
3575
  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)(
3576
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "dsh-mem-rb-card", children: [
3577
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
3578
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "反刍整理" }),
3579
+ /* @__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" }),
3580
+ running ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { disabled: busy || rm.cancelRequested, onClick: cancel, children: rm.cancelRequested ? "取消中…" : "取消整理" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3273
3581
  NButton,
3274
3582
  {
3275
3583
  disabled: busy,
@@ -3282,27 +3590,27 @@ var __defProp = Object.defineProperty;
3282
3590
  }
3283
3591
  )
3284
3592
  ] }),
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)(
3593
+ running ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
3594
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3287
3595
  "div",
3288
3596
  {
3289
3597
  className: "dsh-mem-rb-fill" + (indet ? " dsh-mem-rb-fill-indet" : ""),
3290
3598
  style: { width: indet ? "100%" : barPct + "%" }
3291
3599
  }
3292
3600
  ) }),
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 + " 条" })
3601
+ /* @__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
3602
  ] }) : 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)(
3603
+ running && rm.detail ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6, whiteSpace: "normal" }, children: "当前:" + rm.detail }) : null,
3604
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
3605
+ rmError ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rmError }) : null,
3606
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3299
3607
  NModal,
3300
3608
  {
3301
3609
  open: true,
3302
3610
  onClose: () => setConfirmOpen(false),
3303
3611
  title: "确认反刍整理?",
3304
3612
  footer: [
3305
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3613
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3306
3614
  NButton,
3307
3615
  {
3308
3616
  onClick: () => setConfirmOpen(false),
@@ -3310,11 +3618,11 @@ var __defProp = Object.defineProperty;
3310
3618
  },
3311
3619
  "cancel"
3312
3620
  ),
3313
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
3621
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
3314
3622
  ],
3315
3623
  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 刷新。" })
3624
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: "将扫描未蒸馏缓冲,按会话逐个跑蒸馏管线,完成后强制 L2 场景整合与 L3 画像更新。" }),
3625
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: 8 }, children: "与重建不同:不清空 L1 检索库、不归档旧产物、不改 L0;仅消化攒而未蒸馏的切片,无缓冲时做轻量 L2/L3 刷新。" })
3318
3626
  ]
3319
3627
  }
3320
3628
  ) : null
@@ -3322,13 +3630,13 @@ var __defProp = Object.defineProperty;
3322
3630
  }
3323
3631
 
3324
3632
  // client/src/tabs/OverviewTab.tsx
3325
- var import_jsx_runtime15 = require("react/jsx-runtime");
3633
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3326
3634
  function OverviewTab(props) {
3327
3635
  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)(() => {
3636
+ const [stats, setStats] = (0, import_react16.useState)(null);
3637
+ const [settingsData, setSettingsData] = (0, import_react16.useState)(null);
3638
+ const [error, setError] = (0, import_react16.useState)(null);
3639
+ const load = (0, import_react16.useCallback)(() => {
3332
3640
  rpc("dsh-memory/stats", {}).then((r) => {
3333
3641
  if (r && r.ok) setStats(r.value);
3334
3642
  else setError(r && r.error ? r.error.message : "RPC error");
@@ -3340,7 +3648,7 @@ var __defProp = Object.defineProperty;
3340
3648
  }).catch(() => {
3341
3649
  });
3342
3650
  }, [rpc]);
3343
- (0, import_react15.useEffect)(() => {
3651
+ (0, import_react16.useEffect)(() => {
3344
3652
  load();
3345
3653
  const timer = setInterval(load, 5e3);
3346
3654
  return () => {
@@ -3402,10 +3710,10 @@ var __defProp = Object.defineProperty;
3402
3710
  const toolConflict = settingsData && settingsData.settings ? settingsData.settings.toolConflict !== false : true;
3403
3711
  const toolMutate = settingsData && settingsData.settings ? settingsData.settings.toolMutate !== false : true;
3404
3712
  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)(
3713
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3714
+ 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: [
3715
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
3716
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3409
3717
  SwitchRow,
3410
3718
  {
3411
3719
  label: "记忆模式",
@@ -3416,7 +3724,7 @@ var __defProp = Object.defineProperty;
3416
3724
  }
3417
3725
  }
3418
3726
  ),
3419
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3727
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3420
3728
  SwitchRow,
3421
3729
  {
3422
3730
  label: "捕获",
@@ -3428,7 +3736,7 @@ var __defProp = Object.defineProperty;
3428
3736
  }
3429
3737
  }
3430
3738
  ),
3431
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3739
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3432
3740
  SwitchRow,
3433
3741
  {
3434
3742
  label: "蒸馏",
@@ -3440,7 +3748,7 @@ var __defProp = Object.defineProperty;
3440
3748
  }
3441
3749
  }
3442
3750
  ),
3443
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3751
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3444
3752
  SwitchRow,
3445
3753
  {
3446
3754
  label: "召回",
@@ -3452,8 +3760,8 @@ var __defProp = Object.defineProperty;
3452
3760
  }
3453
3761
  }
3454
3762
  ),
3455
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3456
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3763
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3764
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3457
3765
  SwitchRow,
3458
3766
  {
3459
3767
  label: "高权限模式",
@@ -3464,8 +3772,8 @@ var __defProp = Object.defineProperty;
3464
3772
  }
3465
3773
  }
3466
3774
  ),
3467
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3468
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3775
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3776
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3469
3777
  SwitchRow,
3470
3778
  {
3471
3779
  label: "技能(程序性记忆)",
@@ -3476,8 +3784,8 @@ var __defProp = Object.defineProperty;
3476
3784
  }
3477
3785
  }
3478
3786
  ),
3479
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3480
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3787
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3788
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3481
3789
  SwitchRow,
3482
3790
  {
3483
3791
  label: "Room 管理工具",
@@ -3488,7 +3796,7 @@ var __defProp = Object.defineProperty;
3488
3796
  }
3489
3797
  }
3490
3798
  ),
3491
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3799
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3492
3800
  SwitchRow,
3493
3801
  {
3494
3802
  label: "图谱工具",
@@ -3499,7 +3807,7 @@ var __defProp = Object.defineProperty;
3499
3807
  }
3500
3808
  }
3501
3809
  ),
3502
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3810
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3503
3811
  SwitchRow,
3504
3812
  {
3505
3813
  label: "反刍工具",
@@ -3510,7 +3818,7 @@ var __defProp = Object.defineProperty;
3510
3818
  }
3511
3819
  }
3512
3820
  ),
3513
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3821
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3514
3822
  SwitchRow,
3515
3823
  {
3516
3824
  label: "冲突工具",
@@ -3521,7 +3829,7 @@ var __defProp = Object.defineProperty;
3521
3829
  }
3522
3830
  }
3523
3831
  ),
3524
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3832
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3525
3833
  SwitchRow,
3526
3834
  {
3527
3835
  label: "写删工具",
@@ -3532,8 +3840,8 @@ var __defProp = Object.defineProperty;
3532
3840
  }
3533
3841
  }
3534
3842
  ),
3535
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3536
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3843
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3844
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3537
3845
  SwitchRow,
3538
3846
  {
3539
3847
  label: "人工冲突裁决",
@@ -3544,42 +3852,43 @@ var __defProp = Object.defineProperty;
3544
3852
  }
3545
3853
  }
3546
3854
  ),
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
3855
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
3856
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
3857
+ ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3550
3858
  ] }) : 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 })
3859
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(EmbeddingSection, { rpc }),
3860
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RebuildPanel, { rpc }),
3861
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RuminatePanel, { rpc }),
3862
+ degraded ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
3863
+ 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: [
3864
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
3865
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
3866
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
3867
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statNum, children: t.num }),
3868
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statLabel, children: t.label })
3561
3869
  ] }, t.label);
3562
3870
  }) }),
3563
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3871
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3564
3872
  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] })
3873
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: S.infoRow, children: [
3874
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoKey, children: row2[0] }),
3875
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoVal, children: row2[1] })
3568
3876
  ] }, row2[0]);
3569
3877
  })
3570
3878
  ] }),
3571
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3879
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArchiveSection, { rpc }),
3880
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3572
3881
  ] });
3573
3882
  }
3574
3883
 
3575
3884
  // client/src/tabs/PersonaTab.tsx
3576
- var import_react16 = require("react");
3577
- var import_jsx_runtime16 = require("react/jsx-runtime");
3885
+ var import_react17 = require("react");
3886
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3578
3887
  function PersonaTab(props) {
3579
3888
  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)(() => {
3889
+ const [content, setContent] = (0, import_react17.useState)(null);
3890
+ const [error, setError] = (0, import_react17.useState)(null);
3891
+ const load = (0, import_react17.useCallback)(() => {
3583
3892
  setError(null);
3584
3893
  rpc("dsh-memory/persona", {}).then((r) => {
3585
3894
  if (r && r.ok) setContent(r.value.content);
@@ -3588,64 +3897,55 @@ var __defProp = Object.defineProperty;
3588
3897
  setError(String(e && e.message || e));
3589
3898
  });
3590
3899
  }, [rpc]);
3591
- (0, import_react16.useEffect)(() => {
3900
+ (0, import_react17.useEffect)(() => {
3592
3901
  load();
3593
3902
  }, [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: "刷新" })
3903
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3904
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3905
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
3906
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
3907
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: load, children: "刷新" })
3599
3908
  ] }),
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 会自动产出。" })
3909
+ error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
3910
+ 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
3911
  ] });
3603
3912
  }
3604
3913
 
3605
3914
  // client/src/tabs/RecordsTab.tsx
3606
- var import_react17 = require("react");
3607
- var import_jsx_runtime17 = require("react/jsx-runtime");
3915
+ var import_react18 = require("react");
3916
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3608
3917
  function retiredSelOf(r) {
3609
3918
  if (r === "active") return false;
3610
3919
  if (r === "retired") return true;
3611
3920
  return void 0;
3612
3921
  }
3613
- var TYPE_CHOICES = [
3614
- "persona",
3615
- "episodic",
3616
- "instruction",
3617
- "work_fact",
3618
- "work_task",
3619
- "work_method",
3620
- "work_artifact"
3621
- ];
3622
3922
  var DELETE_LIMIT = 200;
3623
3923
  function RecordsTab(props) {
3624
3924
  const rpc = props.rpc;
3625
3925
  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)(
3926
+ const [items, setItems] = (0, import_react18.useState)([]);
3927
+ const [hasMore, setHasMore] = (0, import_react18.useState)(false);
3928
+ const [total, setTotal] = (0, import_react18.useState)(null);
3929
+ const [sceneOptions, setSceneOptions] = (0, import_react18.useState)([]);
3930
+ const [loading, setLoading] = (0, import_react18.useState)(false);
3931
+ const [truncated, setTruncated] = (0, import_react18.useState)(false);
3932
+ const [error, setError] = (0, import_react18.useState)(null);
3933
+ const [expandedId, setExpandedId] = (0, import_react18.useState)(null);
3934
+ const [sel, setSel] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
3935
+ const [hiPriv, setHiPriv] = (0, import_react18.useState)(false);
3936
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react18.useState)(false);
3937
+ const [query, setQuery] = (0, import_react18.useState)("");
3938
+ const [typeFilter, setTypeFilter] = (0, import_react18.useState)("");
3939
+ const [sceneFilter, setSceneFilter] = (0, import_react18.useState)("");
3940
+ const [hallFilter, setHallFilter] = (0, import_react18.useState)([]);
3941
+ const [tagFilter, setTagFilter] = (0, import_react18.useState)("");
3942
+ const [untaggedOnly, setUntaggedOnly] = (0, import_react18.useState)(false);
3943
+ const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
3944
+ const [retiredFilter, setRetiredFilter] = (0, import_react18.useState)("");
3945
+ const [wingCatalog, setHallCatalog] = (0, import_react18.useState)(null);
3946
+ const [last, setLast] = (0, import_react18.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
3947
+ const seqRef = (0, import_react18.useRef)(0);
3948
+ const fetchPage = (0, import_react18.useCallback)(
3649
3949
  (conds, offset, append) => {
3650
3950
  setLoading(true);
3651
3951
  setError(null);
@@ -3675,6 +3975,7 @@ var __defProp = Object.defineProperty;
3675
3975
  setTruncated(!!v.truncated);
3676
3976
  if (v.scenes) setSceneOptions(v.scenes);
3677
3977
  if (v.wingCatalog) setHallCatalog(v.wingCatalog);
3978
+ if (v.typeCatalog) registerTypeCatalog(v.typeCatalog);
3678
3979
  }).catch((e) => {
3679
3980
  if (token !== seqRef.current) return;
3680
3981
  setLoading(false);
@@ -3694,23 +3995,23 @@ var __defProp = Object.defineProperty;
3694
3995
  setLast(conds);
3695
3996
  fetchPage(conds, 0, false);
3696
3997
  };
3697
- const loadRooms = (0, import_react17.useCallback)(() => {
3998
+ const loadRooms = (0, import_react18.useCallback)(() => {
3698
3999
  rpc("dsh-memory/rooms-get", {}).then((r) => {
3699
4000
  if (r && r.ok) setOrphanCount(r.value.orphanCount ?? 0);
3700
4001
  }).catch(() => {
3701
4002
  });
3702
4003
  }, [rpc]);
3703
- (0, import_react17.useEffect)(() => {
4004
+ (0, import_react18.useEffect)(() => {
3704
4005
  fetchPage({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" }, 0, false);
3705
4006
  loadRooms();
3706
4007
  }, [fetchPage, loadRooms]);
3707
- const loadHiPriv = (0, import_react17.useCallback)(() => {
4008
+ const loadHiPriv = (0, import_react18.useCallback)(() => {
3708
4009
  rpc("dsh-memory/settings-get", {}).then((r) => {
3709
4010
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
3710
4011
  }).catch(() => {
3711
4012
  });
3712
4013
  }, [rpc]);
3713
- (0, import_react17.useEffect)(() => {
4014
+ (0, import_react18.useEffect)(() => {
3714
4015
  loadHiPriv();
3715
4016
  }, [loadHiPriv]);
3716
4017
  const toggleHiPriv = () => {
@@ -3751,7 +4052,9 @@ var __defProp = Object.defineProperty;
3751
4052
  if (r && r.ok) {
3752
4053
  setSel(/* @__PURE__ */ new Set());
3753
4054
  if (expandedId && ids.indexOf(expandedId) >= 0) setExpandedId(null);
3754
- fetchPage(last, 0, false);
4055
+ const removed = r.value?.deleted ?? ids.length;
4056
+ setItems((prev) => prev.filter((m) => !ids.includes(m.id)));
4057
+ setTotal((t) => t === null ? null : Math.max(0, t - removed));
3755
4058
  if (showRetired) loadRetired();
3756
4059
  } else if (r) setError(r.error ? r.error.message : "退场失败");
3757
4060
  }).catch((e) => setError(String(e && e.message || e)));
@@ -3766,16 +4069,17 @@ var __defProp = Object.defineProperty;
3766
4069
  return next;
3767
4070
  });
3768
4071
  if (expandedId === id) setExpandedId(null);
3769
- fetchPage(last, 0, false);
4072
+ setItems((prev) => prev.filter((m) => m.id !== id));
4073
+ setTotal((t) => t === null ? null : Math.max(0, t - 1));
3770
4074
  if (showRetired) loadRetired();
3771
4075
  } else if (r) setError(r.error ? r.error.message : "退场失败");
3772
4076
  }).catch((e) => setError(String(e && e.message || e)));
3773
4077
  };
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)(() => {
4078
+ const [retired, setRetired] = (0, import_react18.useState)([]);
4079
+ const [retiredTotal, setRetiredTotal] = (0, import_react18.useState)(0);
4080
+ const [showRetired, setShowRetired] = (0, import_react18.useState)(false);
4081
+ const [retiredBusy, setRetiredBusy] = (0, import_react18.useState)(false);
4082
+ const loadRetired = (0, import_react18.useCallback)(() => {
3779
4083
  setRetiredBusy(true);
3780
4084
  rpc("dsh-memory/records-retired", { limit: 100, offset: 0 }).then((r) => {
3781
4085
  if (r && r.ok) {
@@ -3784,7 +4088,7 @@ var __defProp = Object.defineProperty;
3784
4088
  } else if (r) setError(r.error ? r.error.message : "已退场列表加载失败");
3785
4089
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
3786
4090
  }, [rpc]);
3787
- (0, import_react17.useEffect)(() => {
4091
+ (0, import_react18.useEffect)(() => {
3788
4092
  if (showRetired) loadRetired();
3789
4093
  }, [showRetired, loadRetired]);
3790
4094
  const restoreRecords = (ids) => {
@@ -3793,7 +4097,10 @@ var __defProp = Object.defineProperty;
3793
4097
  rpc("dsh-memory/records-restore", { ids }).then((r) => {
3794
4098
  if (r && r.ok) {
3795
4099
  loadRetired();
3796
- fetchPage(last, 0, false);
4100
+ const restored = new Set(ids);
4101
+ setItems(
4102
+ (prev) => prev.map((m) => restored.has(m.id) ? { ...m, retired: false, retiredReason: void 0 } : m)
4103
+ );
3797
4104
  } else if (r) setError(r.error ? r.error.message : "恢复失败");
3798
4105
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
3799
4106
  };
@@ -3801,14 +4108,15 @@ var __defProp = Object.defineProperty;
3801
4108
  conflict: "裁决退场",
3802
4109
  superseded: "被取代",
3803
4110
  manual: "人工退场",
4111
+ obsolete: "声明过时",
3804
4112
  unknown: "已退场"
3805
4113
  };
3806
4114
  const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
3807
- const [usageSummary, setUsageSummary] = (0, import_react17.useState)(null);
4115
+ const [usageSummary, setUsageSummary] = (0, import_react18.useState)(null);
3808
4116
  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)(
4117
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4118
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.toolbar, children: [
4119
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3812
4120
  NInput,
3813
4121
  {
3814
4122
  style: { flex: 1, minWidth: 160 },
@@ -3819,23 +4127,32 @@ var __defProp = Object.defineProperty;
3819
4127
  },
3820
4128
  onKeyDown: (e) => {
3821
4129
  if (e.key === "Enter") search();
4130
+ else if (e.key === "Escape" || e.key === "Backspace" && (e.ctrlKey || e.metaKey)) {
4131
+ if (query.length > 0) {
4132
+ e.preventDefault();
4133
+ setQuery("");
4134
+ const conds = { query: "", type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter, untagged: untaggedOnly, retired: retiredFilter };
4135
+ setLast(conds);
4136
+ fetchPage(conds, 0, false);
4137
+ }
4138
+ }
3822
4139
  }
3823
4140
  }
3824
4141
  ),
3825
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4142
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3826
4143
  NSel,
3827
4144
  {
3828
4145
  style: { maxWidth: 200 },
3829
4146
  options: [{ id: "", label: "全部类型" }].concat(
3830
- TYPE_CHOICES.map((t) => {
3831
- return { id: t, label: TYPE_LABELS[t] || t };
4147
+ (typeCatalogIds().length > 0 ? typeCatalogIds() : [...new Set(items.map((m) => m.type))]).map((t) => {
4148
+ return { id: t, label: typeLabel(t) };
3832
4149
  })
3833
4150
  ),
3834
4151
  value: typeFilter,
3835
4152
  onChange: setTypeFilter
3836
4153
  }
3837
4154
  ),
3838
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4155
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3839
4156
  NSel,
3840
4157
  {
3841
4158
  style: { maxWidth: 220 },
@@ -3848,7 +4165,7 @@ var __defProp = Object.defineProperty;
3848
4165
  onChange: setSceneFilter
3849
4166
  }
3850
4167
  ),
3851
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4168
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3852
4169
  WingMultiSelect,
3853
4170
  {
3854
4171
  options: wingCatalog ?? Array.from(new Set(items.map((m) => m.hall).filter((h) => !!h))).map((id) => ({ id, label: id })),
@@ -3856,8 +4173,8 @@ var __defProp = Object.defineProperty;
3856
4173
  onChange: setHallFilter
3857
4174
  }
3858
4175
  ),
3859
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: search, children: "搜索" }),
3860
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4176
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: search, children: "搜索" }),
4177
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3861
4178
  NButton,
3862
4179
  {
3863
4180
  style: {
@@ -3871,8 +4188,8 @@ var __defProp = Object.defineProperty;
3871
4188
  }
3872
4189
  )
3873
4190
  ] }),
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)(
4191
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
4192
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3876
4193
  "button",
3877
4194
  {
3878
4195
  type: "button",
@@ -3897,10 +4214,10 @@ var __defProp = Object.defineProperty;
3897
4214
  children: "无绑定 · " + orphanCount
3898
4215
  }
3899
4216
  ),
3900
- (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
4217
+ (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
3901
4218
  "筛选中:",
3902
4219
  untaggedOnly ? "无绑定" : tagFilter,
3903
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4220
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3904
4221
  "button",
3905
4222
  {
3906
4223
  type: "button",
@@ -3917,7 +4234,7 @@ var __defProp = Object.defineProperty;
3917
4234
  }
3918
4235
  )
3919
4236
  ] }),
3920
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4237
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3921
4238
  "button",
3922
4239
  {
3923
4240
  type: "button",
@@ -3946,15 +4263,15 @@ var __defProp = Object.defineProperty;
3946
4263
  children: "导出孤儿"
3947
4264
  }
3948
4265
  ),
3949
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4266
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
3950
4267
  ] }),
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: "退场筛查" }),
4268
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4269
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
4270
+ usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
4271
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "退场筛查" }),
3955
4272
  [["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
3956
4273
  const on = retiredFilter === val;
3957
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4274
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3958
4275
  "button",
3959
4276
  {
3960
4277
  type: "button",
@@ -3974,7 +4291,7 @@ var __defProp = Object.defineProperty;
3974
4291
  val
3975
4292
  );
3976
4293
  }),
3977
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4294
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3978
4295
  NButton,
3979
4296
  {
3980
4297
  style: selCount > 0 ? { color: "var(--dsh-mem-danger)" } : void 0,
@@ -3984,7 +4301,7 @@ var __defProp = Object.defineProperty;
3984
4301
  children: "删除选中" + (selCount > 0 ? "(" + selCount + ")" : "")
3985
4302
  }
3986
4303
  ),
3987
- selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4304
+ selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3988
4305
  NButton,
3989
4306
  {
3990
4307
  onClick: () => {
@@ -3993,8 +4310,8 @@ var __defProp = Object.defineProperty;
3993
4310
  children: "清空选择"
3994
4311
  }
3995
4312
  ) : null,
3996
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
3997
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4313
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4314
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3998
4315
  NButton,
3999
4316
  {
4000
4317
  onClick: () => {
@@ -4005,13 +4322,13 @@ var __defProp = Object.defineProperty;
4005
4322
  }
4006
4323
  )
4007
4324
  ] }),
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) => {
4325
+ !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4326
+ error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.error, children: error }) : null,
4327
+ truncated ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4328
+ items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4012
4329
  const open = expandedId === m.id;
4013
4330
  const checked = sel.has(m.id);
4014
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4331
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4015
4332
  "div",
4016
4333
  {
4017
4334
  className: "dsh-mem-card dsh-mem-card-hover",
@@ -4020,8 +4337,8 @@ var __defProp = Object.defineProperty;
4020
4337
  setExpandedId(open ? null : m.id);
4021
4338
  },
4022
4339
  children: [
4023
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.cardHead, children: [
4024
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4340
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4341
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4025
4342
  "input",
4026
4343
  {
4027
4344
  type: "checkbox",
@@ -4036,9 +4353,9 @@ var __defProp = Object.defineProperty;
4036
4353
  }
4037
4354
  }
4038
4355
  ),
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)(
4356
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: tagClass(m.type), children: typeLabel(m.type) }),
4357
+ 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,
4358
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4042
4359
  "span",
4043
4360
  {
4044
4361
  title: "该记忆已退场(软删):移出检索面但仍可恢复,并未真正删除",
@@ -4053,8 +4370,8 @@ var __defProp = Object.defineProperty;
4053
4370
  children: "已退场" + (m.retiredReason ? " · " + (RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason) : "")
4054
4371
  }
4055
4372
  ) : null,
4056
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4057
- m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4373
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4374
+ m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4058
4375
  "span",
4059
4376
  {
4060
4377
  title: "成熟度(优先级 + 被用次数 + 新鲜度合成):" + m.maturity,
@@ -4069,7 +4386,7 @@ var __defProp = Object.defineProperty;
4069
4386
  children: m.maturity === "high" ? "成熟·高" : m.maturity === "mid" ? "成熟·中" : "成熟·低"
4070
4387
  }
4071
4388
  ) : null,
4072
- m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4389
+ m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4073
4390
  "span",
4074
4391
  {
4075
4392
  style: {
@@ -4084,7 +4401,7 @@ var __defProp = Object.defineProperty;
4084
4401
  children: "老化 " + Math.round(m.agingWeight * 100) + "%"
4085
4402
  }
4086
4403
  ) : null,
4087
- m.usage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4404
+ m.usage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4088
4405
  "span",
4089
4406
  {
4090
4407
  style: S.muted,
@@ -4092,10 +4409,10 @@ var __defProp = Object.defineProperty;
4092
4409
  children: "用 " + m.usage.used + "/" + m.usage.attempts
4093
4410
  }
4094
4411
  ) : 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)(
4412
+ m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4413
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4414
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
4415
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4099
4416
  NButton,
4100
4417
  {
4101
4418
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-accent)" },
@@ -4106,7 +4423,7 @@ var __defProp = Object.defineProperty;
4106
4423
  },
4107
4424
  children: "恢复"
4108
4425
  }
4109
- ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4426
+ ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4110
4427
  NButton,
4111
4428
  {
4112
4429
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-danger)" },
@@ -4119,34 +4436,34 @@ var __defProp = Object.defineProperty;
4119
4436
  }
4120
4437
  ) : null
4121
4438
  ] }),
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
4439
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content }),
4440
+ 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
4441
  ]
4125
4442
  },
4126
4443
  m.id
4127
4444
  );
4128
4445
  }),
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
4446
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
4447
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
4448
+ showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
4449
+ showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4133
4450
  ] }),
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: "恢复" })
4451
+ 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: [
4452
+ retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
4453
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4454
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
4455
+ m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
4456
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4457
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
4458
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4142
4459
  ] }),
4143
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.content, children: m.content })
4460
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content })
4144
4461
  ] }, m.id)),
4145
- retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4462
+ retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4146
4463
  ] }) }) : 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)(
4464
+ hasMore ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.flexRow, children: [
4465
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4466
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4150
4467
  NButton,
4151
4468
  {
4152
4469
  disabled: loading,
@@ -4160,9 +4477,9 @@ var __defProp = Object.defineProperty;
4160
4477
  ] });
4161
4478
  }
4162
4479
  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)(() => {
4480
+ const [open, setOpen] = (0, import_react18.useState)(false);
4481
+ const wrapRef = (0, import_react18.useRef)(null);
4482
+ (0, import_react18.useEffect)(() => {
4166
4483
  if (!open) return;
4167
4484
  const onDown = (e) => {
4168
4485
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -4182,8 +4499,8 @@ var __defProp = Object.defineProperty;
4182
4499
  const toggle = (id) => {
4183
4500
  props.onChange(props.selected.includes(id) ? props.selected.filter((x) => x !== id) : [...props.selected, id]);
4184
4501
  };
4185
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4186
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4502
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4503
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4187
4504
  "button",
4188
4505
  {
4189
4506
  type: "button",
@@ -4192,31 +4509,31 @@ var __defProp = Object.defineProperty;
4192
4509
  "aria-expanded": open,
4193
4510
  onClick: () => setOpen(!open),
4194
4511
  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" : "") })
4512
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
4513
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
4197
4514
  ]
4198
4515
  }
4199
4516
  ),
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,
4517
+ open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
4518
+ props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
4202
4519
  props.options.map((o) => {
4203
4520
  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 })
4521
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
4522
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
4523
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
4207
4524
  ] }, o.id);
4208
4525
  }),
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: "清除筛选" })
4526
+ props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
4527
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check" }),
4528
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
4212
4529
  ] }) : null
4213
4530
  ] }) : null
4214
4531
  ] });
4215
4532
  }
4216
4533
 
4217
4534
  // client/src/tabs/RoomsTab.tsx
4218
- var import_react18 = require("react");
4219
- var import_jsx_runtime18 = require("react/jsx-runtime");
4535
+ var import_react19 = require("react");
4536
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4220
4537
  function majorOf(slug) {
4221
4538
  const i = slug.indexOf("/");
4222
4539
  return i === -1 ? slug : slug.slice(0, i);
@@ -4245,26 +4562,26 @@ var __defProp = Object.defineProperty;
4245
4562
  };
4246
4563
  function RoomsTab(props) {
4247
4564
  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)(() => {
4565
+ const [registry, setRegistry] = (0, import_react19.useState)([]);
4566
+ const [rooms, setRooms] = (0, import_react19.useState)([]);
4567
+ const [orphanCount, setOrphanCount] = (0, import_react19.useState)(0);
4568
+ const [busy, setBusy] = (0, import_react19.useState)(false);
4569
+ const [msg, setMsg] = (0, import_react19.useState)(null);
4570
+ const [error, setError] = (0, import_react19.useState)(null);
4571
+ const [hiPriv, setHiPriv] = (0, import_react19.useState)(false);
4572
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react19.useState)(false);
4573
+ const [regSlug, setRegSlug] = (0, import_react19.useState)("");
4574
+ const [regLabel, setRegLabel] = (0, import_react19.useState)("");
4575
+ const [regDesc, setRegDesc] = (0, import_react19.useState)("");
4576
+ const [form, setForm] = (0, import_react19.useState)(null);
4577
+ const [preview, setPreview] = (0, import_react19.useState)(null);
4578
+ const [grownOpen, setGrownOpen] = (0, import_react19.useState)(false);
4579
+ const [dragOverHall, setDragOverHall] = (0, import_react19.useState)(null);
4580
+ const [picking, setPicking] = (0, import_react19.useState)(null);
4581
+ const [editing, setEditing] = (0, import_react19.useState)(null);
4582
+ const [expandedRooms, setExpandedRooms] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
4583
+ const [roomRecords, setRoomRecords] = (0, import_react19.useState)({});
4584
+ const [expandedHalls, setExpandedHalls] = (0, import_react19.useState)(() => {
4268
4585
  try {
4269
4586
  const v = window.localStorage.getItem("dsh.memory.halls.open");
4270
4587
  return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
@@ -4272,9 +4589,9 @@ var __defProp = Object.defineProperty;
4272
4589
  return /* @__PURE__ */ new Set();
4273
4590
  }
4274
4591
  });
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);
4592
+ const [filter, setFilter] = (0, import_react19.useState)("");
4593
+ const dragRef = (0, import_react19.useRef)(null);
4594
+ const [ghost, setGhost] = (0, import_react19.useState)(null);
4278
4595
  const onDragLabelDown = (ev, slug) => {
4279
4596
  if (!hiPriv || busy || ev.button !== 0) return;
4280
4597
  ev.currentTarget.setPointerCapture(ev.pointerId);
@@ -4299,7 +4616,7 @@ var __defProp = Object.defineProperty;
4299
4616
  setDragOverHall(null);
4300
4617
  if (hall) beginReclass(d.from, hall);
4301
4618
  };
4302
- const loadAll = (0, import_react18.useCallback)(() => {
4619
+ const loadAll = (0, import_react19.useCallback)(() => {
4303
4620
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4304
4621
  if (r && r.ok) {
4305
4622
  setRooms(r.value.rooms ?? []);
@@ -4308,13 +4625,13 @@ var __defProp = Object.defineProperty;
4308
4625
  }
4309
4626
  }).catch(() => void 0);
4310
4627
  }, [rpc]);
4311
- const loadHiPriv = (0, import_react18.useCallback)(() => {
4628
+ const loadHiPriv = (0, import_react19.useCallback)(() => {
4312
4629
  rpc("dsh-memory/settings-get", {}).then((r) => {
4313
4630
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4314
4631
  }).catch(() => {
4315
4632
  });
4316
4633
  }, [rpc]);
4317
- (0, import_react18.useEffect)(() => {
4634
+ (0, import_react19.useEffect)(() => {
4318
4635
  loadAll();
4319
4636
  loadHiPriv();
4320
4637
  }, [loadAll, loadHiPriv]);
@@ -4428,7 +4745,10 @@ var __defProp = Object.defineProperty;
4428
4745
  loadAll();
4429
4746
  if (expandedRooms.has(slug)) {
4430
4747
  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 } }));
4748
+ if (rr && rr.ok) {
4749
+ registerTypeCatalog(rr.value.typeCatalog);
4750
+ setRoomRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
4751
+ }
4432
4752
  }
4433
4753
  } else setError(r && r.error ? r.error.message : "操作失败");
4434
4754
  });
@@ -4450,6 +4770,7 @@ var __defProp = Object.defineProperty;
4450
4770
  }
4451
4771
  const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
4452
4772
  if (r && r.ok) {
4773
+ registerTypeCatalog(r.value.typeCatalog);
4453
4774
  const next = new Set(expandedRooms);
4454
4775
  next.add(slug);
4455
4776
  setExpandedRooms(next);
@@ -4465,7 +4786,7 @@ var __defProp = Object.defineProperty;
4465
4786
  if (r.value.csv) downloadCsv(r.value.csv, `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`);
4466
4787
  else setError("导出为空");
4467
4788
  });
4468
- const groups = (0, import_react18.useMemo)(() => {
4789
+ const groups = (0, import_react19.useMemo)(() => {
4469
4790
  const countOf = new Map(rooms.map((r) => [r.room, r.count]));
4470
4791
  const byHall = /* @__PURE__ */ new Map();
4471
4792
  for (const e of registry) {
@@ -4482,7 +4803,7 @@ var __defProp = Object.defineProperty;
4482
4803
  total: entries.reduce((s2, e) => s2 + (countOf.get(e.slug) ?? 0), 0)
4483
4804
  })).sort((a, b) => a.hall.localeCompare(b.hall));
4484
4805
  }, [registry, rooms]);
4485
- const grownOnly = (0, import_react18.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4806
+ const grownOnly = (0, import_react19.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4486
4807
  const persistHalls = (next) => {
4487
4808
  try {
4488
4809
  window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
@@ -4502,7 +4823,7 @@ var __defProp = Object.defineProperty;
4502
4823
  persistHalls(next);
4503
4824
  };
4504
4825
  const normFilter = filter.trim().toLowerCase();
4505
- const visibleGroups = (0, import_react18.useMemo)(() => {
4826
+ const visibleGroups = (0, import_react19.useMemo)(() => {
4506
4827
  if (!normFilter) return groups;
4507
4828
  return groups.map((g) => {
4508
4829
  const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
@@ -4512,15 +4833,15 @@ var __defProp = Object.defineProperty;
4512
4833
  return { ...g, entries };
4513
4834
  }).filter((g) => g.entries.length > 0);
4514
4835
  }, [groups, normFilter]);
4515
- const visibleGrown = (0, import_react18.useMemo)(
4836
+ const visibleGrown = (0, import_react19.useMemo)(
4516
4837
  () => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
4517
4838
  [grownOnly, normFilter]
4518
4839
  );
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)(
4840
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4841
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
4842
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
4843
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4844
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4524
4845
  "button",
4525
4846
  {
4526
4847
  type: "button",
@@ -4537,7 +4858,7 @@ var __defProp = Object.defineProperty;
4537
4858
  children: "导出词表"
4538
4859
  }
4539
4860
  ),
4540
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4861
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4541
4862
  "button",
4542
4863
  {
4543
4864
  type: "button",
@@ -4557,7 +4878,7 @@ var __defProp = Object.defineProperty;
4557
4878
  ]
4558
4879
  }
4559
4880
  ),
4560
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4881
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4561
4882
  "button",
4562
4883
  {
4563
4884
  type: "button",
@@ -4572,10 +4893,10 @@ var __defProp = Object.defineProperty;
4572
4893
  children: hiPriv ? "高权限:开" : "高权限:关"
4573
4894
  }
4574
4895
  ),
4575
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
4896
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
4576
4897
  ] }),
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)(
4898
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
4899
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4579
4900
  "input",
4580
4901
  {
4581
4902
  value: filter,
@@ -4584,14 +4905,14 @@ var __defProp = Object.defineProperty;
4584
4905
  style: { ...S.input, width: 250, fontSize: 12 }
4585
4906
  }
4586
4907
  ),
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: "收起全部" })
4908
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
4909
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
4910
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4911
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
4912
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
4592
4913
  ] }),
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)(
4914
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
4915
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4595
4916
  "input",
4596
4917
  {
4597
4918
  value: regSlug,
@@ -4601,7 +4922,7 @@ var __defProp = Object.defineProperty;
4601
4922
  style: { ...S.input, width: 210, fontSize: 12 }
4602
4923
  }
4603
4924
  ),
4604
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4925
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4605
4926
  "input",
4606
4927
  {
4607
4928
  value: regLabel,
@@ -4611,7 +4932,7 @@ var __defProp = Object.defineProperty;
4611
4932
  style: { ...S.input, width: 110, fontSize: 12 }
4612
4933
  }
4613
4934
  ),
4614
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4935
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4615
4936
  "input",
4616
4937
  {
4617
4938
  value: regDesc,
@@ -4621,7 +4942,7 @@ var __defProp = Object.defineProperty;
4621
4942
  style: { ...S.input, width: 170, fontSize: 12 }
4622
4943
  }
4623
4944
  ),
4624
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4945
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4625
4946
  "button",
4626
4947
  {
4627
4948
  type: "button",
@@ -4631,26 +4952,26 @@ var __defProp = Object.defineProperty;
4631
4952
  children: "注册"
4632
4953
  }
4633
4954
  ),
4634
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
4955
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
4635
4956
  ] }),
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: [
4957
+ 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: [
4958
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4638
4959
  "编辑 ",
4639
4960
  editing.slug
4640
4961
  ] }),
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: "取消" })
4962
+ /* @__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 } }),
4963
+ /* @__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 } }),
4964
+ /* @__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: "保存" }),
4965
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
4645
4966
  ] }) : 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: [
4967
+ 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: [
4968
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4648
4969
  form.action === "merge" ? "合并" : "归类/改名",
4649
4970
  " ",
4650
4971
  form.from,
4651
4972
  " →"
4652
4973
  ] }),
4653
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4974
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4654
4975
  "input",
4655
4976
  {
4656
4977
  value: form.to,
@@ -4660,7 +4981,7 @@ var __defProp = Object.defineProperty;
4660
4981
  style: { ...S.input, width: 190, fontSize: 12 }
4661
4982
  }
4662
4983
  ),
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)(
4984
+ 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
4985
  "button",
4665
4986
  {
4666
4987
  type: "button",
@@ -4671,32 +4992,32 @@ var __defProp = Object.defineProperty;
4671
4992
  },
4672
4993
  gg.hall
4673
4994
  )) }) : 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: () => {
4995
+ /* @__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: "预览" }),
4996
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => {
4676
4997
  setForm(null);
4677
4998
  setPreview(null);
4678
4999
  setPicking(null);
4679
5000
  }, 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: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5001
+ picking ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
5002
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
4682
5003
  ] }) : 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: [
5004
+ 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: [
5005
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { children: preview.notice }),
5006
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
5007
+ /* @__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
5008
  "确认执行",
4688
5009
  preview.action === "merge" ? "合并" : "归类/改名"
4689
5010
  ] }),
4690
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5011
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
4691
5012
  ] })
4692
5013
  ] }) : 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) => {
5014
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: msg }) : null,
5015
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
5016
+ 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,
5017
+ 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
5018
  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)(
5019
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
5020
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4700
5021
  "div",
4701
5022
  {
4702
5023
  "data-hall": g.hall,
@@ -4737,7 +5058,7 @@ var __defProp = Object.defineProperty;
4737
5058
  },
4738
5059
  title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
4739
5060
  children: [
4740
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5061
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4741
5062
  "button",
4742
5063
  {
4743
5064
  type: "button",
@@ -4750,13 +5071,13 @@ var __defProp = Object.defineProperty;
4750
5071
  children: hallOpen ? "▾" : "▸"
4751
5072
  }
4752
5073
  ),
4753
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5074
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
4754
5075
  g.hall,
4755
- g.label ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5076
+ g.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
4756
5077
  ] }),
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)(
5078
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
5079
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5080
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4760
5081
  "button",
4761
5082
  {
4762
5083
  type: "button",
@@ -4777,10 +5098,10 @@ var __defProp = Object.defineProperty;
4777
5098
  const standalone = e.slug === g.hall;
4778
5099
  const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
4779
5100
  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)(
5101
+ 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: [
5102
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5103
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5104
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4784
5105
  "button",
4785
5106
  {
4786
5107
  type: "button",
@@ -4790,7 +5111,7 @@ var __defProp = Object.defineProperty;
4790
5111
  children: expandedRooms.has(e.slug) ? "▾" : "▸"
4791
5112
  }
4792
5113
  ),
4793
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5114
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4794
5115
  "span",
4795
5116
  {
4796
5117
  style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
@@ -4804,20 +5125,20 @@ var __defProp = Object.defineProperty;
4804
5125
  ]
4805
5126
  }
4806
5127
  ),
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
5128
+ e.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: e.label }) : null,
5129
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: count + " 条" }),
5130
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5131
+ (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
4811
5132
  ] }),
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: () => {
5133
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5134
+ !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5135
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
4815
5136
  setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
4816
5137
  setForm(null);
4817
5138
  setPreview(null);
4818
5139
  setPicking(null);
4819
5140
  }, style: btn, children: "编辑" }),
4820
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5141
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4821
5142
  "button",
4822
5143
  {
4823
5144
  type: "button",
@@ -4838,43 +5159,43 @@ var __defProp = Object.defineProperty;
4838
5159
  children: picking === e.slug ? "选 hall…" : "归类"
4839
5160
  }
4840
5161
  ),
4841
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5162
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
4842
5163
  setForm({ action: "rename", from: e.slug, to: "" });
4843
5164
  setPreview(null);
4844
5165
  }, style: btn, children: "改名" }),
4845
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5166
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
4846
5167
  setForm({ action: "merge", from: e.slug, to: "" });
4847
5168
  setPreview(null);
4848
5169
  }, 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
5170
+ /* @__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 ? "恢复" : "退役" }),
5171
+ !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
5172
  ] }),
4852
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5173
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
4853
5174
  ] })
4854
5175
  ] }),
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 }),
5176
+ 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: [
5177
+ (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: [
5178
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
4858
5179
  " ",
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 })
5180
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5181
+ /* @__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
5182
  ] }, 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
5183
+ (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
5184
+ (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
5185
  ] }) : null
4865
5186
  ] }, e.slug);
4866
5187
  }) : null
4867
5188
  ] }, g.hall);
4868
5189
  }),
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: [
5190
+ visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: 4 }, children: [
5191
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
4871
5192
  grownOpen ? "▾" : "▸",
4872
5193
  " 自生长未注册 · 共 ",
4873
5194
  visibleGrown.length
4874
5195
  ] }),
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)(
5196
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
5197
+ 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: [
5198
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4878
5199
  "span",
4879
5200
  {
4880
5201
  style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
@@ -4885,8 +5206,8 @@ var __defProp = Object.defineProperty;
4885
5206
  children: r.room + " · " + r.count
4886
5207
  }
4887
5208
  ),
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)(
5209
+ /* @__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: "收编" }),
5210
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4890
5211
  "button",
4891
5212
  {
4892
5213
  type: "button",
@@ -4913,8 +5234,8 @@ var __defProp = Object.defineProperty;
4913
5234
  }
4914
5235
 
4915
5236
  // client/src/tabs/RoomTab.tsx
4916
- var import_react19 = require("react");
4917
- var import_jsx_runtime19 = require("react/jsx-runtime");
5237
+ var import_react20 = require("react");
5238
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4918
5239
  var btn2 = {
4919
5240
  cursor: "pointer",
4920
5241
  fontSize: 12,
@@ -4935,22 +5256,22 @@ var __defProp = Object.defineProperty;
4935
5256
  }
4936
5257
  function RoomTab(props) {
4937
5258
  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)(() => {
5259
+ const [registry, setRegistry] = (0, import_react20.useState)([]);
5260
+ const [counts, setCounts] = (0, import_react20.useState)([]);
5261
+ const [orphanCount, setOrphanCount] = (0, import_react20.useState)(0);
5262
+ const [busy, setBusy] = (0, import_react20.useState)(false);
5263
+ const [msg, setMsg] = (0, import_react20.useState)(null);
5264
+ const [error, setError] = (0, import_react20.useState)(null);
5265
+ const [hiPriv, setHiPriv] = (0, import_react20.useState)(false);
5266
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react20.useState)(false);
5267
+ const [reg, setReg] = (0, import_react20.useState)({ slug: "", label: "", description: "" });
5268
+ const [editing, setEditing] = (0, import_react20.useState)(null);
5269
+ const [renaming, setRenaming] = (0, import_react20.useState)(null);
5270
+ const [expanded, setExpanded] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
5271
+ const [retiredFilter, setRetiredFilter] = (0, import_react20.useState)("");
5272
+ const [filter, setFilter] = (0, import_react20.useState)("");
5273
+ const [records, setRecords] = (0, import_react20.useState)({});
5274
+ const loadAll = (0, import_react20.useCallback)(() => {
4954
5275
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4955
5276
  if (r && r.ok) {
4956
5277
  setCounts(r.value.rooms ?? []);
@@ -4959,13 +5280,13 @@ var __defProp = Object.defineProperty;
4959
5280
  }
4960
5281
  }).catch(() => void 0);
4961
5282
  }, [rpc]);
4962
- const loadHiPriv = (0, import_react19.useCallback)(() => {
5283
+ const loadHiPriv = (0, import_react20.useCallback)(() => {
4963
5284
  rpc("dsh-memory/settings-get", {}).then((r) => {
4964
5285
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4965
5286
  }).catch(() => {
4966
5287
  });
4967
5288
  }, [rpc]);
4968
- (0, import_react19.useEffect)(() => {
5289
+ (0, import_react20.useEffect)(() => {
4969
5290
  loadAll();
4970
5291
  loadHiPriv();
4971
5292
  }, [loadAll, loadHiPriv]);
@@ -5055,7 +5376,10 @@ var __defProp = Object.defineProperty;
5055
5376
  loadAll();
5056
5377
  if (expanded.has(slug)) {
5057
5378
  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 } }));
5379
+ if (rr && rr.ok) {
5380
+ registerTypeCatalog(rr.value.typeCatalog);
5381
+ setRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
5382
+ }
5059
5383
  }
5060
5384
  } else setError(r && r.error ? r.error.message : "操作失败");
5061
5385
  });
@@ -5084,6 +5408,7 @@ var __defProp = Object.defineProperty;
5084
5408
  }
5085
5409
  const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
5086
5410
  if (r && r.ok) {
5411
+ registerTypeCatalog(r.value.typeCatalog);
5087
5412
  const next = new Set(expanded);
5088
5413
  next.add(slug);
5089
5414
  setExpanded(next);
@@ -5103,11 +5428,11 @@ var __defProp = Object.defineProperty;
5103
5428
  const visibleRows = normFilter ? rows.filter(
5104
5429
  (row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
5105
5430
  ) : 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 () => {
5431
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5432
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
5433
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
5434
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5435
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5111
5436
  const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
5112
5437
  if (!r.ok) {
5113
5438
  setError(r.error.message);
@@ -5118,7 +5443,7 @@ var __defProp = Object.defineProperty;
5118
5443
  "导出孤儿 · ",
5119
5444
  orphanCount
5120
5445
  ] }),
5121
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5446
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5122
5447
  "button",
5123
5448
  {
5124
5449
  type: "button",
@@ -5129,35 +5454,35 @@ var __defProp = Object.defineProperty;
5129
5454
  children: hiPriv ? "高权限:开" : "高权限:关"
5130
5455
  }
5131
5456
  ),
5132
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5457
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5133
5458
  ] }),
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: [
5459
+ 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: [
5460
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5136
5461
  "编辑 ",
5137
5462
  editing.slug
5138
5463
  ] }),
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: "取消" })
5464
+ /* @__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 } }),
5465
+ /* @__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 } }),
5466
+ /* @__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: "保存" }),
5467
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5143
5468
  ] }) : 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: [
5469
+ 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: [
5470
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5146
5471
  "改名 ",
5147
5472
  renaming.slug,
5148
5473
  " →"
5149
5474
  ] }),
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: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5475
+ /* @__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 } }),
5476
+ /* @__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: "预览" }),
5477
+ /* @__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: "确认执行" }),
5478
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
5479
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5155
5480
  ] }) : 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: "退场筛选" }),
5481
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
5482
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "退场筛选" }),
5158
5483
  [["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
5159
5484
  const on = retiredFilter === val;
5160
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5485
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5161
5486
  "button",
5162
5487
  {
5163
5488
  type: "button",
@@ -5177,8 +5502,8 @@ var __defProp = Object.defineProperty;
5177
5502
  val
5178
5503
  );
5179
5504
  }),
5180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5181
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5505
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5506
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5182
5507
  "input",
5183
5508
  {
5184
5509
  value: filter,
@@ -5187,24 +5512,24 @@ var __defProp = Object.defineProperty;
5187
5512
  style: { ...S.input, width: 230, fontSize: 12 }
5188
5513
  }
5189
5514
  ),
5190
- filter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5515
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5191
5516
  ] }),
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: "管理操作需先开启高权限模式" })
5517
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5518
+ /* @__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 } }),
5519
+ /* @__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 } }),
5520
+ /* @__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 } }),
5521
+ /* @__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: "注册" }),
5522
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5198
5523
  ] }),
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) => {
5524
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.hint, children: msg }) : null,
5525
+ error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5526
+ 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
5527
  const e = row2.entry;
5203
5528
  const retired = e?.status === "retired";
5204
5529
  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)(
5530
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
5531
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
5532
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5208
5533
  "button",
5209
5534
  {
5210
5535
  type: "button",
@@ -5214,28 +5539,28 @@ var __defProp = Object.defineProperty;
5214
5539
  children: expanded.has(row2.slug) ? "▾" : "▸"
5215
5540
  }
5216
5541
  ),
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: [
5542
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5543
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
5219
5544
  row2.slug,
5220
5545
  e?.source === "pre-registered" ? " ⭐" : ""
5221
5546
  ] }),
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
5547
+ e?.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: e.label }) : null,
5548
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
5549
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
5550
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5551
+ (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
5227
5552
  ] }),
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: () => {
5553
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5554
+ !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5555
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5231
5556
  setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
5232
5557
  setRenaming(null);
5233
5558
  }, style: btn2, children: "编辑" }),
5234
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5559
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5235
5560
  setRenaming({ slug: row2.slug, to: "" });
5236
5561
  setEditing(null);
5237
5562
  }, style: btn2, children: "改名" }),
5238
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5563
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5239
5564
  "button",
5240
5565
  {
5241
5566
  type: "button",
@@ -5246,29 +5571,29 @@ var __defProp = Object.defineProperty;
5246
5571
  children: retired ? "恢复" : "退役"
5247
5572
  }
5248
5573
  ),
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
5574
+ !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
5575
  ] }),
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: () => {
5576
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5577
+ /* @__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: "收编" }),
5578
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
5254
5579
  setRenaming(null);
5255
5580
  retire(row2.slug, false, true);
5256
5581
  }, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
5257
5582
  ] }) : null,
5258
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5583
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5259
5584
  ] })
5260
5585
  ] }),
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 }),
5586
+ 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: [
5587
+ (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: [
5588
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5264
5589
  " ",
5265
- it.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5590
+ it.retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5266
5591
  " ",
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 })
5592
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5593
+ /* @__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
5594
  ] }, 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
5595
+ (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
5596
+ (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
5597
  ] }) : null
5273
5598
  ] }, row2.slug);
5274
5599
  })
@@ -5276,13 +5601,13 @@ var __defProp = Object.defineProperty;
5276
5601
  }
5277
5602
 
5278
5603
  // client/src/tabs/ScenesTab.tsx
5279
- var import_react20 = require("react");
5280
- var import_jsx_runtime20 = require("react/jsx-runtime");
5604
+ var import_react21 = require("react");
5605
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5281
5606
  function SceneCard(props) {
5282
5607
  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)(
5608
+ const [open, setOpen] = (0, import_react21.useState)(false);
5609
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
5610
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5286
5611
  "div",
5287
5612
  {
5288
5613
  style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
@@ -5290,23 +5615,23 @@ var __defProp = Object.defineProperty;
5290
5615
  setOpen(!open);
5291
5616
  },
5292
5617
  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) })
5618
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
5619
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.sceneTitle, children: s.path }),
5620
+ s.heat ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
5621
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5622
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
5298
5623
  ]
5299
5624
  }
5300
5625
  ),
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
5626
+ s.summary ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
5627
+ open ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
5303
5628
  ] });
5304
5629
  }
5305
5630
  function ScenesTab(props) {
5306
5631
  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)(() => {
5632
+ const [items, setItems] = (0, import_react21.useState)(null);
5633
+ const [error, setError] = (0, import_react21.useState)(null);
5634
+ const load = (0, import_react21.useCallback)(() => {
5310
5635
  rpc("dsh-memory/scenes", {}).then((r) => {
5311
5636
  if (r && r.ok) {
5312
5637
  setItems(r.value.items);
@@ -5316,25 +5641,25 @@ var __defProp = Object.defineProperty;
5316
5641
  setError(String(e && e.message || e));
5317
5642
  });
5318
5643
  }, [rpc]);
5319
- (0, import_react20.useEffect)(() => {
5644
+ (0, import_react21.useEffect)(() => {
5320
5645
  load();
5321
5646
  }, [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: "刷新" })
5647
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
5648
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
5649
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
5650
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5651
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(NButton, { onClick: load, children: "刷新" })
5327
5652
  ] }),
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,
5653
+ error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.error, children: error }) : null,
5654
+ items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
5330
5655
  (items || []).map((s) => {
5331
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SceneCard, { s }, s.path);
5656
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SceneCard, { s }, s.path);
5332
5657
  })
5333
5658
  ] });
5334
5659
  }
5335
5660
 
5336
5661
  // client/src/panel.tsx
5337
- var import_jsx_runtime21 = require("react/jsx-runtime");
5662
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5338
5663
  var TABS = [
5339
5664
  ["overview", "概览"],
5340
5665
  ["records", "记忆"],
@@ -5355,10 +5680,10 @@ var __defProp = Object.defineProperty;
5355
5680
  ];
5356
5681
  function MemoryPanel(props) {
5357
5682
  const rpc = props.rpc;
5358
- const [tab, setTab] = (0, import_react21.useState)("overview");
5359
- const [skin, setSkinState] = (0, import_react21.useState)(() => getSkin());
5683
+ const [tab, setTab] = (0, import_react22.useState)("overview");
5684
+ const [skin, setSkinState] = (0, import_react22.useState)(() => getSkin());
5360
5685
  ensureThemeStyle(skin);
5361
- (0, import_react21.useEffect)(() => {
5686
+ (0, import_react22.useEffect)(() => {
5362
5687
  applySkin(skin);
5363
5688
  watchSidebarIcon();
5364
5689
  }, [skin]);
@@ -5367,21 +5692,21 @@ var __defProp = Object.defineProperty;
5367
5692
  setSkinState(next);
5368
5693
  };
5369
5694
  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)(
5695
+ if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(OverviewTab, { rpc });
5696
+ else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RecordsTab, { rpc });
5697
+ else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConflictsTab, { rpc });
5698
+ else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenesTab, { rpc });
5699
+ else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomsTab, { rpc });
5700
+ else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomTab, { rpc });
5701
+ else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PersonaTab, { rpc });
5702
+ else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CostTab, { rpc });
5703
+ else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConnectTab, { rpc });
5704
+ else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SkillsTab, { rpc });
5705
+ else body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LogTab, { rpc });
5706
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
5707
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
5708
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
5709
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5385
5710
  "div",
5386
5711
  {
5387
5712
  style: {
@@ -5393,8 +5718,8 @@ var __defProp = Object.defineProperty;
5393
5718
  marginBottom: 10
5394
5719
  },
5395
5720
  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)(
5721
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
5722
+ SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5398
5723
  "button",
5399
5724
  {
5400
5725
  className: skin === s[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5407,8 +5732,8 @@ var __defProp = Object.defineProperty;
5407
5732
  ]
5408
5733
  }
5409
5734
  ),
5410
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5411
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5735
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5736
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5412
5737
  "button",
5413
5738
  {
5414
5739
  className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5425,7 +5750,7 @@ var __defProp = Object.defineProperty;
5425
5750
  }
5426
5751
 
5427
5752
  // client/src/pill/MemoryModePill.tsx
5428
- var import_react25 = require("react");
5753
+ var import_react26 = require("react");
5429
5754
 
5430
5755
  // src/util/context-occupancy.ts
5431
5756
  var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
@@ -5450,8 +5775,8 @@ var __defProp = Object.defineProperty;
5450
5775
  var panelListeners = /* @__PURE__ */ new Set();
5451
5776
  var panelWasOpen = false;
5452
5777
  var snapshotListeners = /* @__PURE__ */ new Set();
5453
- function initOccupancyIndicator(call) {
5454
- statsCall = call;
5778
+ function initOccupancyIndicator(call2) {
5779
+ statsCall = call2;
5455
5780
  }
5456
5781
  function noteOccupancySession(sessionId) {
5457
5782
  if (sessionId === activeSessionId) return;
@@ -5741,23 +6066,23 @@ var __defProp = Object.defineProperty;
5741
6066
  }
5742
6067
 
5743
6068
  // client/src/pill/WingWheel.tsx
5744
- var import_react24 = require("react");
6069
+ var import_react25 = require("react");
5745
6070
 
5746
6071
  // client/src/pill/SessionInfoArea.tsx
5747
- var import_react22 = require("react");
5748
- var import_jsx_runtime22 = require("react/jsx-runtime");
6072
+ var import_react23 = require("react");
6073
+ var import_jsx_runtime23 = require("react/jsx-runtime");
5749
6074
  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 })
6075
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { title: title || void 0, children: [
6076
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
6077
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
5753
6078
  ] });
5754
6079
  }
5755
6080
  function SessionInfoArea(props) {
5756
6081
  const rpc = props.rpc;
5757
6082
  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)(() => {
6083
+ const [stats, setStats] = (0, import_react23.useState)(void 0);
6084
+ const busyRef = (0, import_react23.useRef)(false);
6085
+ (0, import_react23.useEffect)(() => {
5761
6086
  if (!rpc || !sessionId) return void 0;
5762
6087
  let alive = true;
5763
6088
  let timer = null;
@@ -5790,7 +6115,7 @@ var __defProp = Object.defineProperty;
5790
6115
  }, [rpc, sessionId]);
5791
6116
  if (stats === null) return null;
5792
6117
  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: [
6118
+ 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
6119
  sinfoCell("…", "召回命中"),
5795
6120
  sinfoCell("…", "攒批进度"),
5796
6121
  sinfoCell("…", "本会话记忆"),
@@ -5839,30 +6164,30 @@ var __defProp = Object.defineProperty;
5839
6164
  else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
5840
6165
  }
5841
6166
  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: [
6167
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6168
+ warn ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
6169
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
5845
6170
  sinfoCell(rcVal, rcLabel, rcTitle),
5846
6171
  sinfoCell(dVal, dLabel, dTitle),
5847
6172
  sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
5848
6173
  sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
5849
6174
  ] }),
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 || "尚未蒸馏") })
6175
+ note ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
6176
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
5852
6177
  ] });
5853
6178
  }
5854
6179
 
5855
6180
  // client/src/pill/SessionRecalledArea.tsx
5856
- var import_react23 = require("react");
5857
- var import_jsx_runtime23 = require("react/jsx-runtime");
6181
+ var import_react24 = require("react");
6182
+ var import_jsx_runtime24 = require("react/jsx-runtime");
5858
6183
  var SHOW_CAP = 6;
5859
6184
  var POLL_MS2 = 4e3;
5860
6185
  var MATURITY_LABEL = { high: "成熟·高", mid: "成熟·中", low: "成熟·低" };
5861
6186
  function SessionRecalledArea(props) {
5862
6187
  const rpc = props.rpc;
5863
6188
  const sessionId = props.sessionId;
5864
- const [records, setRecords] = (0, import_react23.useState)(void 0);
5865
- (0, import_react23.useEffect)(() => {
6189
+ const [records, setRecords] = (0, import_react24.useState)(void 0);
6190
+ (0, import_react24.useEffect)(() => {
5866
6191
  if (!rpc || !sessionId) return void 0;
5867
6192
  let alive = true;
5868
6193
  let timer = null;
@@ -5871,7 +6196,10 @@ var __defProp = Object.defineProperty;
5871
6196
  const token = ++seq;
5872
6197
  rpc("dsh-memory/session-recalled", { sessionId }).then((r) => {
5873
6198
  if (!alive || token !== seq) return;
5874
- if (r && r.ok && r.value) setRecords(r.value.records);
6199
+ if (r && r.ok && r.value) {
6200
+ registerTypeCatalog(r.value.typeCatalog);
6201
+ setRecords(r.value.records);
6202
+ }
5875
6203
  }).catch(() => {
5876
6204
  }).then(() => {
5877
6205
  if (alive) timer = setTimeout(tick, POLL_MS2);
@@ -5884,32 +6212,38 @@ var __defProp = Object.defineProperty;
5884
6212
  };
5885
6213
  }, [rpc, sessionId]);
5886
6214
  if (records === void 0) return null;
5887
- const recentFirst = [...records].reverse();
6215
+ const rows = records.filter((r) => r.superseded !== true || r.retired === true);
6216
+ const recentFirst = [...rows].reverse();
5888
6217
  const shown = recentFirst.slice(0, SHOW_CAP);
5889
6218
  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)(
6219
+ const allSuperseded = rows.length === 0 && records.length > 0;
6220
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6221
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5892
6222
  "div",
5893
6223
  {
5894
6224
  style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 6 },
5895
- title: "本会话召回注入、且目前仍在上下文里的记忆(压缩/清空后自动消失,不是常驻)",
5896
- children: "本会话召回 " + records.length + " 条"
6225
+ title: "本会话召回、且正文仍在上下文里的记忆(正文被摘要顶掉的已折叠不显示;清空会话才清除;不是常驻注入)",
6226
+ children: "本会话召回 " + rows.length + " 条"
5897
6227
  }
5898
6228
  ),
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)(
6229
+ allSuperseded ? (
6230
+ // 不是“还没召回到”——那批确实注入过,只是正文已被摘要顶掉。说谎的空态比不显示更糟。
6231
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", lineHeight: "16px" }, children: "本会话注入过的 " + records.length + " 条记忆正文已被摘要取代" })
6232
+ ) : 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: [
6233
+ shown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: rowStyle, title: rowTitle(r), children: [
6234
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5902
6235
  "span",
5903
6236
  {
5904
- className: "dsh-mem-tag dsh-mem-tag-" + r.type,
6237
+ className: tagClass(r.type),
5905
6238
  style: { flexShrink: 0, whiteSpace: "nowrap" },
5906
- children: TYPE_LABELS[r.type] || r.type
6239
+ children: typeLabel(r.type)
5907
6240
  }
5908
6241
  ),
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
6242
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "dsh-mem-sinfo-val", style: r.retired === true ? STALE_TEXT_STYLE : textStyle, children: r.content }),
6243
+ 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,
6244
+ 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
6245
  ] }, r.id)),
5912
- hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "+ " + hidden + " 条更早召回(详见面板「记忆」页)" }) : null
6246
+ hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "+ " + hidden + " 条更早召回(详见面板「记忆」页)" }) : null
5913
6247
  ] })
5914
6248
  ] });
5915
6249
  }
@@ -5929,14 +6263,15 @@ var __defProp = Object.defineProperty;
5929
6263
  WebkitBoxOrient: "vertical",
5930
6264
  overflow: "hidden"
5931
6265
  };
6266
+ var STALE_TEXT_STYLE = { ...textStyle, textDecoration: "line-through" };
5932
6267
  function rowTitle(r) {
5933
- const head = "[" + (TYPE_LABELS[r.type] || r.type) + "] " + r.content;
6268
+ const head = "[" + typeLabel(r.type) + "] " + r.content;
5934
6269
  const sc = r.usageScenario && r.usageScenario.length > 0 ? "\n使用场景:" + r.usageScenario.join(";") : "";
5935
6270
  return head + sc;
5936
6271
  }
5937
6272
 
5938
6273
  // client/src/pill/WingWheel.tsx
5939
- var import_jsx_runtime24 = require("react/jsx-runtime");
6274
+ var import_jsx_runtime25 = require("react/jsx-runtime");
5940
6275
  var SIZE = 196;
5941
6276
  var CENTER = SIZE / 2;
5942
6277
  var R = 64;
@@ -5979,17 +6314,17 @@ var __defProp = Object.defineProperty;
5979
6314
  function WingWheel(props) {
5980
6315
  ensureThemeStyle();
5981
6316
  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)(
6317
+ const [overview, setOverview] = (0, import_react25.useState)(null);
6318
+ const [backfillBusy, setBackfillBusy] = (0, import_react25.useState)(false);
6319
+ const [localError, setLocalError] = (0, import_react25.useState)(null);
6320
+ const timersRef = (0, import_react25.useRef)([]);
6321
+ (0, import_react25.useEffect)(
5987
6322
  () => () => {
5988
6323
  for (const t of timersRef.current) window.clearTimeout(t);
5989
6324
  },
5990
6325
  []
5991
6326
  );
5992
- (0, import_react24.useEffect)(() => {
6327
+ (0, import_react25.useEffect)(() => {
5993
6328
  let alive = true;
5994
6329
  props.rpc("dsh-memory/wing-overview", {}).then((r) => {
5995
6330
  if (!alive) return;
@@ -6035,28 +6370,28 @@ var __defProp = Object.defineProperty;
6035
6370
  finish();
6036
6371
  });
6037
6372
  };
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);
6373
+ const boxRef = (0, import_react25.useRef)(null);
6374
+ const startRef = (0, import_react25.useRef)(null);
6375
+ const movedRef = (0, import_react25.useRef)(false);
6376
+ const downIndexRef = (0, import_react25.useRef)(null);
6377
+ const dragTargetRef = (0, import_react25.useRef)(null);
6378
+ const [drag, setDrag] = (0, import_react25.useState)(null);
6044
6379
  const lockedIndex = (() => {
6045
6380
  if (props.halls.length !== 1 || !overview) return null;
6046
6381
  const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
6047
6382
  return i >= 0 ? i : null;
6048
6383
  })();
6049
6384
  const activeCorner = drag ? drag.index : lockedIndex;
6050
- const blockPosRef = (0, import_react24.useRef)(
6385
+ const blockPosRef = (0, import_react25.useRef)(
6051
6386
  activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
6052
6387
  );
6053
- const blockTargetRef = (0, import_react24.useRef)(blockPosRef.current);
6054
- const [blockPos, setBlockPos] = (0, import_react24.useState)(blockPosRef.current);
6055
- (0, import_react24.useEffect)(() => {
6388
+ const blockTargetRef = (0, import_react25.useRef)(blockPosRef.current);
6389
+ const [blockPos, setBlockPos] = (0, import_react25.useState)(blockPosRef.current);
6390
+ (0, import_react25.useEffect)(() => {
6056
6391
  blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
6057
6392
  }, [activeCorner]);
6058
- const reducedMotionRef = (0, import_react24.useRef)(false);
6059
- (0, import_react24.useEffect)(() => {
6393
+ const reducedMotionRef = (0, import_react25.useRef)(false);
6394
+ (0, import_react25.useEffect)(() => {
6060
6395
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
6061
6396
  const apply2 = () => {
6062
6397
  reducedMotionRef.current = mq.matches;
@@ -6065,7 +6400,7 @@ var __defProp = Object.defineProperty;
6065
6400
  mq.addEventListener("change", apply2);
6066
6401
  return () => mq.removeEventListener("change", apply2);
6067
6402
  }, []);
6068
- (0, import_react24.useEffect)(() => {
6403
+ (0, import_react25.useEffect)(() => {
6069
6404
  let raf = 0;
6070
6405
  const loop = () => {
6071
6406
  const cur = blockPosRef.current;
@@ -6154,8 +6489,8 @@ var __defProp = Object.defineProperty;
6154
6489
  }).join(" ");
6155
6490
  const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
6156
6491
  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)(
6492
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { width: SIZE }, children: [
6493
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6159
6494
  "div",
6160
6495
  {
6161
6496
  ref: boxRef,
@@ -6165,7 +6500,7 @@ var __defProp = Object.defineProperty;
6165
6500
  onPointerUp: onBoxUp,
6166
6501
  onPointerCancel: onBoxUp,
6167
6502
  children: [
6168
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6503
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6169
6504
  "svg",
6170
6505
  {
6171
6506
  width: SIZE,
@@ -6173,7 +6508,7 @@ var __defProp = Object.defineProperty;
6173
6508
  style: { position: "absolute", inset: 0, pointerEvents: "none" },
6174
6509
  "aria-hidden": "true",
6175
6510
  children: [
6176
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6511
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6177
6512
  "polygon",
6178
6513
  {
6179
6514
  points: polyPoints,
@@ -6184,7 +6519,7 @@ var __defProp = Object.defineProperty;
6184
6519
  opacity: 0.45
6185
6520
  }
6186
6521
  ),
6187
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6522
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6188
6523
  "polygon",
6189
6524
  {
6190
6525
  points: polyPoints,
@@ -6195,7 +6530,7 @@ var __defProp = Object.defineProperty;
6195
6530
  ),
6196
6531
  [0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
6197
6532
  const p = cornerPos(i);
6198
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6533
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6199
6534
  "line",
6200
6535
  {
6201
6536
  x1: CENTER,
@@ -6211,7 +6546,7 @@ var __defProp = Object.defineProperty;
6211
6546
  ]
6212
6547
  }
6213
6548
  ),
6214
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6549
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6215
6550
  "div",
6216
6551
  {
6217
6552
  "aria-hidden": "true",
@@ -6230,7 +6565,7 @@ var __defProp = Object.defineProperty;
6230
6565
  }
6231
6566
  }
6232
6567
  ),
6233
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6568
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6234
6569
  "button",
6235
6570
  {
6236
6571
  type: "button",
@@ -6264,7 +6599,7 @@ var __defProp = Object.defineProperty;
6264
6599
  const dim = activeCorner != null && !active;
6265
6600
  const empty = count === 0;
6266
6601
  const p = cornerPos(i);
6267
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6602
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6268
6603
  "div",
6269
6604
  {
6270
6605
  title: id ? `「${label}」${count ?? 0} 条
@@ -6293,8 +6628,8 @@ var __defProp = Object.defineProperty;
6293
6628
  zIndex: 2
6294
6629
  },
6295
6630
  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} 条` })
6631
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }),
6632
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
6298
6633
  ]
6299
6634
  },
6300
6635
  id ?? i
@@ -6303,7 +6638,7 @@ var __defProp = Object.defineProperty;
6303
6638
  ]
6304
6639
  }
6305
6640
  ),
6306
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6641
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6307
6642
  "div",
6308
6643
  {
6309
6644
  title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
@@ -6317,9 +6652,9 @@ var __defProp = Object.defineProperty;
6317
6652
  pointerEvents: boundariesDisabled ? "none" : void 0
6318
6653
  },
6319
6654
  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)(
6655
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
6656
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
6657
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6323
6658
  Segmented,
6324
6659
  {
6325
6660
  value: props.hallIncludeUnlabeled ? "in" : "ex",
@@ -6330,7 +6665,7 @@ var __defProp = Object.defineProperty;
6330
6665
  onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
6331
6666
  }
6332
6667
  ),
6333
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6668
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6334
6669
  Segmented,
6335
6670
  {
6336
6671
  value: props.hallIncludeGeneral ? "in" : "ex",
@@ -6345,7 +6680,7 @@ var __defProp = Object.defineProperty;
6345
6680
  ]
6346
6681
  }
6347
6682
  ),
6348
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6683
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6349
6684
  Segmented,
6350
6685
  {
6351
6686
  value: isOff ? "off" : "on",
@@ -6360,7 +6695,7 @@ var __defProp = Object.defineProperty;
6360
6695
  onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
6361
6696
  }
6362
6697
  ) }),
6363
- props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6698
+ props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6364
6699
  Segmented,
6365
6700
  {
6366
6701
  value: props.recall === null ? "follow" : props.recall ? "on" : "off",
@@ -6373,7 +6708,7 @@ var __defProp = Object.defineProperty;
6373
6708
  onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
6374
6709
  }
6375
6710
  ) }) : null,
6376
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6711
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6377
6712
  "div",
6378
6713
  {
6379
6714
  style: {
@@ -6384,8 +6719,8 @@ var __defProp = Object.defineProperty;
6384
6719
  marginTop: 10
6385
6720
  },
6386
6721
  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)(
6722
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
6723
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6389
6724
  ActionButton,
6390
6725
  {
6391
6726
  label: backfillBusy ? "回填中…" : "回填",
@@ -6397,13 +6732,13 @@ var __defProp = Object.defineProperty;
6397
6732
  ]
6398
6733
  }
6399
6734
  ),
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 })
6735
+ 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,
6736
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionRecalledArea, { rpc: props.rpc, sessionId: props.sessionId }),
6737
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
6403
6738
  ] });
6404
6739
  }
6405
6740
  function Row(props) {
6406
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6741
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6407
6742
  "div",
6408
6743
  {
6409
6744
  style: {
@@ -6413,7 +6748,7 @@ var __defProp = Object.defineProperty;
6413
6748
  marginTop: 10
6414
6749
  },
6415
6750
  children: [
6416
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6751
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6417
6752
  props.children
6418
6753
  ]
6419
6754
  }
@@ -6421,9 +6756,9 @@ var __defProp = Object.defineProperty;
6421
6756
  }
6422
6757
  var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
6423
6758
  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)(() => {
6759
+ const shiftRef = (0, import_react25.useRef)(0);
6760
+ const [shiftX, setShiftX] = (0, import_react25.useState)(0);
6761
+ (0, import_react25.useEffect)(() => {
6427
6762
  const clamp = () => {
6428
6763
  const el = popRef.current;
6429
6764
  if (!el) return;
@@ -6453,24 +6788,24 @@ var __defProp = Object.defineProperty;
6453
6788
  }
6454
6789
 
6455
6790
  // client/src/pill/MemoryModePill.tsx
6456
- var import_jsx_runtime25 = require("react/jsx-runtime");
6791
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6457
6792
  function MemoryModePill(props) {
6458
6793
  const rpc = props.rpc;
6459
6794
  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);
6795
+ const [mode, setMode] = (0, import_react26.useState)(null);
6796
+ const [recall, setRecall] = (0, import_react26.useState)(null);
6797
+ const [recallResolved, setRecallResolved] = (0, import_react26.useState)(true);
6798
+ const [halls, setWings] = (0, import_react26.useState)([]);
6799
+ const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react26.useState)(true);
6800
+ const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react26.useState)(false);
6801
+ const [wingLabels, setHallLabels] = (0, import_react26.useState)({});
6802
+ const [error, setError] = (0, import_react26.useState)(null);
6803
+ const [open, setOpen] = (0, import_react26.useState)(false);
6804
+ const wrapRef = (0, import_react26.useRef)(null);
6805
+ const popRef = (0, import_react26.useRef)(null);
6471
6806
  const shiftX = useViewportClamp(popRef);
6472
- const seqRef = (0, import_react25.useRef)(0);
6473
- const load = (0, import_react25.useCallback)(() => {
6807
+ const seqRef = (0, import_react26.useRef)(0);
6808
+ const load = (0, import_react26.useCallback)(() => {
6474
6809
  if (!sessionId || !rpc) return;
6475
6810
  const token = ++seqRef.current;
6476
6811
  setError(null);
@@ -6495,13 +6830,13 @@ var __defProp = Object.defineProperty;
6495
6830
  }).catch(() => {
6496
6831
  });
6497
6832
  }, [sessionId, rpc]);
6498
- (0, import_react25.useEffect)(() => {
6833
+ (0, import_react26.useEffect)(() => {
6499
6834
  load();
6500
6835
  }, [load]);
6501
- (0, import_react25.useEffect)(() => {
6836
+ (0, import_react26.useEffect)(() => {
6502
6837
  watchSidebarIcon();
6503
6838
  }, []);
6504
- (0, import_react25.useEffect)(() => {
6839
+ (0, import_react26.useEffect)(() => {
6505
6840
  initOccupancyIndicator(
6506
6841
  (endpoint, payload) => rpc(endpoint, payload)
6507
6842
  );
@@ -6509,7 +6844,7 @@ var __defProp = Object.defineProperty;
6509
6844
  watchContextMeter();
6510
6845
  noteOccupancySession(sessionId ?? null);
6511
6846
  }, [sessionId, rpc]);
6512
- (0, import_react25.useEffect)(() => {
6847
+ (0, import_react26.useEffect)(() => {
6513
6848
  if (!open) return;
6514
6849
  const onDown = (e) => {
6515
6850
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -6649,8 +6984,8 @@ var __defProp = Object.defineProperty;
6649
6984
  pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
6650
6985
  pillStyle["--dsh-mem-pill-tint"] = info.color;
6651
6986
  }
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)(
6987
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
6988
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6654
6989
  "button",
6655
6990
  {
6656
6991
  type: "button",
@@ -6663,11 +6998,11 @@ var __defProp = Object.defineProperty;
6663
6998
  style: pillStyle,
6664
6999
  children: [
6665
7000
  "记忆 · ",
6666
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: faceLabel })
7001
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: faceLabel })
6667
7002
  ]
6668
7003
  }
6669
7004
  ),
6670
- open ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7005
+ open ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6671
7006
  "div",
6672
7007
  {
6673
7008
  ref: popRef,
@@ -6678,12 +7013,12 @@ var __defProp = Object.defineProperty;
6678
7013
  transform: "translateX(calc(-50% + " + shiftX + "px))",
6679
7014
  zIndex: 1e3
6680
7015
  },
6681
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7016
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6682
7017
  "div",
6683
7018
  {
6684
7019
  className: "dsh-mem-popover",
6685
7020
  style: { position: "relative", padding: "10px 12px" },
6686
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7021
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6687
7022
  WingWheel,
6688
7023
  {
6689
7024
  mode: mode || "auto",