dsh-prime-memory 0.25.0 → 0.26.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.
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_react22 = require("react");
35
+ var import_react24 = 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>';
@@ -1243,29 +1243,6 @@ var __defProp = Object.defineProperty;
1243
1243
  ] })
1244
1244
  ] });
1245
1245
  }
1246
- function ActionButton(props) {
1247
- const disabled = !!props.disabled;
1248
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1249
- "button",
1250
- {
1251
- type: "button",
1252
- title: props.disabled ? "" : props.title || "",
1253
- "aria-disabled": disabled,
1254
- onClick: () => {
1255
- if (!disabled && props.onClick) props.onClick();
1256
- },
1257
- style: {
1258
- ...S.seg,
1259
- ...S.segBtn,
1260
- fontFamily: "inherit",
1261
- border: "1px solid var(--dsh-mem-border)",
1262
- cursor: disabled ? "not-allowed" : "pointer",
1263
- ...disabled ? S.switchDisabled : null
1264
- },
1265
- children: props.label
1266
- }
1267
- );
1268
- }
1269
1246
  function Segmented(props) {
1270
1247
  const value = props.value;
1271
1248
  const disabled = !!props.disabled;
@@ -1637,7 +1614,7 @@ var __defProp = Object.defineProperty;
1637
1614
  }
1638
1615
 
1639
1616
  // client/src/tabs/OverviewTab.tsx
1640
- var import_react16 = require("react");
1617
+ var import_react17 = require("react");
1641
1618
 
1642
1619
  // client/src/pill/modes.ts
1643
1620
  var MODES = [
@@ -3715,14 +3692,284 @@ var __defProp = Object.defineProperty;
3715
3692
  ] });
3716
3693
  }
3717
3694
 
3718
- // client/src/tabs/OverviewTab.tsx
3695
+ // client/src/tabs/BackfillSection.tsx
3696
+ var import_react16 = require("react");
3719
3697
  var import_jsx_runtime16 = require("react/jsx-runtime");
3698
+ function BackfillSection(props) {
3699
+ const rpc = props.rpc;
3700
+ const [overview, setOverview] = (0, import_react16.useState)(null);
3701
+ const [wingBusy, setWingBusy] = (0, import_react16.useState)(false);
3702
+ const [kwBusy, setKwBusy] = (0, import_react16.useState)(false);
3703
+ const [kwSummary, setKwSummary] = (0, import_react16.useState)(null);
3704
+ const [kwProgress, setKwProgress] = (0, import_react16.useState)(null);
3705
+ const [kwCounts, setKwCounts] = (0, import_react16.useState)(null);
3706
+ const [rdBusy, setRdBusy] = (0, import_react16.useState)(false);
3707
+ const [rdSummary, setRdSummary] = (0, import_react16.useState)(null);
3708
+ const [rdProgress, setRdProgress] = (0, import_react16.useState)(null);
3709
+ const [rdCounts, setRdCounts] = (0, import_react16.useState)(null);
3710
+ const [err, setErr] = (0, import_react16.useState)(null);
3711
+ const timersRef = (0, import_react16.useRef)([]);
3712
+ (0, import_react16.useEffect)(
3713
+ () => () => {
3714
+ for (const t of timersRef.current) window.clearTimeout(t);
3715
+ },
3716
+ []
3717
+ );
3718
+ const refreshOverview = (0, import_react16.useCallback)(() => {
3719
+ rpc("dsh-memory/wing-overview", {}).then((r) => {
3720
+ if (r && r.ok) setOverview(r.value);
3721
+ }).catch(() => {
3722
+ });
3723
+ }, [rpc]);
3724
+ (0, import_react16.useEffect)(() => {
3725
+ refreshOverview();
3726
+ }, [refreshOverview]);
3727
+ ensureThemeStyle();
3728
+ const POLL_CAP = 400;
3729
+ const fmtProgress = (p, verb, counts) => {
3730
+ if (!p) return `${verb}中…`;
3731
+ if (p.scanning || p.candidates === 0) return `${verb}中:正在扫描存量、筛出需${verb}的记录…`;
3732
+ const parts = [
3733
+ `${verb}中:真目标 ${p.candidates} 条`,
3734
+ `已完成 ${p.processed} 条`,
3735
+ p.batchTotal > 0 ? `第 ${Math.min(p.batchesDone + 1, p.batchTotal)}/${p.batchTotal} 条` : "",
3736
+ p.concurrency > 1 ? `并行 ${p.concurrency}` : "串行",
3737
+ (counts?.failed ?? 0) > 0 ? `失败 ${counts.failed} 条` : ""
3738
+ ].filter(Boolean);
3739
+ const outcome = counts ? `(写回 ${counts.updated ?? 0}${counts.skipped !== void 0 ? ` / 留原文 ${counts.skipped}` : ""})` : "";
3740
+ return parts.join(" · ") + outcome;
3741
+ };
3742
+ const tail = (p) => p && p.deferred > 0 ? `,本次未跑完、剩 ${p.deferred} 条待再点一次` : "";
3743
+ const wingBackfill = (mode = "start") => {
3744
+ if (wingBusy) return;
3745
+ if (mode === "start" && (!overview || overview.unlabeled === 0)) return;
3746
+ if (mode === "start") setWingBusy(true);
3747
+ setErr(null);
3748
+ let polls = 0;
3749
+ const finish = () => setWingBusy(false);
3750
+ const tick = () => {
3751
+ polls++;
3752
+ rpc("dsh-memory/wing-overview", {}).then((r) => {
3753
+ const v = r && r.ok ? r.value : null;
3754
+ if (v) setOverview(v);
3755
+ if (v && v.unlabeled === 0 || polls >= POLL_CAP) finish();
3756
+ else timersRef.current.push(window.setTimeout(tick, 3e3));
3757
+ }).catch(() => finish());
3758
+ };
3759
+ rpc("dsh-memory/wing-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3760
+ if (!r || !r.ok) {
3761
+ if (mode === "resume") return finish();
3762
+ setErr(r && r.error ? "回填失败:" + r.error.message : "回填失败");
3763
+ finish();
3764
+ return;
3765
+ }
3766
+ if (mode === "resume") {
3767
+ if (!(r.value && r.value.running)) return;
3768
+ setWingBusy(true);
3769
+ }
3770
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3771
+ }).catch((e) => {
3772
+ if (mode === "resume") return finish();
3773
+ setErr("回填失败:" + String(e && e.message || e));
3774
+ finish();
3775
+ });
3776
+ };
3777
+ const keywordBackfill = (mode = "start") => {
3778
+ if (kwBusy) return;
3779
+ if (mode === "start") {
3780
+ setKwBusy(true);
3781
+ setKwSummary(null);
3782
+ setKwProgress(null);
3783
+ setKwCounts(null);
3784
+ }
3785
+ setErr(null);
3786
+ let polls = 0;
3787
+ let last = null;
3788
+ const finish = () => setKwBusy(false);
3789
+ const showResult = (v) => {
3790
+ const fail = v.failed ?? 0;
3791
+ setKwSummary(`关键词回填完成:成功 ${v.updated ?? 0} 条${fail > 0 ? `,失败 ${fail} 条` : ""}${tail(last)}`);
3792
+ };
3793
+ const failMsg = (m) => {
3794
+ setErr(m);
3795
+ finish();
3796
+ };
3797
+ const tick = () => {
3798
+ polls++;
3799
+ rpc("dsh-memory/keyword-backfill", {}).then((r) => {
3800
+ const v = r && r.ok ? r.value : null;
3801
+ if (!v) return failMsg("关键词回填失败");
3802
+ if (v.progress) {
3803
+ last = v.progress;
3804
+ setKwProgress(v.progress);
3805
+ setKwCounts({ updated: v.updated, failed: v.failed });
3806
+ }
3807
+ if (v.running) {
3808
+ if (polls >= POLL_CAP) {
3809
+ showResult(v);
3810
+ return finish();
3811
+ }
3812
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3813
+ return;
3814
+ }
3815
+ if (v.enabled) showResult(v);
3816
+ finish();
3817
+ }).catch(() => failMsg("关键词回填失败"));
3818
+ };
3819
+ rpc("dsh-memory/keyword-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3820
+ if (!r || !r.ok) {
3821
+ if (mode === "resume") return;
3822
+ return failMsg(r && r.error ? "关键词回填失败:" + r.error.message : "关键词回填失败");
3823
+ }
3824
+ const v = r.value;
3825
+ if (!v) {
3826
+ if (mode === "resume") return;
3827
+ return failMsg("关键词回填失败");
3828
+ }
3829
+ if (mode === "resume") {
3830
+ if (!v.running) return;
3831
+ if (v.progress) {
3832
+ last = v.progress;
3833
+ setKwProgress(v.progress);
3834
+ setKwCounts({ updated: v.updated, failed: v.failed });
3835
+ }
3836
+ setKwBusy(true);
3837
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3838
+ return;
3839
+ }
3840
+ if (!v.enabled) return failMsg("关键词回填未开启:请先在概览开关组打开关键词回填");
3841
+ if (v.progress) {
3842
+ last = v.progress;
3843
+ setKwProgress(v.progress);
3844
+ setKwCounts({ updated: v.updated, failed: v.failed });
3845
+ }
3846
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3847
+ }).catch((e) => {
3848
+ if (mode === "resume") return;
3849
+ failMsg("关键词回填失败:" + String(e && e.message || e));
3850
+ });
3851
+ };
3852
+ const redistillBackfill = (mode = "start") => {
3853
+ if (rdBusy) return;
3854
+ if (mode === "start") {
3855
+ setRdBusy(true);
3856
+ setRdSummary(null);
3857
+ setRdProgress(null);
3858
+ setRdCounts(null);
3859
+ }
3860
+ setErr(null);
3861
+ let polls = 0;
3862
+ let last = null;
3863
+ const finish = () => setRdBusy(false);
3864
+ const showResult = (v) => {
3865
+ setRdSummary(`整形完成:写回 ${v.updated ?? 0} 条,留原文 ${v.skipped ?? 0} 条${(v.failed ?? 0) > 0 ? `,失败 ${v.failed} 条` : ""}${tail(last)}`);
3866
+ };
3867
+ const failMsg = (m) => {
3868
+ setErr(m);
3869
+ finish();
3870
+ };
3871
+ const tick = () => {
3872
+ polls++;
3873
+ rpc("dsh-memory/redistill-backfill", {}).then((r) => {
3874
+ const v = r && r.ok ? r.value : null;
3875
+ if (!v) return failMsg("重蒸馏整形失败");
3876
+ if (v.progress) {
3877
+ last = v.progress;
3878
+ setRdProgress(v.progress);
3879
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3880
+ }
3881
+ if (v.running) {
3882
+ if (polls >= POLL_CAP) {
3883
+ showResult(v);
3884
+ return finish();
3885
+ }
3886
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3887
+ return;
3888
+ }
3889
+ if (v.enabled) showResult(v);
3890
+ finish();
3891
+ }).catch(() => failMsg("重蒸馏整形失败"));
3892
+ };
3893
+ rpc("dsh-memory/redistill-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3894
+ if (!r || !r.ok) {
3895
+ if (mode === "resume") return;
3896
+ return failMsg(r && r.error ? "重蒸馏整形失败:" + r.error.message : "重蒸馏整形失败");
3897
+ }
3898
+ const v = r.value;
3899
+ if (!v) {
3900
+ if (mode === "resume") return;
3901
+ return failMsg("重蒸馏整形失败");
3902
+ }
3903
+ if (mode === "resume") {
3904
+ if (!v.running) return;
3905
+ if (v.progress) {
3906
+ last = v.progress;
3907
+ setRdProgress(v.progress);
3908
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3909
+ }
3910
+ setRdBusy(true);
3911
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3912
+ return;
3913
+ }
3914
+ if (!v.enabled) return failMsg("重蒸馏整形未开启:请先在概览开关组打开重蒸馏整形");
3915
+ if (v.progress) {
3916
+ last = v.progress;
3917
+ setRdProgress(v.progress);
3918
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3919
+ }
3920
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3921
+ }).catch((e) => {
3922
+ if (mode === "resume") return;
3923
+ failMsg("重蒸馏整形失败:" + String(e && e.message || e));
3924
+ });
3925
+ };
3926
+ (0, import_react16.useEffect)(() => {
3927
+ keywordBackfill("resume");
3928
+ redistillBackfill("resume");
3929
+ wingBackfill("resume");
3930
+ }, []);
3931
+ const rowStyle = {
3932
+ display: "flex",
3933
+ alignItems: "center",
3934
+ gap: 10,
3935
+ flexWrap: "wrap",
3936
+ padding: "8px 0"
3937
+ };
3938
+ const hintStyle = { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-3)" };
3939
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-rb-card", style: { padding: "4px 14px", marginTop: 12 }, children: [
3940
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontWeight: 600, padding: "8px 0 2px" }, children: "存量回填与整形" }),
3941
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
3942
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: overview ? `对存量未打标记忆批量补打 wing 标签 · 未打标 ${overview.unlabeled} 条` : "未打标计数加载中…" }),
3943
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3944
+ NButton,
3945
+ {
3946
+ disabled: !overview || overview.unlabeled === 0 || wingBusy,
3947
+ style: { color: "var(--dsh-mem-accent)" },
3948
+ onClick: () => wingBackfill(),
3949
+ children: wingBusy ? "回填中…" : "wing 回填"
3950
+ }
3951
+ )
3952
+ ] }),
3953
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
3954
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: kwBusy ? fmtProgress(kwProgress, "回填", kwCounts ?? void 0) : kwSummary || "为缺 dsh_keywords 的存量记忆补检索关键词,喂 FTS 关键词轴(需先开关键词回填开关)" }),
3955
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { disabled: kwBusy, style: { color: "var(--dsh-mem-accent)" }, onClick: () => keywordBackfill(), children: kwBusy ? "回填中…" : "关键词回填" })
3956
+ ] }),
3957
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
3958
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: rdBusy ? fmtProgress(rdProgress, "整形", rdCounts ?? void 0) : rdSummary || "把“平”的存量记忆按类型重排成分节骨架,顺带产关键词/情景;只有严格更优才写回(需先开重蒸馏整形开关)" }),
3959
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { disabled: rdBusy, style: { color: "var(--dsh-mem-accent)" }, onClick: () => redistillBackfill(), children: rdBusy ? "整形中…" : "重蒸馏整形" })
3960
+ ] }),
3961
+ err ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { padding: "6px 0", fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null
3962
+ ] });
3963
+ }
3964
+
3965
+ // client/src/tabs/OverviewTab.tsx
3966
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3720
3967
  function OverviewTab(props) {
3721
3968
  const rpc = props.rpc;
3722
- const [stats, setStats] = (0, import_react16.useState)(null);
3723
- const [settingsData, setSettingsData] = (0, import_react16.useState)(null);
3724
- const [error, setError] = (0, import_react16.useState)(null);
3725
- const load = (0, import_react16.useCallback)(() => {
3969
+ const [stats, setStats] = (0, import_react17.useState)(null);
3970
+ const [settingsData, setSettingsData] = (0, import_react17.useState)(null);
3971
+ const [error, setError] = (0, import_react17.useState)(null);
3972
+ const load = (0, import_react17.useCallback)(() => {
3726
3973
  rpc("dsh-memory/stats", {}).then((r) => {
3727
3974
  if (r && r.ok) setStats(r.value);
3728
3975
  else setError(r && r.error ? r.error.message : "RPC error");
@@ -3734,7 +3981,7 @@ var __defProp = Object.defineProperty;
3734
3981
  }).catch(() => {
3735
3982
  });
3736
3983
  }, [rpc]);
3737
- (0, import_react16.useEffect)(() => {
3984
+ (0, import_react17.useEffect)(() => {
3738
3985
  load();
3739
3986
  const timer = setInterval(load, 5e3);
3740
3987
  return () => {
@@ -3759,6 +4006,23 @@ var __defProp = Object.defineProperty;
3759
4006
  setError("开关写入失败:" + String(e && e.message || e));
3760
4007
  });
3761
4008
  };
4009
+ const setNum = (key, value) => {
4010
+ if (!settingsData) return;
4011
+ const prev = settingsData;
4012
+ const next = { ...prev, settings: { ...prev.settings, [key]: value } };
4013
+ setSettingsData(next);
4014
+ rpc("dsh-memory/settings-set", { [key]: value }).then((r) => {
4015
+ if (!r || !r.ok) {
4016
+ setSettingsData(prev);
4017
+ setError(r && r.error ? "并行度写入失败:" + r.error.message : "并行度写入失败");
4018
+ } else {
4019
+ setError(null);
4020
+ }
4021
+ }).catch((e) => {
4022
+ setSettingsData(prev);
4023
+ setError("并行度写入失败:" + String(e && e.message || e));
4024
+ });
4025
+ };
3762
4026
  const tiles = [];
3763
4027
  const infos = [];
3764
4028
  if (stats) {
@@ -3796,10 +4060,15 @@ var __defProp = Object.defineProperty;
3796
4060
  const toolConflict = settingsData && settingsData.settings ? settingsData.settings.toolConflict !== false : true;
3797
4061
  const toolMutate = settingsData && settingsData.settings ? settingsData.settings.toolMutate !== false : true;
3798
4062
  const skillsEnabled = settingsData && settingsData.settings ? settingsData.settings.skillsEnabled === true : false;
3799
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3800
- settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: S.switchPanel, children: [
3801
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
3802
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4063
+ const keywordEnabled = settingsData && settingsData.settings ? settingsData.settings.keywordEnabled === true : false;
4064
+ const redistillEnabled = settingsData && settingsData.settings ? settingsData.settings.redistillEnabled === true : false;
4065
+ const mdSyncEnabled = settingsData && settingsData.settings ? settingsData.settings.mdSyncEnabled === true : false;
4066
+ const memportEnabled = settingsData && settingsData.settings ? settingsData.settings.memportEnabled === true : false;
4067
+ const bfConcurrency = settingsData && settingsData.settings ? settingsData.settings.backfillConcurrency ?? 0 : 0;
4068
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
4069
+ settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.switchPanel, children: [
4070
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
4071
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3803
4072
  SwitchRow,
3804
4073
  {
3805
4074
  label: "记忆模式",
@@ -3810,7 +4079,7 @@ var __defProp = Object.defineProperty;
3810
4079
  }
3811
4080
  }
3812
4081
  ),
3813
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4082
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3814
4083
  SwitchRow,
3815
4084
  {
3816
4085
  label: "捕获",
@@ -3822,7 +4091,7 @@ var __defProp = Object.defineProperty;
3822
4091
  }
3823
4092
  }
3824
4093
  ),
3825
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4094
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3826
4095
  SwitchRow,
3827
4096
  {
3828
4097
  label: "蒸馏",
@@ -3834,7 +4103,7 @@ var __defProp = Object.defineProperty;
3834
4103
  }
3835
4104
  }
3836
4105
  ),
3837
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4106
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3838
4107
  SwitchRow,
3839
4108
  {
3840
4109
  label: "召回",
@@ -3846,8 +4115,8 @@ var __defProp = Object.defineProperty;
3846
4115
  }
3847
4116
  }
3848
4117
  ),
3849
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3850
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4118
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
4119
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3851
4120
  SwitchRow,
3852
4121
  {
3853
4122
  label: "高权限模式",
@@ -3858,8 +4127,8 @@ var __defProp = Object.defineProperty;
3858
4127
  }
3859
4128
  }
3860
4129
  ),
3861
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3862
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4130
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
4131
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3863
4132
  SwitchRow,
3864
4133
  {
3865
4134
  label: "技能(程序性记忆)",
@@ -3870,8 +4139,8 @@ var __defProp = Object.defineProperty;
3870
4139
  }
3871
4140
  }
3872
4141
  ),
3873
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3874
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4142
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
4143
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3875
4144
  SwitchRow,
3876
4145
  {
3877
4146
  label: "Room 管理工具",
@@ -3882,7 +4151,7 @@ var __defProp = Object.defineProperty;
3882
4151
  }
3883
4152
  }
3884
4153
  ),
3885
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4154
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3886
4155
  SwitchRow,
3887
4156
  {
3888
4157
  label: "图谱工具",
@@ -3893,7 +4162,7 @@ var __defProp = Object.defineProperty;
3893
4162
  }
3894
4163
  }
3895
4164
  ),
3896
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4165
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3897
4166
  SwitchRow,
3898
4167
  {
3899
4168
  label: "反刍工具",
@@ -3904,7 +4173,7 @@ var __defProp = Object.defineProperty;
3904
4173
  }
3905
4174
  }
3906
4175
  ),
3907
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4176
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3908
4177
  SwitchRow,
3909
4178
  {
3910
4179
  label: "冲突工具",
@@ -3915,7 +4184,7 @@ var __defProp = Object.defineProperty;
3915
4184
  }
3916
4185
  }
3917
4186
  ),
3918
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4187
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3919
4188
  SwitchRow,
3920
4189
  {
3921
4190
  label: "写删工具",
@@ -3926,8 +4195,8 @@ var __defProp = Object.defineProperty;
3926
4195
  }
3927
4196
  }
3928
4197
  ),
3929
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3930
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4198
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
4199
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3931
4200
  SwitchRow,
3932
4201
  {
3933
4202
  label: "人工冲突裁决",
@@ -3938,43 +4207,110 @@ var __defProp = Object.defineProperty;
3938
4207
  }
3939
4208
  }
3940
4209
  ),
3941
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
3942
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
3943
- ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: ceilingNote }) : null
4210
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "存量回填与整形" }),
4211
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4212
+ SwitchRow,
4213
+ {
4214
+ label: "关键词回填",
4215
+ desc: keywordEnabled ? "已开启:可对存量记忆批量补检索关键词(下方「存量回填与整形」区点按钮)" : "默认关闭;开启后才能跑关键词回填(喂 FTS 关键词轴)",
4216
+ checked: keywordEnabled,
4217
+ onChange: (v) => {
4218
+ toggle("keywordEnabled", v);
4219
+ }
4220
+ }
4221
+ ),
4222
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4223
+ SwitchRow,
4224
+ {
4225
+ label: "重蒸馏整形",
4226
+ desc: redistillEnabled ? "已开启:可把“平”的存量记忆按类型重排成分节骨架(仅动严格更优的)" : "默认关闭;开启后才能跑重蒸馏整形(改正文会重算向量+覆盖 .memory.md)",
4227
+ checked: redistillEnabled,
4228
+ onChange: (v) => {
4229
+ toggle("redistillEnabled", v);
4230
+ }
4231
+ }
4232
+ ),
4233
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, padding: "6px 0", flexWrap: "wrap" }, children: [
4234
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { fontSize: 13 }, children: "回填并行度" }),
4235
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4236
+ "input",
4237
+ {
4238
+ type: "range",
4239
+ min: 0,
4240
+ max: 8,
4241
+ step: 1,
4242
+ value: Math.min(8, bfConcurrency),
4243
+ onChange: (e) => {
4244
+ setNum("backfillConcurrency", Number(e.target.value));
4245
+ },
4246
+ style: { width: 120 }
4247
+ }
4248
+ ),
4249
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: [
4250
+ bfConcurrency === 0 ? "0·跟随配置(默认 1=串行)" : bfConcurrency === 1 ? "1·串行逐条" : `${bfConcurrency} 路并发`,
4251
+ "· 对**下一次点击**生效(正在跑的那轮不会改道)"
4252
+ ] })
4253
+ ] }),
4254
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4255
+ SwitchRow,
4256
+ {
4257
+ label: "md 反向同步",
4258
+ desc: mdSyncEnabled ? "已开启:可将 .memory.md 文件侧修改回灌入库(需先开 md 投射 + 高权限)" : "默认关闭;风险高于导出(会写库),需先开 md 投射再开本项",
4259
+ checked: mdSyncEnabled,
4260
+ onChange: (v) => {
4261
+ toggle("mdSyncEnabled", v);
4262
+ }
4263
+ }
4264
+ ),
4265
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4266
+ SwitchRow,
4267
+ {
4268
+ label: "外部记忆来源 Connect",
4269
+ desc: memportEnabled ? "已开启:可登记/扫描外部记忆源并导入" : "默认关闭;开启后 memport 相关端点可用",
4270
+ checked: memportEnabled,
4271
+ onChange: (v) => {
4272
+ toggle("memportEnabled", v);
4273
+ }
4274
+ }
4275
+ ),
4276
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
4277
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
4278
+ ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3944
4279
  ] }) : null,
3945
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(EmbeddingSection, { rpc }),
3946
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RebuildPanel, { rpc }),
3947
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RuminatePanel, { rpc }),
3948
- degraded ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
3949
- error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3950
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
3951
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
3952
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
3953
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statNum, children: t.num }),
3954
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.statLabel, children: t.label })
4280
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EmbeddingSection, { rpc }),
4281
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RebuildPanel, { rpc }),
4282
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RuminatePanel, { rpc }),
4283
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BackfillSection, { rpc }),
4284
+ degraded ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
4285
+ error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
4286
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
4287
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
4288
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
4289
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statNum, children: t.num }),
4290
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statLabel, children: t.label })
3955
4291
  ] }, t.label);
3956
4292
  }) }),
3957
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
4293
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3958
4294
  infos.map((row2) => {
3959
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: S.infoRow, children: [
3960
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoKey, children: row2[0] }),
3961
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.infoVal, children: row2[1] })
4295
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.infoRow, children: [
4296
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.infoKey, children: row2[0] }),
4297
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.infoVal, children: row2[1] })
3962
4298
  ] }, row2[0]);
3963
4299
  })
3964
4300
  ] }),
3965
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArchiveSection, { rpc }),
3966
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
4301
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArchiveSection, { rpc }),
4302
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3967
4303
  ] });
3968
4304
  }
3969
4305
 
3970
4306
  // client/src/tabs/PersonaTab.tsx
3971
- var import_react17 = require("react");
3972
- var import_jsx_runtime17 = require("react/jsx-runtime");
4307
+ var import_react18 = require("react");
4308
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3973
4309
  function PersonaTab(props) {
3974
4310
  const rpc = props.rpc;
3975
- const [content, setContent] = (0, import_react17.useState)(null);
3976
- const [error, setError] = (0, import_react17.useState)(null);
3977
- const load = (0, import_react17.useCallback)(() => {
4311
+ const [content, setContent] = (0, import_react18.useState)(null);
4312
+ const [error, setError] = (0, import_react18.useState)(null);
4313
+ const load = (0, import_react18.useCallback)(() => {
3978
4314
  setError(null);
3979
4315
  rpc("dsh-memory/persona", {}).then((r) => {
3980
4316
  if (r && r.ok) setContent(r.value.content);
@@ -3983,23 +4319,97 @@ var __defProp = Object.defineProperty;
3983
4319
  setError(String(e && e.message || e));
3984
4320
  });
3985
4321
  }, [rpc]);
3986
- (0, import_react17.useEffect)(() => {
4322
+ (0, import_react18.useEffect)(() => {
3987
4323
  load();
3988
4324
  }, [load]);
3989
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3990
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3991
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
3992
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
3993
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(NButton, { onClick: load, children: "刷新" })
4325
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4326
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4327
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
4328
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4329
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: load, children: "刷新" })
3994
4330
  ] }),
3995
- error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
3996
- content ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
4331
+ error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
4332
+ content ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
3997
4333
  ] });
3998
4334
  }
3999
4335
 
4000
4336
  // client/src/tabs/RecordsTab.tsx
4001
- var import_react18 = require("react");
4002
- var import_jsx_runtime18 = require("react/jsx-runtime");
4337
+ var import_react20 = require("react");
4338
+
4339
+ // client/src/ui/MarkdownBody.tsx
4340
+ var import_react19 = require("react");
4341
+ var H_STYLES = [
4342
+ { fontSize: 15, fontWeight: 700, margin: "8px 0 4px", color: "var(--dsh-mem-text-1)" },
4343
+ { fontSize: 14, fontWeight: 600, margin: "6px 0 3px", color: "var(--dsh-mem-text-1)" },
4344
+ { fontSize: 13, fontWeight: 600, margin: "5px 0 2px", color: "var(--dsh-mem-text-1)" },
4345
+ { fontSize: 12, fontWeight: 600, margin: "4px 0 2px", color: "var(--dsh-mem-text-2)" },
4346
+ { fontSize: 12, fontWeight: 600, margin: "3px 0 1px", color: "var(--dsh-mem-text-2)" },
4347
+ { fontSize: 11, fontWeight: 600, margin: "3px 0 1px", color: "var(--dsh-mem-text-2)" }
4348
+ ];
4349
+ var P2 = { margin: "2px 0", whiteSpace: "pre-wrap", wordBreak: "break-word" };
4350
+ var LI = { margin: "1px 0 1px 12px", whiteSpace: "pre-wrap", wordBreak: "break-word" };
4351
+ var CODE = {
4352
+ fontFamily: "ui-monospace, monospace",
4353
+ fontSize: "0.92em",
4354
+ background: "var(--dsh-mem-bg-3)",
4355
+ padding: "0 3px",
4356
+ borderRadius: 3
4357
+ };
4358
+ function inline(text, key) {
4359
+ const nodes = [];
4360
+ const re = /\*\*(.+?)\*\*|`(.+?)`/;
4361
+ let rest = text;
4362
+ let i = 0;
4363
+ while (rest.length > 0) {
4364
+ const m = re.exec(rest);
4365
+ if (m === null) {
4366
+ nodes.push(rest);
4367
+ break;
4368
+ }
4369
+ if (m.index > 0) nodes.push(rest.slice(0, m.index));
4370
+ if (m[1] !== void 0) {
4371
+ nodes.push((0, import_react19.createElement)("strong", { key: `${key}-b${i++}` }, m[1]));
4372
+ } else {
4373
+ nodes.push((0, import_react19.createElement)("code", { key: `${key}-c${i++}`, style: CODE }, m[2]));
4374
+ }
4375
+ rest = rest.slice(m.index + m[0].length);
4376
+ }
4377
+ return nodes;
4378
+ }
4379
+ function MarkdownBody({ text }) {
4380
+ const lines = text.split("\n");
4381
+ const out = [];
4382
+ let idx = 0;
4383
+ for (const line of lines) {
4384
+ const t = line.trim();
4385
+ if (t.length === 0) continue;
4386
+ const h = /^(#{1,6})\s+(.+)/.exec(t);
4387
+ if (h) {
4388
+ const lv = h[1].length;
4389
+ out.push((0, import_react19.createElement)(`h${lv}`, { key: `h${idx}`, style: H_STYLES[lv - 1] }, ...inline(h[2], `h${idx}`)));
4390
+ idx++;
4391
+ continue;
4392
+ }
4393
+ const ul = /^[-*]\s+(.+)/.exec(t);
4394
+ if (ul) {
4395
+ out.push((0, import_react19.createElement)("div", { key: `li${idx}`, style: LI }, "• ", ...inline(ul[1], `li${idx}`)));
4396
+ idx++;
4397
+ continue;
4398
+ }
4399
+ const ol = /^\d+\.\s+(.+)/.exec(t);
4400
+ if (ol) {
4401
+ out.push((0, import_react19.createElement)("div", { key: `li${idx}`, style: LI }, t.slice(0, t.indexOf(".") + 2), ...inline(ol[1], `li${idx}`)));
4402
+ idx++;
4403
+ continue;
4404
+ }
4405
+ out.push((0, import_react19.createElement)("div", { key: `p${idx}`, style: P2 }, ...inline(t, `p${idx}`)));
4406
+ idx++;
4407
+ }
4408
+ return (0, import_react19.createElement)(import_react19.Fragment, null, ...out);
4409
+ }
4410
+
4411
+ // client/src/tabs/RecordsTab.tsx
4412
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4003
4413
  function retiredSelOf(r) {
4004
4414
  if (r === "active") return false;
4005
4415
  if (r === "retired") return true;
@@ -4009,29 +4419,29 @@ var __defProp = Object.defineProperty;
4009
4419
  function RecordsTab(props) {
4010
4420
  const rpc = props.rpc;
4011
4421
  const limit = 50;
4012
- const [items, setItems] = (0, import_react18.useState)([]);
4013
- const [hasMore, setHasMore] = (0, import_react18.useState)(false);
4014
- const [total, setTotal] = (0, import_react18.useState)(null);
4015
- const [sceneOptions, setSceneOptions] = (0, import_react18.useState)([]);
4016
- const [loading, setLoading] = (0, import_react18.useState)(false);
4017
- const [truncated, setTruncated] = (0, import_react18.useState)(false);
4018
- const [error, setError] = (0, import_react18.useState)(null);
4019
- const [expandedId, setExpandedId] = (0, import_react18.useState)(null);
4020
- const [sel, setSel] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
4021
- const [hiPriv, setHiPriv] = (0, import_react18.useState)(false);
4022
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react18.useState)(false);
4023
- const [query, setQuery] = (0, import_react18.useState)("");
4024
- const [typeFilter, setTypeFilter] = (0, import_react18.useState)("");
4025
- const [sceneFilter, setSceneFilter] = (0, import_react18.useState)("");
4026
- const [hallFilter, setHallFilter] = (0, import_react18.useState)([]);
4027
- const [tagFilter, setTagFilter] = (0, import_react18.useState)("");
4028
- const [untaggedOnly, setUntaggedOnly] = (0, import_react18.useState)(false);
4029
- const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
4030
- const [retiredFilter, setRetiredFilter] = (0, import_react18.useState)("");
4031
- const [wingCatalog, setHallCatalog] = (0, import_react18.useState)(null);
4032
- const [last, setLast] = (0, import_react18.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
4033
- const seqRef = (0, import_react18.useRef)(0);
4034
- const fetchPage = (0, import_react18.useCallback)(
4422
+ const [items, setItems] = (0, import_react20.useState)([]);
4423
+ const [hasMore, setHasMore] = (0, import_react20.useState)(false);
4424
+ const [total, setTotal] = (0, import_react20.useState)(null);
4425
+ const [sceneOptions, setSceneOptions] = (0, import_react20.useState)([]);
4426
+ const [loading, setLoading] = (0, import_react20.useState)(false);
4427
+ const [truncated, setTruncated] = (0, import_react20.useState)(false);
4428
+ const [error, setError] = (0, import_react20.useState)(null);
4429
+ const [expandedId, setExpandedId] = (0, import_react20.useState)(null);
4430
+ const [sel, setSel] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
4431
+ const [hiPriv, setHiPriv] = (0, import_react20.useState)(false);
4432
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react20.useState)(false);
4433
+ const [query, setQuery] = (0, import_react20.useState)("");
4434
+ const [typeFilter, setTypeFilter] = (0, import_react20.useState)("");
4435
+ const [sceneFilter, setSceneFilter] = (0, import_react20.useState)("");
4436
+ const [hallFilter, setHallFilter] = (0, import_react20.useState)([]);
4437
+ const [tagFilter, setTagFilter] = (0, import_react20.useState)("");
4438
+ const [untaggedOnly, setUntaggedOnly] = (0, import_react20.useState)(false);
4439
+ const [orphanCount, setOrphanCount] = (0, import_react20.useState)(0);
4440
+ const [retiredFilter, setRetiredFilter] = (0, import_react20.useState)("");
4441
+ const [wingCatalog, setHallCatalog] = (0, import_react20.useState)(null);
4442
+ const [last, setLast] = (0, import_react20.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
4443
+ const seqRef = (0, import_react20.useRef)(0);
4444
+ const fetchPage = (0, import_react20.useCallback)(
4035
4445
  (conds, offset, append) => {
4036
4446
  setLoading(true);
4037
4447
  setError(null);
@@ -4081,23 +4491,23 @@ var __defProp = Object.defineProperty;
4081
4491
  setLast(conds);
4082
4492
  fetchPage(conds, 0, false);
4083
4493
  };
4084
- const loadRooms = (0, import_react18.useCallback)(() => {
4494
+ const loadRooms = (0, import_react20.useCallback)(() => {
4085
4495
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4086
4496
  if (r && r.ok) setOrphanCount(r.value.orphanCount ?? 0);
4087
4497
  }).catch(() => {
4088
4498
  });
4089
4499
  }, [rpc]);
4090
- (0, import_react18.useEffect)(() => {
4500
+ (0, import_react20.useEffect)(() => {
4091
4501
  fetchPage({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" }, 0, false);
4092
4502
  loadRooms();
4093
4503
  }, [fetchPage, loadRooms]);
4094
- const loadHiPriv = (0, import_react18.useCallback)(() => {
4504
+ const loadHiPriv = (0, import_react20.useCallback)(() => {
4095
4505
  rpc("dsh-memory/settings-get", {}).then((r) => {
4096
4506
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4097
4507
  }).catch(() => {
4098
4508
  });
4099
4509
  }, [rpc]);
4100
- (0, import_react18.useEffect)(() => {
4510
+ (0, import_react20.useEffect)(() => {
4101
4511
  loadHiPriv();
4102
4512
  }, [loadHiPriv]);
4103
4513
  const toggleHiPriv = () => {
@@ -4161,11 +4571,11 @@ var __defProp = Object.defineProperty;
4161
4571
  } else if (r) setError(r.error ? r.error.message : "退场失败");
4162
4572
  }).catch((e) => setError(String(e && e.message || e)));
4163
4573
  };
4164
- const [retired, setRetired] = (0, import_react18.useState)([]);
4165
- const [retiredTotal, setRetiredTotal] = (0, import_react18.useState)(0);
4166
- const [showRetired, setShowRetired] = (0, import_react18.useState)(false);
4167
- const [retiredBusy, setRetiredBusy] = (0, import_react18.useState)(false);
4168
- const loadRetired = (0, import_react18.useCallback)(() => {
4574
+ const [retired, setRetired] = (0, import_react20.useState)([]);
4575
+ const [retiredTotal, setRetiredTotal] = (0, import_react20.useState)(0);
4576
+ const [showRetired, setShowRetired] = (0, import_react20.useState)(false);
4577
+ const [retiredBusy, setRetiredBusy] = (0, import_react20.useState)(false);
4578
+ const loadRetired = (0, import_react20.useCallback)(() => {
4169
4579
  setRetiredBusy(true);
4170
4580
  rpc("dsh-memory/records-retired", { limit: 100, offset: 0 }).then((r) => {
4171
4581
  if (r && r.ok) {
@@ -4174,7 +4584,7 @@ var __defProp = Object.defineProperty;
4174
4584
  } else if (r) setError(r.error ? r.error.message : "已退场列表加载失败");
4175
4585
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
4176
4586
  }, [rpc]);
4177
- (0, import_react18.useEffect)(() => {
4587
+ (0, import_react20.useEffect)(() => {
4178
4588
  if (showRetired) loadRetired();
4179
4589
  }, [showRetired, loadRetired]);
4180
4590
  const restoreRecords = (ids) => {
@@ -4198,11 +4608,11 @@ var __defProp = Object.defineProperty;
4198
4608
  unknown: "已退场"
4199
4609
  };
4200
4610
  const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
4201
- const [usageSummary, setUsageSummary] = (0, import_react18.useState)(null);
4611
+ const [usageSummary, setUsageSummary] = (0, import_react20.useState)(null);
4202
4612
  const selCount = sel.size;
4203
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4204
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.toolbar, children: [
4205
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4613
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4614
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.toolbar, children: [
4615
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4206
4616
  NInput,
4207
4617
  {
4208
4618
  style: { flex: 1, minWidth: 160 },
@@ -4225,7 +4635,7 @@ var __defProp = Object.defineProperty;
4225
4635
  }
4226
4636
  }
4227
4637
  ),
4228
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4638
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4229
4639
  NSel,
4230
4640
  {
4231
4641
  style: { maxWidth: 200 },
@@ -4238,7 +4648,7 @@ var __defProp = Object.defineProperty;
4238
4648
  onChange: setTypeFilter
4239
4649
  }
4240
4650
  ),
4241
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4651
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4242
4652
  NSel,
4243
4653
  {
4244
4654
  style: { maxWidth: 220 },
@@ -4251,7 +4661,7 @@ var __defProp = Object.defineProperty;
4251
4661
  onChange: setSceneFilter
4252
4662
  }
4253
4663
  ),
4254
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4664
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4255
4665
  WingMultiSelect,
4256
4666
  {
4257
4667
  options: wingCatalog ?? Array.from(new Set(items.map((m) => m.hall).filter((h) => !!h))).map((id) => ({ id, label: id })),
@@ -4259,8 +4669,8 @@ var __defProp = Object.defineProperty;
4259
4669
  onChange: setHallFilter
4260
4670
  }
4261
4671
  ),
4262
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: search, children: "搜索" }),
4263
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4672
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { onClick: search, children: "搜索" }),
4673
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4264
4674
  NButton,
4265
4675
  {
4266
4676
  style: {
@@ -4274,8 +4684,8 @@ var __defProp = Object.defineProperty;
4274
4684
  }
4275
4685
  )
4276
4686
  ] }),
4277
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
4278
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4687
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
4688
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4279
4689
  "button",
4280
4690
  {
4281
4691
  type: "button",
@@ -4300,10 +4710,10 @@ var __defProp = Object.defineProperty;
4300
4710
  children: "无绑定 · " + orphanCount
4301
4711
  }
4302
4712
  ),
4303
- (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
4713
+ (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4304
4714
  "筛选中:",
4305
4715
  untaggedOnly ? "无绑定" : tagFilter,
4306
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4716
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4307
4717
  "button",
4308
4718
  {
4309
4719
  type: "button",
@@ -4320,7 +4730,7 @@ var __defProp = Object.defineProperty;
4320
4730
  }
4321
4731
  )
4322
4732
  ] }),
4323
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4733
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4324
4734
  "button",
4325
4735
  {
4326
4736
  type: "button",
@@ -4349,15 +4759,15 @@ var __defProp = Object.defineProperty;
4349
4759
  children: "导出孤儿"
4350
4760
  }
4351
4761
  ),
4352
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4762
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4353
4763
  ] }),
4354
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4355
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
4356
- usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
4357
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "退场筛查" }),
4764
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4765
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
4766
+ usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
4767
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "退场筛查" }),
4358
4768
  [["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
4359
4769
  const on = retiredFilter === val;
4360
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4770
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4361
4771
  "button",
4362
4772
  {
4363
4773
  type: "button",
@@ -4377,7 +4787,7 @@ var __defProp = Object.defineProperty;
4377
4787
  val
4378
4788
  );
4379
4789
  }),
4380
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4790
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4381
4791
  NButton,
4382
4792
  {
4383
4793
  style: selCount > 0 ? { color: "var(--dsh-mem-danger)" } : void 0,
@@ -4387,7 +4797,7 @@ var __defProp = Object.defineProperty;
4387
4797
  children: "删除选中" + (selCount > 0 ? "(" + selCount + ")" : "")
4388
4798
  }
4389
4799
  ),
4390
- selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4800
+ selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4391
4801
  NButton,
4392
4802
  {
4393
4803
  onClick: () => {
@@ -4396,8 +4806,8 @@ var __defProp = Object.defineProperty;
4396
4806
  children: "清空选择"
4397
4807
  }
4398
4808
  ) : null,
4399
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4400
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4809
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4810
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4401
4811
  NButton,
4402
4812
  {
4403
4813
  onClick: () => {
@@ -4408,13 +4818,13 @@ var __defProp = Object.defineProperty;
4408
4818
  }
4409
4819
  )
4410
4820
  ] }),
4411
- !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4412
- error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.error, children: error }) : null,
4413
- truncated ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4414
- items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4821
+ !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4822
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
4823
+ truncated ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4824
+ items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4415
4825
  const open = expandedId === m.id;
4416
4826
  const checked = sel.has(m.id);
4417
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4827
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4418
4828
  "div",
4419
4829
  {
4420
4830
  className: "dsh-mem-card dsh-mem-card-hover",
@@ -4423,8 +4833,8 @@ var __defProp = Object.defineProperty;
4423
4833
  setExpandedId(open ? null : m.id);
4424
4834
  },
4425
4835
  children: [
4426
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4427
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4836
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.cardHead, children: [
4837
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4428
4838
  "input",
4429
4839
  {
4430
4840
  type: "checkbox",
@@ -4439,9 +4849,9 @@ var __defProp = Object.defineProperty;
4439
4849
  }
4440
4850
  }
4441
4851
  ),
4442
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: tagClass(m.type), children: typeLabel(m.type) }),
4443
- m.hall ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Wing · " + (wingCatalog?.find((h) => h.id === m.hall)?.label || m.hall) }) : null,
4444
- m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4852
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: tagClass(m.type), children: typeLabel(m.type) }),
4853
+ m.hall ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Wing · " + (wingCatalog?.find((h) => h.id === m.hall)?.label || m.hall) }) : null,
4854
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4445
4855
  "span",
4446
4856
  {
4447
4857
  title: "该记忆已退场(软删):移出检索面但仍可恢复,并未真正删除",
@@ -4456,8 +4866,8 @@ var __defProp = Object.defineProperty;
4456
4866
  children: "已退场" + (m.retiredReason ? " · " + (RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason) : "")
4457
4867
  }
4458
4868
  ) : null,
4459
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4460
- m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4869
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4870
+ m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4461
4871
  "span",
4462
4872
  {
4463
4873
  title: "成熟度(优先级 + 被用次数 + 新鲜度合成):" + m.maturity,
@@ -4472,7 +4882,7 @@ var __defProp = Object.defineProperty;
4472
4882
  children: m.maturity === "high" ? "成熟·高" : m.maturity === "mid" ? "成熟·中" : "成熟·低"
4473
4883
  }
4474
4884
  ) : null,
4475
- m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4885
+ m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4476
4886
  "span",
4477
4887
  {
4478
4888
  style: {
@@ -4487,7 +4897,7 @@ var __defProp = Object.defineProperty;
4487
4897
  children: "老化 " + Math.round(m.agingWeight * 100) + "%"
4488
4898
  }
4489
4899
  ) : null,
4490
- m.usage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4900
+ m.usage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4491
4901
  "span",
4492
4902
  {
4493
4903
  style: S.muted,
@@ -4495,7 +4905,7 @@ var __defProp = Object.defineProperty;
4495
4905
  children: "用 " + m.usage.used + "/" + m.usage.attempts
4496
4906
  }
4497
4907
  ) : null,
4498
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4908
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4499
4909
  "span",
4500
4910
  {
4501
4911
  title: m.name && m.name.length > 0 ? "名称(名称蒸馏产物;投射文件的命名取它):" + m.name : "尚未命名(名称蒸馏未产出);投射回落 mem-" + m.id.slice(-8),
@@ -4513,7 +4923,7 @@ var __defProp = Object.defineProperty;
4513
4923
  children: "名称 " + (m.name && m.name.length > 0 ? m.name : "未命名")
4514
4924
  }
4515
4925
  ),
4516
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4926
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4517
4927
  "span",
4518
4928
  {
4519
4929
  title: m.scope === "workspace" ? "作用范围:指定工作区(仅归属工作区可见)" + (m.workspaceId ? ":" + m.workspaceId : "") : "作用范围:用户默认(global,任何工作区可见)",
@@ -4528,10 +4938,10 @@ var __defProp = Object.defineProperty;
4528
4938
  children: m.scope === "workspace" ? "工作区" : "用户默认"
4529
4939
  }
4530
4940
  ),
4531
- m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4532
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4533
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
4534
- m.retired ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4941
+ m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4942
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4943
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
4944
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4535
4945
  NButton,
4536
4946
  {
4537
4947
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-accent)" },
@@ -4542,7 +4952,7 @@ var __defProp = Object.defineProperty;
4542
4952
  },
4543
4953
  children: "恢复"
4544
4954
  }
4545
- ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4955
+ ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4546
4956
  NButton,
4547
4957
  {
4548
4958
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-danger)" },
@@ -4555,34 +4965,34 @@ var __defProp = Object.defineProperty;
4555
4965
  }
4556
4966
  ) : null
4557
4967
  ] }),
4558
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content }),
4559
- open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n名称: " + (m.name && m.name.length > 0 ? m.name : "(未命名,投射回落 mem-" + m.id.slice(-8) + ")") + "\n情境: " + (m.scene || "-") + "\n关键词: " + (m.keywords && m.keywords.length > 0 ? m.keywords.join(",") : "(暂无 · 预留检索轴)") + "\n作用范围: " + (m.scope === "workspace" ? "指定工作区" + (m.workspaceId ? ":" + m.workspaceId : "(未记录路径)") : "用户默认(global,任何工作区可见)") + "\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
4968
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.content, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MarkdownBody, { text: m.content }) }),
4969
+ open ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n名称: " + (m.name && m.name.length > 0 ? m.name : "(未命名,投射回落 mem-" + m.id.slice(-8) + ")") + "\n情境: " + (m.scene || "-") + "\n关键词: " + (m.keywords && m.keywords.length > 0 ? m.keywords.join(",") : "(暂无 · 预留检索轴)") + "\n作用范围: " + (m.scope === "workspace" ? "指定工作区" + (m.workspaceId ? ":" + m.workspaceId : "(未记录路径)") : "用户默认(global,任何工作区可见)") + "\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
4560
4970
  ]
4561
4971
  },
4562
4972
  m.id
4563
4973
  );
4564
4974
  }),
4565
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
4566
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
4567
- showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
4568
- showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4975
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
4976
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
4977
+ showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
4978
+ showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4569
4979
  ] }),
4570
- 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: [
4571
- retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
4572
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4573
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
4574
- m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
4575
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4576
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
4577
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4980
+ showRetired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: 8 }, children: retired.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.hint, children: retiredBusy ? " " : "没有已退场的记忆。" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4981
+ retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
4982
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.cardHead, children: [
4983
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
4984
+ m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
4985
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4986
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
4987
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4578
4988
  ] }),
4579
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content })
4989
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.content, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MarkdownBody, { text: m.content }) })
4580
4990
  ] }, m.id)),
4581
- retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4991
+ retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4582
4992
  ] }) }) : null,
4583
- hasMore ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.flexRow, children: [
4584
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4585
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4993
+ hasMore ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.flexRow, children: [
4994
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4995
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4586
4996
  NButton,
4587
4997
  {
4588
4998
  disabled: loading,
@@ -4596,9 +5006,9 @@ var __defProp = Object.defineProperty;
4596
5006
  ] });
4597
5007
  }
4598
5008
  function WingMultiSelect(props) {
4599
- const [open, setOpen] = (0, import_react18.useState)(false);
4600
- const wrapRef = (0, import_react18.useRef)(null);
4601
- (0, import_react18.useEffect)(() => {
5009
+ const [open, setOpen] = (0, import_react20.useState)(false);
5010
+ const wrapRef = (0, import_react20.useRef)(null);
5011
+ (0, import_react20.useEffect)(() => {
4602
5012
  if (!open) return;
4603
5013
  const onDown = (e) => {
4604
5014
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -4618,8 +5028,8 @@ var __defProp = Object.defineProperty;
4618
5028
  const toggle = (id) => {
4619
5029
  props.onChange(props.selected.includes(id) ? props.selected.filter((x) => x !== id) : [...props.selected, id]);
4620
5030
  };
4621
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4622
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5031
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
5032
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4623
5033
  "button",
4624
5034
  {
4625
5035
  type: "button",
@@ -4628,31 +5038,31 @@ var __defProp = Object.defineProperty;
4628
5038
  "aria-expanded": open,
4629
5039
  onClick: () => setOpen(!open),
4630
5040
  children: [
4631
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
4632
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
5041
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
5042
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
4633
5043
  ]
4634
5044
  }
4635
5045
  ),
4636
- open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
4637
- props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
5046
+ open ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
5047
+ props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
4638
5048
  props.options.map((o) => {
4639
5049
  const active = props.selected.includes(o.id);
4640
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
4641
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
4642
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
5050
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
5051
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
5052
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
4643
5053
  ] }, o.id);
4644
5054
  }),
4645
- props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
4646
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-check" }),
4647
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
5055
+ props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
5056
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-check" }),
5057
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
4648
5058
  ] }) : null
4649
5059
  ] }) : null
4650
5060
  ] });
4651
5061
  }
4652
5062
 
4653
5063
  // client/src/tabs/RoomsTab.tsx
4654
- var import_react19 = require("react");
4655
- var import_jsx_runtime19 = require("react/jsx-runtime");
5064
+ var import_react21 = require("react");
5065
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4656
5066
  function majorOf(slug) {
4657
5067
  const i = slug.indexOf("/");
4658
5068
  return i === -1 ? slug : slug.slice(0, i);
@@ -4681,26 +5091,26 @@ var __defProp = Object.defineProperty;
4681
5091
  };
4682
5092
  function RoomsTab(props) {
4683
5093
  const rpc = props.rpc;
4684
- const [registry, setRegistry] = (0, import_react19.useState)([]);
4685
- const [rooms, setRooms] = (0, import_react19.useState)([]);
4686
- const [orphanCount, setOrphanCount] = (0, import_react19.useState)(0);
4687
- const [busy, setBusy] = (0, import_react19.useState)(false);
4688
- const [msg, setMsg] = (0, import_react19.useState)(null);
4689
- const [error, setError] = (0, import_react19.useState)(null);
4690
- const [hiPriv, setHiPriv] = (0, import_react19.useState)(false);
4691
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react19.useState)(false);
4692
- const [regSlug, setRegSlug] = (0, import_react19.useState)("");
4693
- const [regLabel, setRegLabel] = (0, import_react19.useState)("");
4694
- const [regDesc, setRegDesc] = (0, import_react19.useState)("");
4695
- const [form, setForm] = (0, import_react19.useState)(null);
4696
- const [preview, setPreview] = (0, import_react19.useState)(null);
4697
- const [grownOpen, setGrownOpen] = (0, import_react19.useState)(false);
4698
- const [dragOverHall, setDragOverHall] = (0, import_react19.useState)(null);
4699
- const [picking, setPicking] = (0, import_react19.useState)(null);
4700
- const [editing, setEditing] = (0, import_react19.useState)(null);
4701
- const [expandedRooms, setExpandedRooms] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
4702
- const [roomRecords, setRoomRecords] = (0, import_react19.useState)({});
4703
- const [expandedHalls, setExpandedHalls] = (0, import_react19.useState)(() => {
5094
+ const [registry, setRegistry] = (0, import_react21.useState)([]);
5095
+ const [rooms, setRooms] = (0, import_react21.useState)([]);
5096
+ const [orphanCount, setOrphanCount] = (0, import_react21.useState)(0);
5097
+ const [busy, setBusy] = (0, import_react21.useState)(false);
5098
+ const [msg, setMsg] = (0, import_react21.useState)(null);
5099
+ const [error, setError] = (0, import_react21.useState)(null);
5100
+ const [hiPriv, setHiPriv] = (0, import_react21.useState)(false);
5101
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react21.useState)(false);
5102
+ const [regSlug, setRegSlug] = (0, import_react21.useState)("");
5103
+ const [regLabel, setRegLabel] = (0, import_react21.useState)("");
5104
+ const [regDesc, setRegDesc] = (0, import_react21.useState)("");
5105
+ const [form, setForm] = (0, import_react21.useState)(null);
5106
+ const [preview, setPreview] = (0, import_react21.useState)(null);
5107
+ const [grownOpen, setGrownOpen] = (0, import_react21.useState)(false);
5108
+ const [dragOverHall, setDragOverHall] = (0, import_react21.useState)(null);
5109
+ const [picking, setPicking] = (0, import_react21.useState)(null);
5110
+ const [editing, setEditing] = (0, import_react21.useState)(null);
5111
+ const [expandedRooms, setExpandedRooms] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
5112
+ const [roomRecords, setRoomRecords] = (0, import_react21.useState)({});
5113
+ const [expandedHalls, setExpandedHalls] = (0, import_react21.useState)(() => {
4704
5114
  try {
4705
5115
  const v = window.localStorage.getItem("dsh.memory.halls.open");
4706
5116
  return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
@@ -4708,9 +5118,9 @@ var __defProp = Object.defineProperty;
4708
5118
  return /* @__PURE__ */ new Set();
4709
5119
  }
4710
5120
  });
4711
- const [filter, setFilter] = (0, import_react19.useState)("");
4712
- const dragRef = (0, import_react19.useRef)(null);
4713
- const [ghost, setGhost] = (0, import_react19.useState)(null);
5121
+ const [filter, setFilter] = (0, import_react21.useState)("");
5122
+ const dragRef = (0, import_react21.useRef)(null);
5123
+ const [ghost, setGhost] = (0, import_react21.useState)(null);
4714
5124
  const onDragLabelDown = (ev, slug) => {
4715
5125
  if (!hiPriv || busy || ev.button !== 0) return;
4716
5126
  ev.currentTarget.setPointerCapture(ev.pointerId);
@@ -4735,7 +5145,7 @@ var __defProp = Object.defineProperty;
4735
5145
  setDragOverHall(null);
4736
5146
  if (hall) beginReclass(d.from, hall);
4737
5147
  };
4738
- const loadAll = (0, import_react19.useCallback)(() => {
5148
+ const loadAll = (0, import_react21.useCallback)(() => {
4739
5149
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4740
5150
  if (r && r.ok) {
4741
5151
  setRooms(r.value.rooms ?? []);
@@ -4744,13 +5154,13 @@ var __defProp = Object.defineProperty;
4744
5154
  }
4745
5155
  }).catch(() => void 0);
4746
5156
  }, [rpc]);
4747
- const loadHiPriv = (0, import_react19.useCallback)(() => {
5157
+ const loadHiPriv = (0, import_react21.useCallback)(() => {
4748
5158
  rpc("dsh-memory/settings-get", {}).then((r) => {
4749
5159
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4750
5160
  }).catch(() => {
4751
5161
  });
4752
5162
  }, [rpc]);
4753
- (0, import_react19.useEffect)(() => {
5163
+ (0, import_react21.useEffect)(() => {
4754
5164
  loadAll();
4755
5165
  loadHiPriv();
4756
5166
  }, [loadAll, loadHiPriv]);
@@ -4905,7 +5315,7 @@ var __defProp = Object.defineProperty;
4905
5315
  if (r.value.csv) downloadCsv(r.value.csv, `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`);
4906
5316
  else setError("导出为空");
4907
5317
  });
4908
- const groups = (0, import_react19.useMemo)(() => {
5318
+ const groups = (0, import_react21.useMemo)(() => {
4909
5319
  const countOf = new Map(rooms.map((r) => [r.room, r.count]));
4910
5320
  const byHall = /* @__PURE__ */ new Map();
4911
5321
  for (const e of registry) {
@@ -4922,7 +5332,7 @@ var __defProp = Object.defineProperty;
4922
5332
  total: entries.reduce((s2, e) => s2 + (countOf.get(e.slug) ?? 0), 0)
4923
5333
  })).sort((a, b) => a.hall.localeCompare(b.hall));
4924
5334
  }, [registry, rooms]);
4925
- const grownOnly = (0, import_react19.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
5335
+ const grownOnly = (0, import_react21.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4926
5336
  const persistHalls = (next) => {
4927
5337
  try {
4928
5338
  window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
@@ -4942,7 +5352,7 @@ var __defProp = Object.defineProperty;
4942
5352
  persistHalls(next);
4943
5353
  };
4944
5354
  const normFilter = filter.trim().toLowerCase();
4945
- const visibleGroups = (0, import_react19.useMemo)(() => {
5355
+ const visibleGroups = (0, import_react21.useMemo)(() => {
4946
5356
  if (!normFilter) return groups;
4947
5357
  return groups.map((g) => {
4948
5358
  const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
@@ -4952,15 +5362,15 @@ var __defProp = Object.defineProperty;
4952
5362
  return { ...g, entries };
4953
5363
  }).filter((g) => g.entries.length > 0);
4954
5364
  }, [groups, normFilter]);
4955
- const visibleGrown = (0, import_react19.useMemo)(
5365
+ const visibleGrown = (0, import_react21.useMemo)(
4956
5366
  () => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
4957
5367
  [grownOnly, normFilter]
4958
5368
  );
4959
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4960
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
4961
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
4962
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4963
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5369
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5370
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
5371
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
5372
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5373
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4964
5374
  "button",
4965
5375
  {
4966
5376
  type: "button",
@@ -4977,7 +5387,7 @@ var __defProp = Object.defineProperty;
4977
5387
  children: "导出词表"
4978
5388
  }
4979
5389
  ),
4980
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5390
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4981
5391
  "button",
4982
5392
  {
4983
5393
  type: "button",
@@ -4997,7 +5407,7 @@ var __defProp = Object.defineProperty;
4997
5407
  ]
4998
5408
  }
4999
5409
  ),
5000
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5410
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5001
5411
  "button",
5002
5412
  {
5003
5413
  type: "button",
@@ -5012,10 +5422,10 @@ var __defProp = Object.defineProperty;
5012
5422
  children: hiPriv ? "高权限:开" : "高权限:关"
5013
5423
  }
5014
5424
  ),
5015
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
5425
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
5016
5426
  ] }),
5017
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
5018
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5427
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
5428
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5019
5429
  "input",
5020
5430
  {
5021
5431
  value: filter,
@@ -5024,14 +5434,14 @@ var __defProp = Object.defineProperty;
5024
5434
  style: { ...S.input, width: 250, fontSize: 12 }
5025
5435
  }
5026
5436
  ),
5027
- filter ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
5028
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
5029
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5030
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
5031
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
5437
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
5438
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
5439
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5440
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
5441
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
5032
5442
  ] }),
5033
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5034
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5443
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5444
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5035
5445
  "input",
5036
5446
  {
5037
5447
  value: regSlug,
@@ -5041,7 +5451,7 @@ var __defProp = Object.defineProperty;
5041
5451
  style: { ...S.input, width: 210, fontSize: 12 }
5042
5452
  }
5043
5453
  ),
5044
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5454
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5045
5455
  "input",
5046
5456
  {
5047
5457
  value: regLabel,
@@ -5051,7 +5461,7 @@ var __defProp = Object.defineProperty;
5051
5461
  style: { ...S.input, width: 110, fontSize: 12 }
5052
5462
  }
5053
5463
  ),
5054
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5464
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5055
5465
  "input",
5056
5466
  {
5057
5467
  value: regDesc,
@@ -5061,7 +5471,7 @@ var __defProp = Object.defineProperty;
5061
5471
  style: { ...S.input, width: 170, fontSize: 12 }
5062
5472
  }
5063
5473
  ),
5064
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5474
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5065
5475
  "button",
5066
5476
  {
5067
5477
  type: "button",
@@ -5071,26 +5481,26 @@ var __defProp = Object.defineProperty;
5071
5481
  children: "注册"
5072
5482
  }
5073
5483
  ),
5074
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5484
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5075
5485
  ] }),
5076
- 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: [
5077
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
5486
+ 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: [
5487
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5078
5488
  "编辑 ",
5079
5489
  editing.slug
5080
5490
  ] }),
5081
- /* @__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 } }),
5082
- /* @__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 } }),
5083
- /* @__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: "保存" }),
5084
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
5491
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: editing.label, onChange: (ev) => setEditing({ ...editing, label: ev.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
5492
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { value: editing.description, onChange: (ev) => setEditing({ ...editing, description: ev.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5493
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
5494
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
5085
5495
  ] }) : null,
5086
- 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: [
5087
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
5496
+ form ? /* @__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: [
5497
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5088
5498
  form.action === "merge" ? "合并" : "归类/改名",
5089
5499
  " ",
5090
5500
  form.from,
5091
5501
  " →"
5092
5502
  ] }),
5093
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5503
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5094
5504
  "input",
5095
5505
  {
5096
5506
  value: form.to,
@@ -5100,7 +5510,7 @@ var __defProp = Object.defineProperty;
5100
5510
  style: { ...S.input, width: 190, fontSize: 12 }
5101
5511
  }
5102
5512
  ),
5103
- 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)(
5513
+ form.action === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime20.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_runtime20.jsx)(
5104
5514
  "button",
5105
5515
  {
5106
5516
  type: "button",
@@ -5111,32 +5521,32 @@ var __defProp = Object.defineProperty;
5111
5521
  },
5112
5522
  gg.hall
5113
5523
  )) }) : null,
5114
- /* @__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: "预览" }),
5115
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => {
5524
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => previewMerge(), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
5525
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => {
5116
5526
  setForm(null);
5117
5527
  setPreview(null);
5118
5528
  setPicking(null);
5119
5529
  }, style: btn, children: "取消" }),
5120
- picking ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
5121
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5530
+ picking ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
5531
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5122
5532
  ] }) : null,
5123
- 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: [
5124
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { children: preview.notice }),
5125
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
5126
- /* @__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: [
5533
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime20.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: [
5534
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { children: preview.notice }),
5535
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
5536
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", disabled: busy, onClick: execMerge, style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: [
5127
5537
  "确认执行",
5128
5538
  preview.action === "merge" ? "合并" : "归类/改名"
5129
5539
  ] }),
5130
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5540
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5131
5541
  ] })
5132
5542
  ] }) : null,
5133
- msg ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: msg }) : null,
5134
- error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
5135
- 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,
5136
- 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) => {
5543
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.hint, children: msg }) : null,
5544
+ error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5545
+ ghost ? /* @__PURE__ */ (0, import_jsx_runtime20.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,
5546
+ visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: S.intro, children: normFilter ? "无匹配的 hall/room。" : "注册表为空。在上方注册 Hall/Room(如 dsh-plugin),或把自生长 slug「收编」进词表 —— 之后候选标注器会优先把相关记忆挂到这些 slug 上。" }) : visibleGroups.map((g) => {
5137
5547
  const hallOpen = !!normFilter || expandedHalls.has(g.hall);
5138
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
5139
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5548
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
5549
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5140
5550
  "div",
5141
5551
  {
5142
5552
  "data-hall": g.hall,
@@ -5177,7 +5587,7 @@ var __defProp = Object.defineProperty;
5177
5587
  },
5178
5588
  title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
5179
5589
  children: [
5180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5590
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5181
5591
  "button",
5182
5592
  {
5183
5593
  type: "button",
@@ -5190,13 +5600,13 @@ var __defProp = Object.defineProperty;
5190
5600
  children: hallOpen ? "▾" : "▸"
5191
5601
  }
5192
5602
  ),
5193
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5603
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5194
5604
  g.hall,
5195
- g.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5605
+ g.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5196
5606
  ] }),
5197
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
5198
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5199
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5607
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
5608
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5609
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5200
5610
  "button",
5201
5611
  {
5202
5612
  type: "button",
@@ -5217,10 +5627,10 @@ var __defProp = Object.defineProperty;
5217
5627
  const standalone = e.slug === g.hall;
5218
5628
  const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
5219
5629
  const retired = e.status === "retired";
5220
- 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: [
5221
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5222
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5223
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5630
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { padding: "4px 10px", borderTop: "1px solid var(--dsh-mem-border)", opacity: retired ? 0.55 : 1 }, children: [
5631
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5632
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5633
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5224
5634
  "button",
5225
5635
  {
5226
5636
  type: "button",
@@ -5230,7 +5640,7 @@ var __defProp = Object.defineProperty;
5230
5640
  children: expandedRooms.has(e.slug) ? "▾" : "▸"
5231
5641
  }
5232
5642
  ),
5233
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5643
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5234
5644
  "span",
5235
5645
  {
5236
5646
  style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
@@ -5244,20 +5654,20 @@ var __defProp = Object.defineProperty;
5244
5654
  ]
5245
5655
  }
5246
5656
  ),
5247
- e.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: e.label }) : null,
5248
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: count + " 条" }),
5249
- retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5250
- (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
5657
+ e.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: e.label }) : null,
5658
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: count + " 条" }),
5659
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5660
+ (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
5251
5661
  ] }),
5252
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5253
- !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5254
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5662
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5663
+ !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5664
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5255
5665
  setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
5256
5666
  setForm(null);
5257
5667
  setPreview(null);
5258
5668
  setPicking(null);
5259
5669
  }, style: btn, children: "编辑" }),
5260
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5670
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5261
5671
  "button",
5262
5672
  {
5263
5673
  type: "button",
@@ -5278,43 +5688,43 @@ var __defProp = Object.defineProperty;
5278
5688
  children: picking === e.slug ? "选 hall…" : "归类"
5279
5689
  }
5280
5690
  ),
5281
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5691
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5282
5692
  setForm({ action: "rename", from: e.slug, to: "" });
5283
5693
  setPreview(null);
5284
5694
  }, style: btn, children: "改名" }),
5285
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5695
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5286
5696
  setForm({ action: "merge", from: e.slug, to: "" });
5287
5697
  setPreview(null);
5288
5698
  }, style: btn, children: "合并" }),
5289
- /* @__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 ? "恢复" : "退役" }),
5290
- !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
5699
+ /* @__PURE__ */ (0, import_jsx_runtime20.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 ? "恢复" : "退役" }),
5700
+ !retired ? /* @__PURE__ */ (0, import_jsx_runtime20.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
5291
5701
  ] }),
5292
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5702
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5293
5703
  ] })
5294
5704
  ] }),
5295
- 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: [
5296
- (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: [
5297
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5705
+ expandedRooms.has(e.slug) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { margin: "4px 0 2px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
5706
+ (roomRecords[e.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: [
5707
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5298
5708
  " ",
5299
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5300
- /* @__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 })
5709
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5710
+ /* @__PURE__ */ (0, import_jsx_runtime20.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 })
5301
5711
  ] }, it.id)),
5302
- (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
5303
- (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
5712
+ (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
5713
+ (roomRecords[e.slug]?.total ?? 0) > (roomRecords[e.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + roomRecords[e.slug].total + " 条,仅显示前 " + roomRecords[e.slug].items.length + " 条" }) : null
5304
5714
  ] }) : null
5305
5715
  ] }, e.slug);
5306
5716
  }) : null
5307
5717
  ] }, g.hall);
5308
5718
  }),
5309
- visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: 4 }, children: [
5310
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
5719
+ visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginTop: 4 }, children: [
5720
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
5311
5721
  grownOpen ? "▾" : "▸",
5312
5722
  " 自生长未注册 · 共 ",
5313
5723
  visibleGrown.length
5314
5724
  ] }),
5315
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
5316
- 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: [
5317
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5725
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
5726
+ grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children: visibleGrown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
5727
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5318
5728
  "span",
5319
5729
  {
5320
5730
  style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
@@ -5325,8 +5735,8 @@ var __defProp = Object.defineProperty;
5325
5735
  children: r.room + " · " + r.count
5326
5736
  }
5327
5737
  ),
5328
- /* @__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: "收编" }),
5329
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5738
+ /* @__PURE__ */ (0, import_jsx_runtime20.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: "收编" }),
5739
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5330
5740
  "button",
5331
5741
  {
5332
5742
  type: "button",
@@ -5353,8 +5763,8 @@ var __defProp = Object.defineProperty;
5353
5763
  }
5354
5764
 
5355
5765
  // client/src/tabs/RoomTab.tsx
5356
- var import_react20 = require("react");
5357
- var import_jsx_runtime20 = require("react/jsx-runtime");
5766
+ var import_react22 = require("react");
5767
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5358
5768
  var btn2 = {
5359
5769
  cursor: "pointer",
5360
5770
  fontSize: 12,
@@ -5375,22 +5785,22 @@ var __defProp = Object.defineProperty;
5375
5785
  }
5376
5786
  function RoomTab(props) {
5377
5787
  const rpc = props.rpc;
5378
- const [registry, setRegistry] = (0, import_react20.useState)([]);
5379
- const [counts, setCounts] = (0, import_react20.useState)([]);
5380
- const [orphanCount, setOrphanCount] = (0, import_react20.useState)(0);
5381
- const [busy, setBusy] = (0, import_react20.useState)(false);
5382
- const [msg, setMsg] = (0, import_react20.useState)(null);
5383
- const [error, setError] = (0, import_react20.useState)(null);
5384
- const [hiPriv, setHiPriv] = (0, import_react20.useState)(false);
5385
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react20.useState)(false);
5386
- const [reg, setReg] = (0, import_react20.useState)({ slug: "", label: "", description: "" });
5387
- const [editing, setEditing] = (0, import_react20.useState)(null);
5388
- const [renaming, setRenaming] = (0, import_react20.useState)(null);
5389
- const [expanded, setExpanded] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
5390
- const [retiredFilter, setRetiredFilter] = (0, import_react20.useState)("");
5391
- const [filter, setFilter] = (0, import_react20.useState)("");
5392
- const [records, setRecords] = (0, import_react20.useState)({});
5393
- const loadAll = (0, import_react20.useCallback)(() => {
5788
+ const [registry, setRegistry] = (0, import_react22.useState)([]);
5789
+ const [counts, setCounts] = (0, import_react22.useState)([]);
5790
+ const [orphanCount, setOrphanCount] = (0, import_react22.useState)(0);
5791
+ const [busy, setBusy] = (0, import_react22.useState)(false);
5792
+ const [msg, setMsg] = (0, import_react22.useState)(null);
5793
+ const [error, setError] = (0, import_react22.useState)(null);
5794
+ const [hiPriv, setHiPriv] = (0, import_react22.useState)(false);
5795
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react22.useState)(false);
5796
+ const [reg, setReg] = (0, import_react22.useState)({ slug: "", label: "", description: "" });
5797
+ const [editing, setEditing] = (0, import_react22.useState)(null);
5798
+ const [renaming, setRenaming] = (0, import_react22.useState)(null);
5799
+ const [expanded, setExpanded] = (0, import_react22.useState)(/* @__PURE__ */ new Set());
5800
+ const [retiredFilter, setRetiredFilter] = (0, import_react22.useState)("");
5801
+ const [filter, setFilter] = (0, import_react22.useState)("");
5802
+ const [records, setRecords] = (0, import_react22.useState)({});
5803
+ const loadAll = (0, import_react22.useCallback)(() => {
5394
5804
  rpc("dsh-memory/rooms-get", {}).then((r) => {
5395
5805
  if (r && r.ok) {
5396
5806
  setCounts(r.value.rooms ?? []);
@@ -5399,13 +5809,13 @@ var __defProp = Object.defineProperty;
5399
5809
  }
5400
5810
  }).catch(() => void 0);
5401
5811
  }, [rpc]);
5402
- const loadHiPriv = (0, import_react20.useCallback)(() => {
5812
+ const loadHiPriv = (0, import_react22.useCallback)(() => {
5403
5813
  rpc("dsh-memory/settings-get", {}).then((r) => {
5404
5814
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
5405
5815
  }).catch(() => {
5406
5816
  });
5407
5817
  }, [rpc]);
5408
- (0, import_react20.useEffect)(() => {
5818
+ (0, import_react22.useEffect)(() => {
5409
5819
  loadAll();
5410
5820
  loadHiPriv();
5411
5821
  }, [loadAll, loadHiPriv]);
@@ -5547,11 +5957,11 @@ var __defProp = Object.defineProperty;
5547
5957
  const visibleRows = normFilter ? rows.filter(
5548
5958
  (row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
5549
5959
  ) : rows;
5550
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5551
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
5552
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
5553
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5554
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5960
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
5961
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
5962
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
5963
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5964
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5555
5965
  const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
5556
5966
  if (!r.ok) {
5557
5967
  setError(r.error.message);
@@ -5562,7 +5972,7 @@ var __defProp = Object.defineProperty;
5562
5972
  "导出孤儿 · ",
5563
5973
  orphanCount
5564
5974
  ] }),
5565
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5975
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5566
5976
  "button",
5567
5977
  {
5568
5978
  type: "button",
@@ -5573,35 +5983,35 @@ var __defProp = Object.defineProperty;
5573
5983
  children: hiPriv ? "高权限:开" : "高权限:关"
5574
5984
  }
5575
5985
  ),
5576
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5986
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5577
5987
  ] }),
5578
- 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: [
5579
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5988
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime21.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: [
5989
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: S.muted, children: [
5580
5990
  "编辑 ",
5581
5991
  editing.slug
5582
5992
  ] }),
5583
- /* @__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 } }),
5584
- /* @__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 } }),
5585
- /* @__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: "保存" }),
5586
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5993
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { value: editing.label, onChange: (e) => setEditing({ ...editing, label: e.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
5994
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { value: editing.description, onChange: (e) => setEditing({ ...editing, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
5995
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
5996
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5587
5997
  ] }) : null,
5588
- 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: [
5589
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5998
+ renaming ? /* @__PURE__ */ (0, import_jsx_runtime21.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: [
5999
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: S.muted, children: [
5590
6000
  "改名 ",
5591
6001
  renaming.slug,
5592
6002
  " →"
5593
6003
  ] }),
5594
- /* @__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 } }),
5595
- /* @__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: "预览" }),
5596
- /* @__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: "确认执行" }),
5597
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
5598
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
6004
+ /* @__PURE__ */ (0, import_jsx_runtime21.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 } }),
6005
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: previewRename, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
6006
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: execRename, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "确认执行" }),
6007
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
6008
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5599
6009
  ] }) : null,
5600
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
5601
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "退场筛选" }),
6010
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
6011
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "退场筛选" }),
5602
6012
  [["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
5603
6013
  const on = retiredFilter === val;
5604
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6014
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5605
6015
  "button",
5606
6016
  {
5607
6017
  type: "button",
@@ -5621,8 +6031,8 @@ var __defProp = Object.defineProperty;
5621
6031
  val
5622
6032
  );
5623
6033
  }),
5624
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5625
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6034
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
6035
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5626
6036
  "input",
5627
6037
  {
5628
6038
  value: filter,
@@ -5631,24 +6041,24 @@ var __defProp = Object.defineProperty;
5631
6041
  style: { ...S.input, width: 230, fontSize: 12 }
5632
6042
  }
5633
6043
  ),
5634
- filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
6044
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5635
6045
  ] }),
5636
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5637
- /* @__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 } }),
5638
- /* @__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 } }),
5639
- /* @__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 } }),
5640
- /* @__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: "注册" }),
5641
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
6046
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
6047
+ /* @__PURE__ */ (0, import_jsx_runtime21.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 } }),
6048
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { value: reg.label, onChange: (e) => setReg({ ...reg, label: e.target.value }), placeholder: "名称(可中文)", disabled: !hiPriv || busy, style: { ...S.input, width: 110, fontSize: 12 } }),
6049
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { value: reg.description, onChange: (e) => setReg({ ...reg, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: !hiPriv || busy, style: { ...S.input, width: 170, fontSize: 12 } }),
6050
+ /* @__PURE__ */ (0, import_jsx_runtime21.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: "注册" }),
6051
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5642
6052
  ] }),
5643
- msg ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.hint, children: msg }) : null,
5644
- error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5645
- 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) => {
6053
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.hint, children: msg }) : null,
6054
+ error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.error, children: error }) : null,
6055
+ visibleRows.length === 0 ? normFilter ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "无匹配的 Room。" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "暂无 Room:对话/反刍会从标签涌现,或在上方注册。" }) : visibleRows.map((row2) => {
5646
6056
  const e = row2.entry;
5647
6057
  const retired = e?.status === "retired";
5648
6058
  const grownOnly = !e;
5649
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
5650
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
5651
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6059
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
6060
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
6061
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5652
6062
  "button",
5653
6063
  {
5654
6064
  type: "button",
@@ -5658,28 +6068,28 @@ var __defProp = Object.defineProperty;
5658
6068
  children: expanded.has(row2.slug) ? "▾" : "▸"
5659
6069
  }
5660
6070
  ),
5661
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5662
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
6071
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
6072
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
5663
6073
  row2.slug,
5664
6074
  e?.source === "pre-registered" ? " ⭐" : ""
5665
6075
  ] }),
5666
- e?.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: e.label }) : null,
5667
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
5668
- grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
5669
- retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5670
- (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
6076
+ e?.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: e.label }) : null,
6077
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
6078
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
6079
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
6080
+ (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
5671
6081
  ] }),
5672
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5673
- !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5674
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
6082
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
6083
+ !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6084
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5675
6085
  setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
5676
6086
  setRenaming(null);
5677
6087
  }, style: btn2, children: "编辑" }),
5678
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
6088
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5679
6089
  setRenaming({ slug: row2.slug, to: "" });
5680
6090
  setEditing(null);
5681
6091
  }, style: btn2, children: "改名" }),
5682
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6092
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5683
6093
  "button",
5684
6094
  {
5685
6095
  type: "button",
@@ -5690,29 +6100,29 @@ var __defProp = Object.defineProperty;
5690
6100
  children: retired ? "恢复" : "退役"
5691
6101
  }
5692
6102
  ),
5693
- !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
6103
+ !retired ? /* @__PURE__ */ (0, import_jsx_runtime21.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
5694
6104
  ] }),
5695
- grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5696
- /* @__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: "收编" }),
5697
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
6105
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6106
+ /* @__PURE__ */ (0, import_jsx_runtime21.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: "收编" }),
6107
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
5698
6108
  setRenaming(null);
5699
6109
  retire(row2.slug, false, true);
5700
6110
  }, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
5701
6111
  ] }) : null,
5702
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
6112
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5703
6113
  ] })
5704
6114
  ] }),
5705
- 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: [
5706
- (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: [
5707
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
6115
+ expanded.has(row2.slug) ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { margin: "0 10px 6px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
6116
+ (records[row2.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
6117
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5708
6118
  " ",
5709
- it.retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
6119
+ it.retired ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5710
6120
  " ",
5711
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5712
- /* @__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 })
6121
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
6122
+ /* @__PURE__ */ (0, import_jsx_runtime21.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 })
5713
6123
  ] }, it.id)),
5714
- (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
5715
- (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
6124
+ (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
6125
+ (records[row2.slug]?.total ?? 0) > (records[row2.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + records[row2.slug].total + " 条,仅显示前 " + records[row2.slug].items.length + " 条" }) : null
5716
6126
  ] }) : null
5717
6127
  ] }, row2.slug);
5718
6128
  })
@@ -5720,13 +6130,13 @@ var __defProp = Object.defineProperty;
5720
6130
  }
5721
6131
 
5722
6132
  // client/src/tabs/ScenesTab.tsx
5723
- var import_react21 = require("react");
5724
- var import_jsx_runtime21 = require("react/jsx-runtime");
6133
+ var import_react23 = require("react");
6134
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5725
6135
  function SceneCard(props) {
5726
6136
  const s = props.s;
5727
- const [open, setOpen] = (0, import_react21.useState)(false);
5728
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
5729
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6137
+ const [open, setOpen] = (0, import_react23.useState)(false);
6138
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
6139
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5730
6140
  "div",
5731
6141
  {
5732
6142
  style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
@@ -5734,23 +6144,23 @@ var __defProp = Object.defineProperty;
5734
6144
  setOpen(!open);
5735
6145
  },
5736
6146
  children: [
5737
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
5738
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.sceneTitle, children: s.path }),
5739
- s.heat ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
5740
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5741
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
6147
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
6148
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.sceneTitle, children: s.path }),
6149
+ s.heat ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
6150
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.grow }),
6151
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
5742
6152
  ]
5743
6153
  }
5744
6154
  ),
5745
- s.summary ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
5746
- open ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
6155
+ s.summary ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
6156
+ open ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
5747
6157
  ] });
5748
6158
  }
5749
6159
  function ScenesTab(props) {
5750
6160
  const rpc = props.rpc;
5751
- const [items, setItems] = (0, import_react21.useState)(null);
5752
- const [error, setError] = (0, import_react21.useState)(null);
5753
- const load = (0, import_react21.useCallback)(() => {
6161
+ const [items, setItems] = (0, import_react23.useState)(null);
6162
+ const [error, setError] = (0, import_react23.useState)(null);
6163
+ const load = (0, import_react23.useCallback)(() => {
5754
6164
  rpc("dsh-memory/scenes", {}).then((r) => {
5755
6165
  if (r && r.ok) {
5756
6166
  setItems(r.value.items);
@@ -5760,25 +6170,25 @@ var __defProp = Object.defineProperty;
5760
6170
  setError(String(e && e.message || e));
5761
6171
  });
5762
6172
  }, [rpc]);
5763
- (0, import_react21.useEffect)(() => {
6173
+ (0, import_react23.useEffect)(() => {
5764
6174
  load();
5765
6175
  }, [load]);
5766
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
5767
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
5768
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
5769
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
5770
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(NButton, { onClick: load, children: "刷新" })
6176
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
6177
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
6178
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
6179
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.grow }),
6180
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NButton, { onClick: load, children: "刷新" })
5771
6181
  ] }),
5772
- error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.error, children: error }) : null,
5773
- items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
6182
+ error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.error, children: error }) : null,
6183
+ items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
5774
6184
  (items || []).map((s) => {
5775
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SceneCard, { s }, s.path);
6185
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SceneCard, { s }, s.path);
5776
6186
  })
5777
6187
  ] });
5778
6188
  }
5779
6189
 
5780
6190
  // client/src/panel.tsx
5781
- var import_jsx_runtime22 = require("react/jsx-runtime");
6191
+ var import_jsx_runtime23 = require("react/jsx-runtime");
5782
6192
  var TABS = [
5783
6193
  ["overview", "概览"],
5784
6194
  ["records", "记忆"],
@@ -5799,10 +6209,10 @@ var __defProp = Object.defineProperty;
5799
6209
  ];
5800
6210
  function MemoryPanel(props) {
5801
6211
  const rpc = props.rpc;
5802
- const [tab, setTab] = (0, import_react22.useState)("overview");
5803
- const [skin, setSkinState] = (0, import_react22.useState)(() => getSkin());
6212
+ const [tab, setTab] = (0, import_react24.useState)("overview");
6213
+ const [skin, setSkinState] = (0, import_react24.useState)(() => getSkin());
5804
6214
  ensureThemeStyle(skin);
5805
- (0, import_react22.useEffect)(() => {
6215
+ (0, import_react24.useEffect)(() => {
5806
6216
  applySkin(skin);
5807
6217
  watchSidebarIcon();
5808
6218
  }, [skin]);
@@ -5811,21 +6221,21 @@ var __defProp = Object.defineProperty;
5811
6221
  setSkinState(next);
5812
6222
  };
5813
6223
  let body;
5814
- if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(OverviewTab, { rpc });
5815
- else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RecordsTab, { rpc });
5816
- else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConflictsTab, { rpc });
5817
- else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenesTab, { rpc });
5818
- else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomsTab, { rpc });
5819
- else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(RoomTab, { rpc });
5820
- else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PersonaTab, { rpc });
5821
- else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CostTab, { rpc });
5822
- else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConnectTab, { rpc });
5823
- else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SkillsTab, { rpc });
5824
- else body = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LogTab, { rpc });
5825
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
5826
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
5827
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
5828
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
6224
+ if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(OverviewTab, { rpc });
6225
+ else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RecordsTab, { rpc });
6226
+ else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ConflictsTab, { rpc });
6227
+ else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenesTab, { rpc });
6228
+ else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RoomsTab, { rpc });
6229
+ else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RoomTab, { rpc });
6230
+ else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PersonaTab, { rpc });
6231
+ else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CostTab, { rpc });
6232
+ else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ConnectTab, { rpc });
6233
+ else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkillsTab, { rpc });
6234
+ else body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LogTab, { rpc });
6235
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
6236
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
6237
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
6238
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5829
6239
  "div",
5830
6240
  {
5831
6241
  style: {
@@ -5837,8 +6247,8 @@ var __defProp = Object.defineProperty;
5837
6247
  marginBottom: 10
5838
6248
  },
5839
6249
  children: [
5840
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
5841
- SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6250
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
6251
+ SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5842
6252
  "button",
5843
6253
  {
5844
6254
  className: skin === s[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5851,8 +6261,8 @@ var __defProp = Object.defineProperty;
5851
6261
  ]
5852
6262
  }
5853
6263
  ),
5854
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5855
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6264
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
6265
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5856
6266
  "button",
5857
6267
  {
5858
6268
  className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5869,7 +6279,7 @@ var __defProp = Object.defineProperty;
5869
6279
  }
5870
6280
 
5871
6281
  // client/src/pill/MemoryModePill.tsx
5872
- var import_react25 = require("react");
6282
+ var import_react27 = require("react");
5873
6283
 
5874
6284
  // src/util/context-occupancy.ts
5875
6285
  var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
@@ -6185,23 +6595,23 @@ var __defProp = Object.defineProperty;
6185
6595
  }
6186
6596
 
6187
6597
  // client/src/pill/WingWheel.tsx
6188
- var import_react24 = require("react");
6598
+ var import_react26 = require("react");
6189
6599
 
6190
6600
  // client/src/pill/SessionInfoArea.tsx
6191
- var import_react23 = require("react");
6192
- var import_jsx_runtime23 = require("react/jsx-runtime");
6601
+ var import_react25 = require("react");
6602
+ var import_jsx_runtime24 = require("react/jsx-runtime");
6193
6603
  function sinfoCell(val, label, title) {
6194
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { title: title || void 0, children: [
6195
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
6196
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
6604
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { title: title || void 0, children: [
6605
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
6606
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
6197
6607
  ] });
6198
6608
  }
6199
6609
  function SessionInfoArea(props) {
6200
6610
  const rpc = props.rpc;
6201
6611
  const sessionId = props.sessionId;
6202
- const [stats, setStats] = (0, import_react23.useState)(void 0);
6203
- const busyRef = (0, import_react23.useRef)(false);
6204
- (0, import_react23.useEffect)(() => {
6612
+ const [stats, setStats] = (0, import_react25.useState)(void 0);
6613
+ const busyRef = (0, import_react25.useRef)(false);
6614
+ (0, import_react25.useEffect)(() => {
6205
6615
  if (!rpc || !sessionId) return void 0;
6206
6616
  let alive = true;
6207
6617
  let timer = null;
@@ -6234,7 +6644,7 @@ var __defProp = Object.defineProperty;
6234
6644
  }, [rpc, sessionId]);
6235
6645
  if (stats === null) return null;
6236
6646
  if (stats === void 0) {
6237
- 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: [
6647
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6238
6648
  sinfoCell("…", "召回命中"),
6239
6649
  sinfoCell("…", "攒批进度"),
6240
6650
  sinfoCell("…", "本会话记忆"),
@@ -6283,21 +6693,21 @@ var __defProp = Object.defineProperty;
6283
6693
  else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
6284
6694
  }
6285
6695
  const ago = fmtAgo(gl.lastExtractAt);
6286
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6287
- warn ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
6288
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6696
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6697
+ warn ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
6698
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6289
6699
  sinfoCell(rcVal, rcLabel, rcTitle),
6290
6700
  sinfoCell(dVal, dLabel, dTitle),
6291
6701
  sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
6292
6702
  sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
6293
6703
  ] }),
6294
- note ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
6295
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
6704
+ note ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
6705
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
6296
6706
  ] });
6297
6707
  }
6298
6708
 
6299
6709
  // client/src/pill/WingWheel.tsx
6300
- var import_jsx_runtime24 = require("react/jsx-runtime");
6710
+ var import_jsx_runtime25 = require("react/jsx-runtime");
6301
6711
  var SIZE = 196;
6302
6712
  var CENTER = SIZE / 2;
6303
6713
  var R = 64;
@@ -6340,19 +6750,8 @@ var __defProp = Object.defineProperty;
6340
6750
  function WingWheel(props) {
6341
6751
  ensureThemeStyle();
6342
6752
  const isOff = props.mode === "off";
6343
- const [overview, setOverview] = (0, import_react24.useState)(null);
6344
- const [backfillBusy, setBackfillBusy] = (0, import_react24.useState)(false);
6345
- const [kwBusy, setKwBusy] = (0, import_react24.useState)(false);
6346
- const [kwSummary, setKwSummary] = (0, import_react24.useState)(null);
6347
- const [localError, setLocalError] = (0, import_react24.useState)(null);
6348
- const timersRef = (0, import_react24.useRef)([]);
6349
- (0, import_react24.useEffect)(
6350
- () => () => {
6351
- for (const t of timersRef.current) window.clearTimeout(t);
6352
- },
6353
- []
6354
- );
6355
- (0, import_react24.useEffect)(() => {
6753
+ const [overview, setOverview] = (0, import_react26.useState)(null);
6754
+ (0, import_react26.useEffect)(() => {
6356
6755
  let alive = true;
6357
6756
  props.rpc("dsh-memory/wing-overview", {}).then((r) => {
6358
6757
  if (!alive) return;
@@ -6368,110 +6767,28 @@ var __defProp = Object.defineProperty;
6368
6767
  if (id === "general") return overview.general;
6369
6768
  return overview.corners.find((c) => c.id === id)?.count ?? 0;
6370
6769
  };
6371
- const backfill = () => {
6372
- if (backfillBusy || !overview || overview.unlabeled === 0) return;
6373
- setBackfillBusy(true);
6374
- setLocalError(null);
6375
- let polls = 0;
6376
- const finish = () => setBackfillBusy(false);
6377
- const tick = () => {
6378
- polls++;
6379
- props.rpc("dsh-memory/wing-overview", {}).then((r) => {
6380
- const v = r && r.ok ? r.value : null;
6381
- if (v) setOverview(v);
6382
- if (v && v.unlabeled === 0 || polls >= 20) finish();
6383
- else {
6384
- const t = window.setTimeout(tick, 3e3);
6385
- timersRef.current.push(t);
6386
- }
6387
- }).catch(() => finish());
6388
- };
6389
- props.rpc("dsh-memory/wing-backfill", {}).then((r) => {
6390
- if (!r || !r.ok) {
6391
- setLocalError(r && r.error ? "回填失败:" + r.error.message : "回填失败");
6392
- finish();
6393
- return;
6394
- }
6395
- timersRef.current.push(window.setTimeout(tick, 3e3));
6396
- }).catch((e) => {
6397
- setLocalError("回填失败:" + String(e && e.message || e));
6398
- finish();
6399
- });
6400
- };
6401
- const keywordBackfill = () => {
6402
- if (kwBusy) return;
6403
- setKwBusy(true);
6404
- setKwSummary(null);
6405
- setLocalError(null);
6406
- let polls = 0;
6407
- const finish = () => setKwBusy(false);
6408
- const showResult = (v) => {
6409
- const fail = v.failed ?? 0;
6410
- setKwSummary(`关键词回填完成:成功 ${v.updated ?? 0} 条${fail > 0 ? `,失败 ${fail} 条` : ""}`);
6411
- };
6412
- const failMsg = (m) => {
6413
- setLocalError(m);
6414
- finish();
6415
- };
6416
- const tick = () => {
6417
- polls++;
6418
- props.rpc("dsh-memory/keyword-backfill", {}).then((r) => {
6419
- const v = r && r.ok ? r.value : null;
6420
- if (!v) {
6421
- failMsg("关键词回填失败");
6422
- return;
6423
- }
6424
- if (!v.enabled) {
6425
- failMsg("关键词回填未开启:请先在设置里打开 keyword.enabled");
6426
- return;
6427
- }
6428
- if (!v.running) {
6429
- showResult(v);
6430
- finish();
6431
- return;
6432
- }
6433
- if (polls >= 20) {
6434
- showResult(v);
6435
- finish();
6436
- return;
6437
- }
6438
- timersRef.current.push(window.setTimeout(tick, 3e3));
6439
- }).catch(() => failMsg("关键词回填失败"));
6440
- };
6441
- props.rpc("dsh-memory/keyword-backfill", {}).then((r) => {
6442
- if (!r || !r.ok) {
6443
- failMsg(r && r.error ? "关键词回填失败:" + r.error.message : "关键词回填失败");
6444
- return;
6445
- }
6446
- if (!r.value || !r.value.enabled) {
6447
- failMsg("关键词回填未开启:请先在设置里打开 keyword.enabled");
6448
- return;
6449
- }
6450
- timersRef.current.push(window.setTimeout(tick, 3e3));
6451
- }).catch((e) => failMsg("关键词回填失败:" + String(e && e.message || e)));
6452
- };
6453
- const boxRef = (0, import_react24.useRef)(null);
6454
- const startRef = (0, import_react24.useRef)(null);
6455
- const movedRef = (0, import_react24.useRef)(false);
6456
- const downIndexRef = (0, import_react24.useRef)(null);
6457
- const dragTargetRef = (0, import_react24.useRef)(null);
6458
- const [drag, setDrag] = (0, import_react24.useState)(null);
6770
+ const boxRef = (0, import_react26.useRef)(null);
6771
+ const startRef = (0, import_react26.useRef)(null);
6772
+ const movedRef = (0, import_react26.useRef)(false);
6773
+ const downIndexRef = (0, import_react26.useRef)(null);
6774
+ const dragTargetRef = (0, import_react26.useRef)(null);
6775
+ const [drag, setDrag] = (0, import_react26.useState)(null);
6459
6776
  const lockedIndex = (() => {
6460
6777
  if (props.halls.length !== 1 || !overview) return null;
6461
6778
  const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
6462
6779
  return i >= 0 ? i : null;
6463
6780
  })();
6464
6781
  const activeCorner = drag ? drag.index : lockedIndex;
6465
- const blockPosRef = (0, import_react24.useRef)(
6782
+ const blockPosRef = (0, import_react26.useRef)(
6466
6783
  activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
6467
6784
  );
6468
- const blockTargetRef = (0, import_react24.useRef)(blockPosRef.current);
6469
- const [blockPos, setBlockPos] = (0, import_react24.useState)(blockPosRef.current);
6470
- (0, import_react24.useEffect)(() => {
6785
+ const blockTargetRef = (0, import_react26.useRef)(blockPosRef.current);
6786
+ const [blockPos, setBlockPos] = (0, import_react26.useState)(blockPosRef.current);
6787
+ (0, import_react26.useEffect)(() => {
6471
6788
  blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
6472
6789
  }, [activeCorner]);
6473
- const reducedMotionRef = (0, import_react24.useRef)(false);
6474
- (0, import_react24.useEffect)(() => {
6790
+ const reducedMotionRef = (0, import_react26.useRef)(false);
6791
+ (0, import_react26.useEffect)(() => {
6475
6792
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
6476
6793
  const apply2 = () => {
6477
6794
  reducedMotionRef.current = mq.matches;
@@ -6480,7 +6797,7 @@ var __defProp = Object.defineProperty;
6480
6797
  mq.addEventListener("change", apply2);
6481
6798
  return () => mq.removeEventListener("change", apply2);
6482
6799
  }, []);
6483
- (0, import_react24.useEffect)(() => {
6800
+ (0, import_react26.useEffect)(() => {
6484
6801
  let raf = 0;
6485
6802
  const loop = () => {
6486
6803
  const cur = blockPosRef.current;
@@ -6569,8 +6886,8 @@ var __defProp = Object.defineProperty;
6569
6886
  }).join(" ");
6570
6887
  const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
6571
6888
  const boundariesDisabled = props.halls.length === 0 || isOff;
6572
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { width: SIZE }, children: [
6573
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6889
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { width: SIZE }, children: [
6890
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6574
6891
  "div",
6575
6892
  {
6576
6893
  ref: boxRef,
@@ -6580,7 +6897,7 @@ var __defProp = Object.defineProperty;
6580
6897
  onPointerUp: onBoxUp,
6581
6898
  onPointerCancel: onBoxUp,
6582
6899
  children: [
6583
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6900
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6584
6901
  "svg",
6585
6902
  {
6586
6903
  width: SIZE,
@@ -6588,7 +6905,7 @@ var __defProp = Object.defineProperty;
6588
6905
  style: { position: "absolute", inset: 0, pointerEvents: "none" },
6589
6906
  "aria-hidden": "true",
6590
6907
  children: [
6591
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6908
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6592
6909
  "polygon",
6593
6910
  {
6594
6911
  points: polyPoints,
@@ -6599,7 +6916,7 @@ var __defProp = Object.defineProperty;
6599
6916
  opacity: 0.45
6600
6917
  }
6601
6918
  ),
6602
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6919
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6603
6920
  "polygon",
6604
6921
  {
6605
6922
  points: polyPoints,
@@ -6610,7 +6927,7 @@ var __defProp = Object.defineProperty;
6610
6927
  ),
6611
6928
  [0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
6612
6929
  const p = cornerPos(i);
6613
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6930
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6614
6931
  "line",
6615
6932
  {
6616
6933
  x1: CENTER,
@@ -6626,7 +6943,7 @@ var __defProp = Object.defineProperty;
6626
6943
  ]
6627
6944
  }
6628
6945
  ),
6629
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6946
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6630
6947
  "div",
6631
6948
  {
6632
6949
  "aria-hidden": "true",
@@ -6645,7 +6962,7 @@ var __defProp = Object.defineProperty;
6645
6962
  }
6646
6963
  }
6647
6964
  ),
6648
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6965
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6649
6966
  "button",
6650
6967
  {
6651
6968
  type: "button",
@@ -6679,7 +6996,7 @@ var __defProp = Object.defineProperty;
6679
6996
  const dim = activeCorner != null && !active;
6680
6997
  const empty = count === 0;
6681
6998
  const p = cornerPos(i);
6682
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6999
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6683
7000
  "div",
6684
7001
  {
6685
7002
  title: id ? `「${label}」${count ?? 0} 条
@@ -6708,8 +7025,8 @@ var __defProp = Object.defineProperty;
6708
7025
  zIndex: 2
6709
7026
  },
6710
7027
  children: [
6711
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: label }),
6712
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
7028
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }),
7029
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
6713
7030
  ]
6714
7031
  },
6715
7032
  id ?? i
@@ -6718,7 +7035,7 @@ var __defProp = Object.defineProperty;
6718
7035
  ]
6719
7036
  }
6720
7037
  ),
6721
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7038
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6722
7039
  "div",
6723
7040
  {
6724
7041
  title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
@@ -6732,9 +7049,9 @@ var __defProp = Object.defineProperty;
6732
7049
  pointerEvents: boundariesDisabled ? "none" : void 0
6733
7050
  },
6734
7051
  children: [
6735
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
6736
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
6737
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7052
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
7053
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
7054
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6738
7055
  Segmented,
6739
7056
  {
6740
7057
  value: props.hallIncludeUnlabeled ? "in" : "ex",
@@ -6745,7 +7062,7 @@ var __defProp = Object.defineProperty;
6745
7062
  onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
6746
7063
  }
6747
7064
  ),
6748
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7065
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6749
7066
  Segmented,
6750
7067
  {
6751
7068
  value: props.hallIncludeGeneral ? "in" : "ex",
@@ -6760,7 +7077,7 @@ var __defProp = Object.defineProperty;
6760
7077
  ]
6761
7078
  }
6762
7079
  ),
6763
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7080
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6764
7081
  Segmented,
6765
7082
  {
6766
7083
  value: isOff ? "off" : "on",
@@ -6775,7 +7092,7 @@ var __defProp = Object.defineProperty;
6775
7092
  onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
6776
7093
  }
6777
7094
  ) }),
6778
- props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7095
+ props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6779
7096
  Segmented,
6780
7097
  {
6781
7098
  value: props.recall === null ? "follow" : props.recall ? "on" : "off",
@@ -6788,60 +7105,12 @@ var __defProp = Object.defineProperty;
6788
7105
  onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
6789
7106
  }
6790
7107
  ) }) : null,
6791
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6792
- "div",
6793
- {
6794
- style: {
6795
- display: "flex",
6796
- justifyContent: "space-between",
6797
- alignItems: "center",
6798
- gap: 8,
6799
- marginTop: 10
6800
- },
6801
- children: [
6802
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
6803
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6804
- ActionButton,
6805
- {
6806
- label: backfillBusy ? "回填中…" : "回填",
6807
- title: "对存量未打标记忆批量补打 wing 标签",
6808
- disabled: !overview || overview.unlabeled === 0 || backfillBusy,
6809
- onClick: () => backfill()
6810
- }
6811
- )
6812
- ]
6813
- }
6814
- ),
6815
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6816
- "div",
6817
- {
6818
- style: {
6819
- display: "flex",
6820
- justifyContent: "space-between",
6821
- alignItems: "center",
6822
- gap: 8,
6823
- marginTop: 10
6824
- },
6825
- children: [
6826
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: kwSummary || "为存量记忆补检索关键词" }),
6827
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6828
- ActionButton,
6829
- {
6830
- label: kwBusy ? "回填中…" : "关键词回填",
6831
- title: "对缺 dsh_keywords 的存量记忆批量补关键词,喂 FTS 关键词检索轴(需先开 keyword.enabled)",
6832
- disabled: kwBusy,
6833
- onClick: () => keywordBackfill()
6834
- }
6835
- )
6836
- ]
6837
- }
6838
- ),
6839
- 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,
6840
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
7108
+ props.error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error }) : null,
7109
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
6841
7110
  ] });
6842
7111
  }
6843
7112
  function Row(props) {
6844
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7113
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6845
7114
  "div",
6846
7115
  {
6847
7116
  style: {
@@ -6851,7 +7120,7 @@ var __defProp = Object.defineProperty;
6851
7120
  marginTop: 10
6852
7121
  },
6853
7122
  children: [
6854
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
7123
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6855
7124
  props.children
6856
7125
  ]
6857
7126
  }
@@ -6859,9 +7128,9 @@ var __defProp = Object.defineProperty;
6859
7128
  }
6860
7129
  var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
6861
7130
  function useViewportClamp(popRef) {
6862
- const shiftRef = (0, import_react24.useRef)(0);
6863
- const [shiftX, setShiftX] = (0, import_react24.useState)(0);
6864
- (0, import_react24.useEffect)(() => {
7131
+ const shiftRef = (0, import_react26.useRef)(0);
7132
+ const [shiftX, setShiftX] = (0, import_react26.useState)(0);
7133
+ (0, import_react26.useEffect)(() => {
6865
7134
  const clamp = () => {
6866
7135
  const el = popRef.current;
6867
7136
  if (!el) return;
@@ -6891,24 +7160,24 @@ var __defProp = Object.defineProperty;
6891
7160
  }
6892
7161
 
6893
7162
  // client/src/pill/MemoryModePill.tsx
6894
- var import_jsx_runtime25 = require("react/jsx-runtime");
7163
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6895
7164
  function MemoryModePill(props) {
6896
7165
  const rpc = props.rpc;
6897
7166
  const sessionId = props.sessionId || props.session && props.session.sessionId;
6898
- const [mode, setMode] = (0, import_react25.useState)(null);
6899
- const [recall, setRecall] = (0, import_react25.useState)(null);
6900
- const [recallResolved, setRecallResolved] = (0, import_react25.useState)(true);
6901
- const [halls, setWings] = (0, import_react25.useState)([]);
6902
- const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react25.useState)(true);
6903
- const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react25.useState)(false);
6904
- const [wingLabels, setHallLabels] = (0, import_react25.useState)({});
6905
- const [error, setError] = (0, import_react25.useState)(null);
6906
- const [open, setOpen] = (0, import_react25.useState)(false);
6907
- const wrapRef = (0, import_react25.useRef)(null);
6908
- const popRef = (0, import_react25.useRef)(null);
7167
+ const [mode, setMode] = (0, import_react27.useState)(null);
7168
+ const [recall, setRecall] = (0, import_react27.useState)(null);
7169
+ const [recallResolved, setRecallResolved] = (0, import_react27.useState)(true);
7170
+ const [halls, setWings] = (0, import_react27.useState)([]);
7171
+ const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react27.useState)(true);
7172
+ const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react27.useState)(false);
7173
+ const [wingLabels, setHallLabels] = (0, import_react27.useState)({});
7174
+ const [error, setError] = (0, import_react27.useState)(null);
7175
+ const [open, setOpen] = (0, import_react27.useState)(false);
7176
+ const wrapRef = (0, import_react27.useRef)(null);
7177
+ const popRef = (0, import_react27.useRef)(null);
6909
7178
  const shiftX = useViewportClamp(popRef);
6910
- const seqRef = (0, import_react25.useRef)(0);
6911
- const load = (0, import_react25.useCallback)(() => {
7179
+ const seqRef = (0, import_react27.useRef)(0);
7180
+ const load = (0, import_react27.useCallback)(() => {
6912
7181
  if (!sessionId || !rpc) return;
6913
7182
  const token = ++seqRef.current;
6914
7183
  setError(null);
@@ -6933,13 +7202,13 @@ var __defProp = Object.defineProperty;
6933
7202
  }).catch(() => {
6934
7203
  });
6935
7204
  }, [sessionId, rpc]);
6936
- (0, import_react25.useEffect)(() => {
7205
+ (0, import_react27.useEffect)(() => {
6937
7206
  load();
6938
7207
  }, [load]);
6939
- (0, import_react25.useEffect)(() => {
7208
+ (0, import_react27.useEffect)(() => {
6940
7209
  watchSidebarIcon();
6941
7210
  }, []);
6942
- (0, import_react25.useEffect)(() => {
7211
+ (0, import_react27.useEffect)(() => {
6943
7212
  initOccupancyIndicator(
6944
7213
  (endpoint, payload) => rpc(endpoint, payload)
6945
7214
  );
@@ -6947,7 +7216,7 @@ var __defProp = Object.defineProperty;
6947
7216
  watchContextMeter();
6948
7217
  noteOccupancySession(sessionId ?? null);
6949
7218
  }, [sessionId, rpc]);
6950
- (0, import_react25.useEffect)(() => {
7219
+ (0, import_react27.useEffect)(() => {
6951
7220
  if (!open) return;
6952
7221
  const onDown = (e) => {
6953
7222
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -7087,8 +7356,8 @@ var __defProp = Object.defineProperty;
7087
7356
  pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
7088
7357
  pillStyle["--dsh-mem-pill-tint"] = info.color;
7089
7358
  }
7090
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
7091
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
7359
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
7360
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
7092
7361
  "button",
7093
7362
  {
7094
7363
  type: "button",
@@ -7101,11 +7370,11 @@ var __defProp = Object.defineProperty;
7101
7370
  style: pillStyle,
7102
7371
  children: [
7103
7372
  "记忆 · ",
7104
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: faceLabel })
7373
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: faceLabel })
7105
7374
  ]
7106
7375
  }
7107
7376
  ),
7108
- open ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7377
+ open ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7109
7378
  "div",
7110
7379
  {
7111
7380
  ref: popRef,
@@ -7116,12 +7385,12 @@ var __defProp = Object.defineProperty;
7116
7385
  transform: "translateX(calc(-50% + " + shiftX + "px))",
7117
7386
  zIndex: 1e3
7118
7387
  },
7119
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7388
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7120
7389
  "div",
7121
7390
  {
7122
7391
  className: "dsh-mem-popover",
7123
7392
  style: { position: "relative", padding: "10px 12px" },
7124
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7393
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7125
7394
  WingWheel,
7126
7395
  {
7127
7396
  mode: mode || "auto",