dsh-prime-memory 0.25.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,329 @@ 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 [wingAborting, setWingAborting] = (0, import_react16.useState)(false);
3712
+ const [kwAborting, setKwAborting] = (0, import_react16.useState)(false);
3713
+ const [rdAborting, setRdAborting] = (0, import_react16.useState)(false);
3714
+ const wingStopRef = (0, import_react16.useRef)(false);
3715
+ const timersRef = (0, import_react16.useRef)([]);
3716
+ (0, import_react16.useEffect)(
3717
+ () => () => {
3718
+ for (const t of timersRef.current) window.clearTimeout(t);
3719
+ },
3720
+ []
3721
+ );
3722
+ const refreshOverview = (0, import_react16.useCallback)(() => {
3723
+ rpc("dsh-memory/wing-overview", {}).then((r) => {
3724
+ if (r && r.ok) setOverview(r.value);
3725
+ }).catch(() => {
3726
+ });
3727
+ }, [rpc]);
3728
+ (0, import_react16.useEffect)(() => {
3729
+ refreshOverview();
3730
+ }, [refreshOverview]);
3731
+ ensureThemeStyle();
3732
+ const POLL_CAP = 400;
3733
+ const fmtProgress = (p, verb, counts, aborting = false) => {
3734
+ if (aborting) return `${verb}:正在中止——先等在跑的那条收工,超时即强行中断(已写回的保留)…`;
3735
+ if (!p) return `${verb}中…`;
3736
+ if (p.scanning) {
3737
+ return p.scanTotal > 0 ? `${verb}中:正在扫描存量 ${p.scanned}/${p.scanTotal} 行,筛出需${verb}的记录…` : `${verb}中:正在扫描活跃存量(已扫 ${p.scanned} 行),筛出需${verb}的记录…`;
3738
+ }
3739
+ if (p.candidates === 0) return `${verb}中:扫描完成,没有需要${verb}的记录…`;
3740
+ const parts = [
3741
+ `${verb}中:真目标 ${p.candidates} 条`,
3742
+ `已完成 ${p.processed} 条`,
3743
+ p.batchTotal > 0 ? `第 ${Math.min(p.batchesDone + 1, p.batchTotal)}/${p.batchTotal} 条` : "",
3744
+ p.concurrency > 1 ? `并行 ${p.concurrency}` : "串行",
3745
+ (counts?.failed ?? 0) > 0 ? `失败 ${counts.failed} 条` : ""
3746
+ ].filter(Boolean);
3747
+ const outcome = counts ? `(写回 ${counts.updated ?? 0}${counts.skipped !== void 0 ? ` / 留原文 ${counts.skipped}` : ""})` : "";
3748
+ return parts.join(" · ") + outcome;
3749
+ };
3750
+ const tail = (p) => p && p.cancelled ? `,已中止、剩 ${p.deferred} 条待再点一次` : p && p.deferred > 0 ? `,本次未跑完、剩 ${p.deferred} 条待再点一次` : "";
3751
+ const wingBackfill = (mode = "start") => {
3752
+ if (wingBusy) return;
3753
+ if (mode === "start" && (!overview || overview.unlabeled === 0)) return;
3754
+ if (mode === "start") setWingBusy(true);
3755
+ setErr(null);
3756
+ wingStopRef.current = false;
3757
+ setWingAborting(false);
3758
+ let polls = 0;
3759
+ const finish = () => setWingBusy(false);
3760
+ const tick = () => {
3761
+ if (wingStopRef.current) return;
3762
+ polls++;
3763
+ rpc("dsh-memory/wing-overview", {}).then((r) => {
3764
+ const v = r && r.ok ? r.value : null;
3765
+ if (v) setOverview(v);
3766
+ if (v && v.unlabeled === 0 || polls >= POLL_CAP) finish();
3767
+ else timersRef.current.push(window.setTimeout(tick, 3e3));
3768
+ }).catch(() => finish());
3769
+ };
3770
+ rpc("dsh-memory/wing-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3771
+ if (!r || !r.ok) {
3772
+ if (mode === "resume") return finish();
3773
+ setErr(r && r.error ? "回填失败:" + r.error.message : "回填失败");
3774
+ finish();
3775
+ return;
3776
+ }
3777
+ if (mode === "resume") {
3778
+ if (!(r.value && r.value.running)) return;
3779
+ setWingBusy(true);
3780
+ }
3781
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3782
+ }).catch((e) => {
3783
+ if (mode === "resume") return finish();
3784
+ setErr("回填失败:" + String(e && e.message || e));
3785
+ finish();
3786
+ });
3787
+ };
3788
+ const keywordBackfill = (mode = "start") => {
3789
+ if (kwBusy) return;
3790
+ if (mode === "start") {
3791
+ setKwBusy(true);
3792
+ setKwSummary(null);
3793
+ setKwProgress(null);
3794
+ setKwCounts(null);
3795
+ setKwAborting(false);
3796
+ }
3797
+ setErr(null);
3798
+ let polls = 0;
3799
+ let last = null;
3800
+ const finish = () => setKwBusy(false);
3801
+ const showResult = (v) => {
3802
+ const fail = v.failed ?? 0;
3803
+ if (last && !last.cancelled && last.candidates === 0) {
3804
+ setKwSummary("关键词回填:没有缺关键词的记录,无需回填");
3805
+ return;
3806
+ }
3807
+ const head = last?.cancelled ? "关键词回填已中止" : "关键词回填完成";
3808
+ setKwSummary(`${head}:成功 ${v.updated ?? 0} 条${fail > 0 ? `,失败 ${fail} 条` : ""}${tail(last)}`);
3809
+ };
3810
+ const failMsg = (m) => {
3811
+ setErr(m);
3812
+ finish();
3813
+ };
3814
+ const tick = () => {
3815
+ polls++;
3816
+ rpc("dsh-memory/keyword-backfill", { probe: true }).then((r) => {
3817
+ const v = r && r.ok ? r.value : null;
3818
+ if (!v) return failMsg("关键词回填失败");
3819
+ if (v.progress) {
3820
+ last = v.progress;
3821
+ setKwProgress(v.progress);
3822
+ setKwCounts({ updated: v.updated, failed: v.failed });
3823
+ }
3824
+ if (v.running) {
3825
+ if (polls >= POLL_CAP) {
3826
+ showResult(v);
3827
+ return finish();
3828
+ }
3829
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3830
+ return;
3831
+ }
3832
+ if (v.enabled) showResult(v);
3833
+ finish();
3834
+ }).catch(() => failMsg("关键词回填失败"));
3835
+ };
3836
+ rpc("dsh-memory/keyword-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3837
+ if (!r || !r.ok) {
3838
+ if (mode === "resume") return;
3839
+ return failMsg(r && r.error ? "关键词回填失败:" + r.error.message : "关键词回填失败");
3840
+ }
3841
+ const v = r.value;
3842
+ if (!v) {
3843
+ if (mode === "resume") return;
3844
+ return failMsg("关键词回填失败");
3845
+ }
3846
+ if (mode === "resume") {
3847
+ if (!v.running) return;
3848
+ if (v.progress) {
3849
+ last = v.progress;
3850
+ setKwProgress(v.progress);
3851
+ setKwCounts({ updated: v.updated, failed: v.failed });
3852
+ }
3853
+ setKwBusy(true);
3854
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3855
+ return;
3856
+ }
3857
+ if (!v.enabled) return failMsg("关键词回填未开启:请先在概览开关组打开关键词回填");
3858
+ if (v.progress) {
3859
+ last = v.progress;
3860
+ setKwProgress(v.progress);
3861
+ setKwCounts({ updated: v.updated, failed: v.failed });
3862
+ }
3863
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3864
+ }).catch((e) => {
3865
+ if (mode === "resume") return;
3866
+ failMsg("关键词回填失败:" + String(e && e.message || e));
3867
+ });
3868
+ };
3869
+ const redistillBackfill = (mode = "start") => {
3870
+ if (rdBusy) return;
3871
+ if (mode === "start") {
3872
+ setRdBusy(true);
3873
+ setRdSummary(null);
3874
+ setRdProgress(null);
3875
+ setRdCounts(null);
3876
+ setRdAborting(false);
3877
+ }
3878
+ setErr(null);
3879
+ let polls = 0;
3880
+ let last = null;
3881
+ const finish = () => setRdBusy(false);
3882
+ const showResult = (v) => {
3883
+ if (last && !last.cancelled && last.candidates === 0) {
3884
+ setRdSummary("重蒸馏整形:没有需要整形的记录(骨架都已齐备),无需处理");
3885
+ return;
3886
+ }
3887
+ const head = last?.cancelled ? "整形已中止" : "整形完成";
3888
+ setRdSummary(`${head}:写回 ${v.updated ?? 0} 条,留原文 ${v.skipped ?? 0} 条${(v.failed ?? 0) > 0 ? `,失败 ${v.failed} 条` : ""}${tail(last)}`);
3889
+ };
3890
+ const failMsg = (m) => {
3891
+ setErr(m);
3892
+ finish();
3893
+ };
3894
+ const tick = () => {
3895
+ polls++;
3896
+ rpc("dsh-memory/redistill-backfill", { probe: true }).then((r) => {
3897
+ const v = r && r.ok ? r.value : null;
3898
+ if (!v) return failMsg("重蒸馏整形失败");
3899
+ if (v.progress) {
3900
+ last = v.progress;
3901
+ setRdProgress(v.progress);
3902
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3903
+ }
3904
+ if (v.running) {
3905
+ if (polls >= POLL_CAP) {
3906
+ showResult(v);
3907
+ return finish();
3908
+ }
3909
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3910
+ return;
3911
+ }
3912
+ if (v.enabled) showResult(v);
3913
+ finish();
3914
+ }).catch(() => failMsg("重蒸馏整形失败"));
3915
+ };
3916
+ rpc("dsh-memory/redistill-backfill", mode === "resume" ? { probe: true } : {}).then((r) => {
3917
+ if (!r || !r.ok) {
3918
+ if (mode === "resume") return;
3919
+ return failMsg(r && r.error ? "重蒸馏整形失败:" + r.error.message : "重蒸馏整形失败");
3920
+ }
3921
+ const v = r.value;
3922
+ if (!v) {
3923
+ if (mode === "resume") return;
3924
+ return failMsg("重蒸馏整形失败");
3925
+ }
3926
+ if (mode === "resume") {
3927
+ if (!v.running) return;
3928
+ if (v.progress) {
3929
+ last = v.progress;
3930
+ setRdProgress(v.progress);
3931
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3932
+ }
3933
+ setRdBusy(true);
3934
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3935
+ return;
3936
+ }
3937
+ if (!v.enabled) return failMsg("重蒸馏整形未开启:请先在概览开关组打开重蒸馏整形");
3938
+ if (v.progress) {
3939
+ last = v.progress;
3940
+ setRdProgress(v.progress);
3941
+ setRdCounts({ updated: v.updated, skipped: v.skipped, failed: v.failed });
3942
+ }
3943
+ timersRef.current.push(window.setTimeout(tick, 3e3));
3944
+ }).catch((e) => {
3945
+ if (mode === "resume") return;
3946
+ failMsg("重蒸馏整形失败:" + String(e && e.message || e));
3947
+ });
3948
+ };
3949
+ const cancelWing = () => {
3950
+ wingStopRef.current = true;
3951
+ setWingAborting(true);
3952
+ setWingBusy(false);
3953
+ rpc("dsh-memory/wing-backfill", { cancel: true }).catch((e) => {
3954
+ setErr("中止请求失败:" + String(e && e.message || e));
3955
+ });
3956
+ };
3957
+ const cancelKw = () => {
3958
+ setKwAborting(true);
3959
+ rpc("dsh-memory/keyword-backfill", { cancel: true }).catch((e) => {
3960
+ setKwAborting(false);
3961
+ setErr("中止请求失败:" + String(e && e.message || e));
3962
+ });
3963
+ };
3964
+ const cancelRd = () => {
3965
+ setRdAborting(true);
3966
+ rpc("dsh-memory/redistill-backfill", { cancel: true }).catch((e) => {
3967
+ setRdAborting(false);
3968
+ setErr("中止请求失败:" + String(e && e.message || e));
3969
+ });
3970
+ };
3971
+ (0, import_react16.useEffect)(() => {
3972
+ keywordBackfill("resume");
3973
+ redistillBackfill("resume");
3974
+ wingBackfill("resume");
3975
+ }, []);
3976
+ const rowStyle = {
3977
+ display: "flex",
3978
+ alignItems: "center",
3979
+ gap: 10,
3980
+ flexWrap: "wrap",
3981
+ padding: "8px 0"
3982
+ };
3983
+ const hintStyle = { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-3)" };
3984
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-rb-card", style: { padding: "4px 14px", marginTop: 12 }, children: [
3985
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontWeight: 600, padding: "8px 0 2px" }, children: "存量回填与整形" }),
3986
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
3987
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: wingAborting ? "回填:正在中止…" : overview ? `对存量未打标记忆批量补打 wing 标签 · 未打标 ${overview.unlabeled} 条` : "未打标计数加载中…" }),
3988
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3989
+ NButton,
3990
+ {
3991
+ disabled: !wingBusy && (!overview || overview.unlabeled === 0),
3992
+ style: { color: "var(--dsh-mem-accent)" },
3993
+ onClick: () => wingBusy ? cancelWing() : wingBackfill(),
3994
+ children: wingBusy ? "中止" : "wing 回填"
3995
+ }
3996
+ )
3997
+ ] }),
3998
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
3999
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: kwBusy ? fmtProgress(kwProgress, "回填", kwCounts ?? void 0, kwAborting) : kwSummary || "为缺 dsh_keywords 的存量记忆补检索关键词,喂 FTS 关键词轴(需先开关键词回填开关)" }),
4000
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { disabled: kwAborting, style: { color: "var(--dsh-mem-accent)" }, onClick: () => kwBusy ? cancelKw() : keywordBackfill(), children: kwBusy ? kwAborting ? "中止中…" : "中止" : "关键词回填" })
4001
+ ] }),
4002
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: rowStyle, children: [
4003
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: hintStyle, children: rdBusy ? fmtProgress(rdProgress, "整形", rdCounts ?? void 0, rdAborting) : rdSummary || "把“平”的存量记忆按类型重排成分节骨架,顺带产关键词/情景;只有严格更优才写回(需先开重蒸馏整形开关)" }),
4004
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { disabled: rdAborting, style: { color: "var(--dsh-mem-accent)" }, onClick: () => rdBusy ? cancelRd() : redistillBackfill(), children: rdBusy ? rdAborting ? "中止中…" : "中止" : "重蒸馏整形" })
4005
+ ] }),
4006
+ err ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { padding: "6px 0", fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null
4007
+ ] });
4008
+ }
4009
+
4010
+ // client/src/tabs/OverviewTab.tsx
4011
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3720
4012
  function OverviewTab(props) {
3721
4013
  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)(() => {
4014
+ const [stats, setStats] = (0, import_react17.useState)(null);
4015
+ const [settingsData, setSettingsData] = (0, import_react17.useState)(null);
4016
+ const [error, setError] = (0, import_react17.useState)(null);
4017
+ const load = (0, import_react17.useCallback)(() => {
3726
4018
  rpc("dsh-memory/stats", {}).then((r) => {
3727
4019
  if (r && r.ok) setStats(r.value);
3728
4020
  else setError(r && r.error ? r.error.message : "RPC error");
@@ -3734,7 +4026,7 @@ var __defProp = Object.defineProperty;
3734
4026
  }).catch(() => {
3735
4027
  });
3736
4028
  }, [rpc]);
3737
- (0, import_react16.useEffect)(() => {
4029
+ (0, import_react17.useEffect)(() => {
3738
4030
  load();
3739
4031
  const timer = setInterval(load, 5e3);
3740
4032
  return () => {
@@ -3759,6 +4051,23 @@ var __defProp = Object.defineProperty;
3759
4051
  setError("开关写入失败:" + String(e && e.message || e));
3760
4052
  });
3761
4053
  };
4054
+ const setNum = (key, value) => {
4055
+ if (!settingsData) return;
4056
+ const prev = settingsData;
4057
+ const next = { ...prev, settings: { ...prev.settings, [key]: value } };
4058
+ setSettingsData(next);
4059
+ rpc("dsh-memory/settings-set", { [key]: value }).then((r) => {
4060
+ if (!r || !r.ok) {
4061
+ setSettingsData(prev);
4062
+ setError(r && r.error ? "并行度写入失败:" + r.error.message : "并行度写入失败");
4063
+ } else {
4064
+ setError(null);
4065
+ }
4066
+ }).catch((e) => {
4067
+ setSettingsData(prev);
4068
+ setError("并行度写入失败:" + String(e && e.message || e));
4069
+ });
4070
+ };
3762
4071
  const tiles = [];
3763
4072
  const infos = [];
3764
4073
  if (stats) {
@@ -3795,11 +4104,17 @@ var __defProp = Object.defineProperty;
3795
4104
  const toolRuminate = settingsData && settingsData.settings ? settingsData.settings.toolRuminate !== false : true;
3796
4105
  const toolConflict = settingsData && settingsData.settings ? settingsData.settings.toolConflict !== false : true;
3797
4106
  const toolMutate = settingsData && settingsData.settings ? settingsData.settings.toolMutate !== false : true;
4107
+ const toolSkills = settingsData && settingsData.settings ? settingsData.settings.toolSkills !== false : true;
3798
4108
  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)(
4109
+ const keywordEnabled = settingsData && settingsData.settings ? settingsData.settings.keywordEnabled === true : false;
4110
+ const redistillEnabled = settingsData && settingsData.settings ? settingsData.settings.redistillEnabled === true : false;
4111
+ const mdSyncEnabled = settingsData && settingsData.settings ? settingsData.settings.mdSyncEnabled === true : false;
4112
+ const memportEnabled = settingsData && settingsData.settings ? settingsData.settings.memportEnabled === true : false;
4113
+ const bfConcurrency = settingsData && settingsData.settings ? settingsData.settings.backfillConcurrency ?? 0 : 0;
4114
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
4115
+ 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: [
4116
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
4117
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3803
4118
  SwitchRow,
3804
4119
  {
3805
4120
  label: "记忆模式",
@@ -3810,7 +4125,7 @@ var __defProp = Object.defineProperty;
3810
4125
  }
3811
4126
  }
3812
4127
  ),
3813
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4128
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3814
4129
  SwitchRow,
3815
4130
  {
3816
4131
  label: "捕获",
@@ -3822,7 +4137,7 @@ var __defProp = Object.defineProperty;
3822
4137
  }
3823
4138
  }
3824
4139
  ),
3825
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4140
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3826
4141
  SwitchRow,
3827
4142
  {
3828
4143
  label: "蒸馏",
@@ -3834,7 +4149,7 @@ var __defProp = Object.defineProperty;
3834
4149
  }
3835
4150
  }
3836
4151
  ),
3837
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4152
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3838
4153
  SwitchRow,
3839
4154
  {
3840
4155
  label: "召回",
@@ -3846,8 +4161,8 @@ var __defProp = Object.defineProperty;
3846
4161
  }
3847
4162
  }
3848
4163
  ),
3849
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3850
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4164
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
4165
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3851
4166
  SwitchRow,
3852
4167
  {
3853
4168
  label: "高权限模式",
@@ -3858,20 +4173,20 @@ var __defProp = Object.defineProperty;
3858
4173
  }
3859
4174
  }
3860
4175
  ),
3861
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
3862
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4176
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "技能结晶" }),
4177
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3863
4178
  SwitchRow,
3864
4179
  {
3865
4180
  label: "技能(程序性记忆)",
3866
- desc: skillsEnabled ? "已开启:重复工作方法会结晶为技能候选,注入活跃技能,可在「技能」页审阅晋升" : "默认关闭;开启后注册 memory_skill_* 工具与注入(新装工具需重启后完全生效)",
4181
+ desc: skillsEnabled ? "已开启:重复工作方法会结晶为技能候选,注入活跃技能,可在「技能」页审阅晋升" : "默认关闭;开启后注册 memory_skill_* 工具与注入(开关即时生效)",
3867
4182
  checked: skillsEnabled,
3868
4183
  onChange: (v) => {
3869
4184
  toggle("skillsEnabled", v);
3870
4185
  }
3871
4186
  }
3872
4187
  ),
3873
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
3874
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4188
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "工具封印" }),
4189
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3875
4190
  SwitchRow,
3876
4191
  {
3877
4192
  label: "Room 管理工具",
@@ -3882,7 +4197,7 @@ var __defProp = Object.defineProperty;
3882
4197
  }
3883
4198
  }
3884
4199
  ),
3885
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3886
4201
  SwitchRow,
3887
4202
  {
3888
4203
  label: "图谱工具",
@@ -3893,7 +4208,7 @@ var __defProp = Object.defineProperty;
3893
4208
  }
3894
4209
  }
3895
4210
  ),
3896
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4211
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3897
4212
  SwitchRow,
3898
4213
  {
3899
4214
  label: "反刍工具",
@@ -3904,7 +4219,7 @@ var __defProp = Object.defineProperty;
3904
4219
  }
3905
4220
  }
3906
4221
  ),
3907
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4222
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3908
4223
  SwitchRow,
3909
4224
  {
3910
4225
  label: "冲突工具",
@@ -3915,7 +4230,7 @@ var __defProp = Object.defineProperty;
3915
4230
  }
3916
4231
  }
3917
4232
  ),
3918
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4233
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3919
4234
  SwitchRow,
3920
4235
  {
3921
4236
  label: "写删工具",
@@ -3926,8 +4241,19 @@ var __defProp = Object.defineProperty;
3926
4241
  }
3927
4242
  }
3928
4243
  ),
3929
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
3930
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4244
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4245
+ SwitchRow,
4246
+ {
4247
+ label: "技能工具",
4248
+ desc: toolSkills ? "已注册:memory_skill_list / _read / _pin / _archive(需先开启「技能结晶」)" : "已封印:技能四件从模型工具列表移除(技能功能关闭时本就零表面积)",
4249
+ checked: toolSkills,
4250
+ onChange: (v) => {
4251
+ toggle("toolSkills", v);
4252
+ }
4253
+ }
4254
+ ),
4255
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "人工冲突裁决" }),
4256
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3931
4257
  SwitchRow,
3932
4258
  {
3933
4259
  label: "人工冲突裁决",
@@ -3938,43 +4264,110 @@ var __defProp = Object.defineProperty;
3938
4264
  }
3939
4265
  }
3940
4266
  ),
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
4267
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "存量回填与整形" }),
4268
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4269
+ SwitchRow,
4270
+ {
4271
+ label: "关键词回填",
4272
+ desc: keywordEnabled ? "已开启:可对存量记忆批量补检索关键词(下方「存量回填与整形」区点按钮)" : "默认关闭;开启后才能跑关键词回填(喂 FTS 关键词轴)",
4273
+ checked: keywordEnabled,
4274
+ onChange: (v) => {
4275
+ toggle("keywordEnabled", v);
4276
+ }
4277
+ }
4278
+ ),
4279
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4280
+ SwitchRow,
4281
+ {
4282
+ label: "重蒸馏整形",
4283
+ desc: redistillEnabled ? "已开启:可把“平”的存量记忆按类型重排成分节骨架(仅动严格更优的)" : "默认关闭;开启后才能跑重蒸馏整形(改正文会重算向量+覆盖 .memory.md)",
4284
+ checked: redistillEnabled,
4285
+ onChange: (v) => {
4286
+ toggle("redistillEnabled", v);
4287
+ }
4288
+ }
4289
+ ),
4290
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, padding: "6px 0", flexWrap: "wrap" }, children: [
4291
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { fontSize: 13 }, children: "回填并行度" }),
4292
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4293
+ "input",
4294
+ {
4295
+ type: "range",
4296
+ min: 0,
4297
+ max: 8,
4298
+ step: 1,
4299
+ value: Math.min(8, bfConcurrency),
4300
+ onChange: (e) => {
4301
+ setNum("backfillConcurrency", Number(e.target.value));
4302
+ },
4303
+ style: { width: 120 }
4304
+ }
4305
+ ),
4306
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: [
4307
+ bfConcurrency === 0 ? "0·跟随配置(默认 1=串行)" : bfConcurrency === 1 ? "1·串行逐条" : `${bfConcurrency} 路并发`,
4308
+ "· 对**下一次点击**生效(正在跑的那轮不会改道)"
4309
+ ] })
4310
+ ] }),
4311
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4312
+ SwitchRow,
4313
+ {
4314
+ label: "md 反向同步",
4315
+ desc: mdSyncEnabled ? "已开启:可将 .memory.md 文件侧修改回灌入库(需先开 md 投射 + 高权限)" : "默认关闭;风险高于导出(会写库),需先开 md 投射再开本项",
4316
+ checked: mdSyncEnabled,
4317
+ onChange: (v) => {
4318
+ toggle("mdSyncEnabled", v);
4319
+ }
4320
+ }
4321
+ ),
4322
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4323
+ SwitchRow,
4324
+ {
4325
+ label: "外部记忆来源 Connect",
4326
+ desc: memportEnabled ? "已开启:可登记/扫描外部记忆源并导入" : "默认关闭;开启后 memport 相关端点可用",
4327
+ checked: memportEnabled,
4328
+ onChange: (v) => {
4329
+ toggle("memportEnabled", v);
4330
+ }
4331
+ }
4332
+ ),
4333
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
4334
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
4335
+ ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3944
4336
  ] }) : 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 })
4337
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EmbeddingSection, { rpc }),
4338
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RebuildPanel, { rpc }),
4339
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RuminatePanel, { rpc }),
4340
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BackfillSection, { rpc }),
4341
+ degraded ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
4342
+ 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: [
4343
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
4344
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
4345
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
4346
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statNum, children: t.num }),
4347
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.statLabel, children: t.label })
3955
4348
  ] }, t.label);
3956
4349
  }) }),
3957
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
4350
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3958
4351
  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] })
4352
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: S.infoRow, children: [
4353
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.infoKey, children: row2[0] }),
4354
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.infoVal, children: row2[1] })
3962
4355
  ] }, row2[0]);
3963
4356
  })
3964
4357
  ] }),
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 工具查询。" })
4358
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArchiveSection, { rpc }),
4359
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3967
4360
  ] });
3968
4361
  }
3969
4362
 
3970
4363
  // client/src/tabs/PersonaTab.tsx
3971
- var import_react17 = require("react");
3972
- var import_jsx_runtime17 = require("react/jsx-runtime");
4364
+ var import_react18 = require("react");
4365
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3973
4366
  function PersonaTab(props) {
3974
4367
  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)(() => {
4368
+ const [content, setContent] = (0, import_react18.useState)(null);
4369
+ const [error, setError] = (0, import_react18.useState)(null);
4370
+ const load = (0, import_react18.useCallback)(() => {
3978
4371
  setError(null);
3979
4372
  rpc("dsh-memory/persona", {}).then((r) => {
3980
4373
  if (r && r.ok) setContent(r.value.content);
@@ -3983,23 +4376,97 @@ var __defProp = Object.defineProperty;
3983
4376
  setError(String(e && e.message || e));
3984
4377
  });
3985
4378
  }, [rpc]);
3986
- (0, import_react17.useEffect)(() => {
4379
+ (0, import_react18.useEffect)(() => {
3987
4380
  load();
3988
4381
  }, [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: "刷新" })
4382
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
4383
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4384
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
4385
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4386
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: load, children: "刷新" })
3994
4387
  ] }),
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 会自动产出。" })
4388
+ error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
4389
+ 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
4390
  ] });
3998
4391
  }
3999
4392
 
4000
4393
  // client/src/tabs/RecordsTab.tsx
4001
- var import_react18 = require("react");
4002
- var import_jsx_runtime18 = require("react/jsx-runtime");
4394
+ var import_react20 = require("react");
4395
+
4396
+ // client/src/ui/MarkdownBody.tsx
4397
+ var import_react19 = require("react");
4398
+ var H_STYLES = [
4399
+ { fontSize: 15, fontWeight: 700, margin: "8px 0 4px", color: "var(--dsh-mem-text-1)" },
4400
+ { fontSize: 14, fontWeight: 600, margin: "6px 0 3px", color: "var(--dsh-mem-text-1)" },
4401
+ { fontSize: 13, fontWeight: 600, margin: "5px 0 2px", color: "var(--dsh-mem-text-1)" },
4402
+ { fontSize: 12, fontWeight: 600, margin: "4px 0 2px", color: "var(--dsh-mem-text-2)" },
4403
+ { fontSize: 12, fontWeight: 600, margin: "3px 0 1px", color: "var(--dsh-mem-text-2)" },
4404
+ { fontSize: 11, fontWeight: 600, margin: "3px 0 1px", color: "var(--dsh-mem-text-2)" }
4405
+ ];
4406
+ var P2 = { margin: "2px 0", whiteSpace: "pre-wrap", wordBreak: "break-word" };
4407
+ var LI = { margin: "1px 0 1px 12px", whiteSpace: "pre-wrap", wordBreak: "break-word" };
4408
+ var CODE = {
4409
+ fontFamily: "ui-monospace, monospace",
4410
+ fontSize: "0.92em",
4411
+ background: "var(--dsh-mem-bg-3)",
4412
+ padding: "0 3px",
4413
+ borderRadius: 3
4414
+ };
4415
+ function inline(text, key) {
4416
+ const nodes = [];
4417
+ const re = /\*\*(.+?)\*\*|`(.+?)`/;
4418
+ let rest = text;
4419
+ let i = 0;
4420
+ while (rest.length > 0) {
4421
+ const m = re.exec(rest);
4422
+ if (m === null) {
4423
+ nodes.push(rest);
4424
+ break;
4425
+ }
4426
+ if (m.index > 0) nodes.push(rest.slice(0, m.index));
4427
+ if (m[1] !== void 0) {
4428
+ nodes.push((0, import_react19.createElement)("strong", { key: `${key}-b${i++}` }, m[1]));
4429
+ } else {
4430
+ nodes.push((0, import_react19.createElement)("code", { key: `${key}-c${i++}`, style: CODE }, m[2]));
4431
+ }
4432
+ rest = rest.slice(m.index + m[0].length);
4433
+ }
4434
+ return nodes;
4435
+ }
4436
+ function MarkdownBody({ text }) {
4437
+ const lines = text.split("\n");
4438
+ const out = [];
4439
+ let idx = 0;
4440
+ for (const line of lines) {
4441
+ const t = line.trim();
4442
+ if (t.length === 0) continue;
4443
+ const h = /^(#{1,6})\s+(.+)/.exec(t);
4444
+ if (h) {
4445
+ const lv = h[1].length;
4446
+ out.push((0, import_react19.createElement)(`h${lv}`, { key: `h${idx}`, style: H_STYLES[lv - 1] }, ...inline(h[2], `h${idx}`)));
4447
+ idx++;
4448
+ continue;
4449
+ }
4450
+ const ul = /^[-*]\s+(.+)/.exec(t);
4451
+ if (ul) {
4452
+ out.push((0, import_react19.createElement)("div", { key: `li${idx}`, style: LI }, "• ", ...inline(ul[1], `li${idx}`)));
4453
+ idx++;
4454
+ continue;
4455
+ }
4456
+ const ol = /^\d+\.\s+(.+)/.exec(t);
4457
+ if (ol) {
4458
+ out.push((0, import_react19.createElement)("div", { key: `li${idx}`, style: LI }, t.slice(0, t.indexOf(".") + 2), ...inline(ol[1], `li${idx}`)));
4459
+ idx++;
4460
+ continue;
4461
+ }
4462
+ out.push((0, import_react19.createElement)("div", { key: `p${idx}`, style: P2 }, ...inline(t, `p${idx}`)));
4463
+ idx++;
4464
+ }
4465
+ return (0, import_react19.createElement)(import_react19.Fragment, null, ...out);
4466
+ }
4467
+
4468
+ // client/src/tabs/RecordsTab.tsx
4469
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4003
4470
  function retiredSelOf(r) {
4004
4471
  if (r === "active") return false;
4005
4472
  if (r === "retired") return true;
@@ -4009,29 +4476,29 @@ var __defProp = Object.defineProperty;
4009
4476
  function RecordsTab(props) {
4010
4477
  const rpc = props.rpc;
4011
4478
  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)(
4479
+ const [items, setItems] = (0, import_react20.useState)([]);
4480
+ const [hasMore, setHasMore] = (0, import_react20.useState)(false);
4481
+ const [total, setTotal] = (0, import_react20.useState)(null);
4482
+ const [sceneOptions, setSceneOptions] = (0, import_react20.useState)([]);
4483
+ const [loading, setLoading] = (0, import_react20.useState)(false);
4484
+ const [truncated, setTruncated] = (0, import_react20.useState)(false);
4485
+ const [error, setError] = (0, import_react20.useState)(null);
4486
+ const [expandedId, setExpandedId] = (0, import_react20.useState)(null);
4487
+ const [sel, setSel] = (0, import_react20.useState)(/* @__PURE__ */ new Set());
4488
+ const [hiPriv, setHiPriv] = (0, import_react20.useState)(false);
4489
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react20.useState)(false);
4490
+ const [query, setQuery] = (0, import_react20.useState)("");
4491
+ const [typeFilter, setTypeFilter] = (0, import_react20.useState)("");
4492
+ const [sceneFilter, setSceneFilter] = (0, import_react20.useState)("");
4493
+ const [hallFilter, setHallFilter] = (0, import_react20.useState)([]);
4494
+ const [tagFilter, setTagFilter] = (0, import_react20.useState)("");
4495
+ const [untaggedOnly, setUntaggedOnly] = (0, import_react20.useState)(false);
4496
+ const [orphanCount, setOrphanCount] = (0, import_react20.useState)(0);
4497
+ const [retiredFilter, setRetiredFilter] = (0, import_react20.useState)("");
4498
+ const [wingCatalog, setHallCatalog] = (0, import_react20.useState)(null);
4499
+ const [last, setLast] = (0, import_react20.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
4500
+ const seqRef = (0, import_react20.useRef)(0);
4501
+ const fetchPage = (0, import_react20.useCallback)(
4035
4502
  (conds, offset, append) => {
4036
4503
  setLoading(true);
4037
4504
  setError(null);
@@ -4081,23 +4548,23 @@ var __defProp = Object.defineProperty;
4081
4548
  setLast(conds);
4082
4549
  fetchPage(conds, 0, false);
4083
4550
  };
4084
- const loadRooms = (0, import_react18.useCallback)(() => {
4551
+ const loadRooms = (0, import_react20.useCallback)(() => {
4085
4552
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4086
4553
  if (r && r.ok) setOrphanCount(r.value.orphanCount ?? 0);
4087
4554
  }).catch(() => {
4088
4555
  });
4089
4556
  }, [rpc]);
4090
- (0, import_react18.useEffect)(() => {
4557
+ (0, import_react20.useEffect)(() => {
4091
4558
  fetchPage({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" }, 0, false);
4092
4559
  loadRooms();
4093
4560
  }, [fetchPage, loadRooms]);
4094
- const loadHiPriv = (0, import_react18.useCallback)(() => {
4561
+ const loadHiPriv = (0, import_react20.useCallback)(() => {
4095
4562
  rpc("dsh-memory/settings-get", {}).then((r) => {
4096
4563
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4097
4564
  }).catch(() => {
4098
4565
  });
4099
4566
  }, [rpc]);
4100
- (0, import_react18.useEffect)(() => {
4567
+ (0, import_react20.useEffect)(() => {
4101
4568
  loadHiPriv();
4102
4569
  }, [loadHiPriv]);
4103
4570
  const toggleHiPriv = () => {
@@ -4161,11 +4628,11 @@ var __defProp = Object.defineProperty;
4161
4628
  } else if (r) setError(r.error ? r.error.message : "退场失败");
4162
4629
  }).catch((e) => setError(String(e && e.message || e)));
4163
4630
  };
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)(() => {
4631
+ const [retired, setRetired] = (0, import_react20.useState)([]);
4632
+ const [retiredTotal, setRetiredTotal] = (0, import_react20.useState)(0);
4633
+ const [showRetired, setShowRetired] = (0, import_react20.useState)(false);
4634
+ const [retiredBusy, setRetiredBusy] = (0, import_react20.useState)(false);
4635
+ const loadRetired = (0, import_react20.useCallback)(() => {
4169
4636
  setRetiredBusy(true);
4170
4637
  rpc("dsh-memory/records-retired", { limit: 100, offset: 0 }).then((r) => {
4171
4638
  if (r && r.ok) {
@@ -4174,7 +4641,7 @@ var __defProp = Object.defineProperty;
4174
4641
  } else if (r) setError(r.error ? r.error.message : "已退场列表加载失败");
4175
4642
  }).catch((e) => setError(String(e && e.message || e))).finally(() => setRetiredBusy(false));
4176
4643
  }, [rpc]);
4177
- (0, import_react18.useEffect)(() => {
4644
+ (0, import_react20.useEffect)(() => {
4178
4645
  if (showRetired) loadRetired();
4179
4646
  }, [showRetired, loadRetired]);
4180
4647
  const restoreRecords = (ids) => {
@@ -4198,11 +4665,11 @@ var __defProp = Object.defineProperty;
4198
4665
  unknown: "已退场"
4199
4666
  };
4200
4667
  const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
4201
- const [usageSummary, setUsageSummary] = (0, import_react18.useState)(null);
4668
+ const [usageSummary, setUsageSummary] = (0, import_react20.useState)(null);
4202
4669
  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)(
4670
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
4671
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.toolbar, children: [
4672
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4206
4673
  NInput,
4207
4674
  {
4208
4675
  style: { flex: 1, minWidth: 160 },
@@ -4225,7 +4692,7 @@ var __defProp = Object.defineProperty;
4225
4692
  }
4226
4693
  }
4227
4694
  ),
4228
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4695
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4229
4696
  NSel,
4230
4697
  {
4231
4698
  style: { maxWidth: 200 },
@@ -4238,7 +4705,7 @@ var __defProp = Object.defineProperty;
4238
4705
  onChange: setTypeFilter
4239
4706
  }
4240
4707
  ),
4241
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4708
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4242
4709
  NSel,
4243
4710
  {
4244
4711
  style: { maxWidth: 220 },
@@ -4251,7 +4718,7 @@ var __defProp = Object.defineProperty;
4251
4718
  onChange: setSceneFilter
4252
4719
  }
4253
4720
  ),
4254
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4721
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4255
4722
  WingMultiSelect,
4256
4723
  {
4257
4724
  options: wingCatalog ?? Array.from(new Set(items.map((m) => m.hall).filter((h) => !!h))).map((id) => ({ id, label: id })),
@@ -4259,8 +4726,8 @@ var __defProp = Object.defineProperty;
4259
4726
  onChange: setHallFilter
4260
4727
  }
4261
4728
  ),
4262
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: search, children: "搜索" }),
4263
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4729
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { onClick: search, children: "搜索" }),
4730
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4264
4731
  NButton,
4265
4732
  {
4266
4733
  style: {
@@ -4274,8 +4741,8 @@ var __defProp = Object.defineProperty;
4274
4741
  }
4275
4742
  )
4276
4743
  ] }),
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)(
4744
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
4745
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4279
4746
  "button",
4280
4747
  {
4281
4748
  type: "button",
@@ -4300,10 +4767,10 @@ var __defProp = Object.defineProperty;
4300
4767
  children: "无绑定 · " + orphanCount
4301
4768
  }
4302
4769
  ),
4303
- (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: S.muted, children: [
4770
+ (tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: S.muted, children: [
4304
4771
  "筛选中:",
4305
4772
  untaggedOnly ? "无绑定" : tagFilter,
4306
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4773
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4307
4774
  "button",
4308
4775
  {
4309
4776
  type: "button",
@@ -4320,7 +4787,7 @@ var __defProp = Object.defineProperty;
4320
4787
  }
4321
4788
  )
4322
4789
  ] }),
4323
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4790
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4324
4791
  "button",
4325
4792
  {
4326
4793
  type: "button",
@@ -4349,15 +4816,15 @@ var __defProp = Object.defineProperty;
4349
4816
  children: "导出孤儿"
4350
4817
  }
4351
4818
  ),
4352
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4819
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
4353
4820
  ] }),
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: "退场筛查" }),
4821
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
4822
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
4823
+ usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
4824
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "退场筛查" }),
4358
4825
  [["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
4359
4826
  const on = retiredFilter === val;
4360
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4827
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4361
4828
  "button",
4362
4829
  {
4363
4830
  type: "button",
@@ -4377,7 +4844,7 @@ var __defProp = Object.defineProperty;
4377
4844
  val
4378
4845
  );
4379
4846
  }),
4380
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4847
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4381
4848
  NButton,
4382
4849
  {
4383
4850
  style: selCount > 0 ? { color: "var(--dsh-mem-danger)" } : void 0,
@@ -4387,7 +4854,7 @@ var __defProp = Object.defineProperty;
4387
4854
  children: "删除选中" + (selCount > 0 ? "(" + selCount + ")" : "")
4388
4855
  }
4389
4856
  ),
4390
- selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4857
+ selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4391
4858
  NButton,
4392
4859
  {
4393
4860
  onClick: () => {
@@ -4396,8 +4863,8 @@ var __defProp = Object.defineProperty;
4396
4863
  children: "清空选择"
4397
4864
  }
4398
4865
  ) : null,
4399
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
4400
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4866
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
4867
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4401
4868
  NButton,
4402
4869
  {
4403
4870
  onClick: () => {
@@ -4408,13 +4875,13 @@ var __defProp = Object.defineProperty;
4408
4875
  }
4409
4876
  )
4410
4877
  ] }),
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) => {
4878
+ !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
4879
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.error, children: error }) : null,
4880
+ truncated ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
4881
+ items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
4415
4882
  const open = expandedId === m.id;
4416
4883
  const checked = sel.has(m.id);
4417
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4884
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4418
4885
  "div",
4419
4886
  {
4420
4887
  className: "dsh-mem-card dsh-mem-card-hover",
@@ -4423,8 +4890,8 @@ var __defProp = Object.defineProperty;
4423
4890
  setExpandedId(open ? null : m.id);
4424
4891
  },
4425
4892
  children: [
4426
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: S.cardHead, children: [
4427
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4893
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.cardHead, children: [
4894
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4428
4895
  "input",
4429
4896
  {
4430
4897
  type: "checkbox",
@@ -4439,9 +4906,9 @@ var __defProp = Object.defineProperty;
4439
4906
  }
4440
4907
  }
4441
4908
  ),
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)(
4909
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: tagClass(m.type), children: typeLabel(m.type) }),
4910
+ 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,
4911
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4445
4912
  "span",
4446
4913
  {
4447
4914
  title: "该记忆已退场(软删):移出检索面但仍可恢复,并未真正删除",
@@ -4456,8 +4923,8 @@ var __defProp = Object.defineProperty;
4456
4923
  children: "已退场" + (m.retiredReason ? " · " + (RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason) : "")
4457
4924
  }
4458
4925
  ) : null,
4459
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4460
- m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4926
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
4927
+ m.maturity ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4461
4928
  "span",
4462
4929
  {
4463
4930
  title: "成熟度(优先级 + 被用次数 + 新鲜度合成):" + m.maturity,
@@ -4472,7 +4939,7 @@ var __defProp = Object.defineProperty;
4472
4939
  children: m.maturity === "high" ? "成熟·高" : m.maturity === "mid" ? "成熟·中" : "成熟·低"
4473
4940
  }
4474
4941
  ) : null,
4475
- m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4942
+ m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4476
4943
  "span",
4477
4944
  {
4478
4945
  style: {
@@ -4487,7 +4954,7 @@ var __defProp = Object.defineProperty;
4487
4954
  children: "老化 " + Math.round(m.agingWeight * 100) + "%"
4488
4955
  }
4489
4956
  ) : null,
4490
- m.usage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4957
+ m.usage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4491
4958
  "span",
4492
4959
  {
4493
4960
  style: S.muted,
@@ -4495,7 +4962,7 @@ var __defProp = Object.defineProperty;
4495
4962
  children: "用 " + m.usage.used + "/" + m.usage.attempts
4496
4963
  }
4497
4964
  ) : null,
4498
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4965
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4499
4966
  "span",
4500
4967
  {
4501
4968
  title: m.name && m.name.length > 0 ? "名称(名称蒸馏产物;投射文件的命名取它):" + m.name : "尚未命名(名称蒸馏未产出);投射回落 mem-" + m.id.slice(-8),
@@ -4513,7 +4980,7 @@ var __defProp = Object.defineProperty;
4513
4980
  children: "名称 " + (m.name && m.name.length > 0 ? m.name : "未命名")
4514
4981
  }
4515
4982
  ),
4516
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4983
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4517
4984
  "span",
4518
4985
  {
4519
4986
  title: m.scope === "workspace" ? "作用范围:指定工作区(仅归属工作区可见)" + (m.workspaceId ? ":" + m.workspaceId : "") : "作用范围:用户默认(global,任何工作区可见)",
@@ -4528,10 +4995,10 @@ var __defProp = Object.defineProperty;
4528
4995
  children: m.scope === "workspace" ? "工作区" : "用户默认"
4529
4996
  }
4530
4997
  ),
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)(
4998
+ m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
4999
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5000
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
5001
+ m.retired ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4535
5002
  NButton,
4536
5003
  {
4537
5004
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-accent)" },
@@ -4542,7 +5009,7 @@ var __defProp = Object.defineProperty;
4542
5009
  },
4543
5010
  children: "恢复"
4544
5011
  }
4545
- ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5012
+ ) : hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4546
5013
  NButton,
4547
5014
  {
4548
5015
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-danger)" },
@@ -4555,34 +5022,34 @@ var __defProp = Object.defineProperty;
4555
5022
  }
4556
5023
  ) : null
4557
5024
  ] }),
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
5025
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.content, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MarkdownBody, { text: m.content }) }),
5026
+ 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
5027
  ]
4561
5028
  },
4562
5029
  m.id
4563
5030
  );
4564
5031
  }),
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
5032
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { ...S.flexRow, marginTop: 12 }, children: [
5033
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { onClick: () => setShowRetired((v) => !v), children: (showRetired ? "收起" : "展开") + "「已退场」(可恢复)" }),
5034
+ showRetired && retiredBusy ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "加载中…" }) : null,
5035
+ showRetired && !retiredBusy && retiredTotal > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "共 " + retiredTotal + " 条可恢复" }) : null
4569
5036
  ] }),
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: "恢复" })
5037
+ 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: [
5038
+ retired.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
5039
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.cardHead, children: [
5040
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: RETIRE_REASON_LABEL[m.retiredReason] || m.retiredReason }),
5041
+ m.verdict ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "结论 " + m.verdict }) : null,
5042
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5043
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: fmtTime(m.retiredAt) }),
5044
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NButton, { disabled: retiredBusy, title: "恢复到检索面", onClick: () => restoreRecords([m.id]), children: "恢复" })
4578
5045
  ] }),
4579
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.content, children: m.content })
5046
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.content, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MarkdownBody, { text: m.content }) })
4580
5047
  ] }, m.id)),
4581
- retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
5048
+ retiredTotal > retired.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.hint, children: "共 " + retiredTotal + " 条,此处显示 " + retired.length + " 条" }) : null
4582
5049
  ] }) }) : 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)(
5050
+ hasMore ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: S.flexRow, children: [
5051
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.grow }),
5052
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4586
5053
  NButton,
4587
5054
  {
4588
5055
  disabled: loading,
@@ -4596,9 +5063,9 @@ var __defProp = Object.defineProperty;
4596
5063
  ] });
4597
5064
  }
4598
5065
  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)(() => {
5066
+ const [open, setOpen] = (0, import_react20.useState)(false);
5067
+ const wrapRef = (0, import_react20.useRef)(null);
5068
+ (0, import_react20.useEffect)(() => {
4602
5069
  if (!open) return;
4603
5070
  const onDown = (e) => {
4604
5071
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -4618,8 +5085,8 @@ var __defProp = Object.defineProperty;
4618
5085
  const toggle = (id) => {
4619
5086
  props.onChange(props.selected.includes(id) ? props.selected.filter((x) => x !== id) : [...props.selected, id]);
4620
5087
  };
4621
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
4622
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5088
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { ref: wrapRef, style: { position: "relative", maxWidth: 150 }, children: [
5089
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4623
5090
  "button",
4624
5091
  {
4625
5092
  type: "button",
@@ -4628,31 +5095,31 @@ var __defProp = Object.defineProperty;
4628
5095
  "aria-expanded": open,
4629
5096
  onClick: () => setOpen(!open),
4630
5097
  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" : "") })
5098
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-select-label", title: summary, children: summary }),
5099
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : "") })
4633
5100
  ]
4634
5101
  }
4635
5102
  ),
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,
5103
+ open ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "dsh-mem-pop", role: "listbox", style: { left: 0, right: "auto", minWidth: 150 }, children: [
5104
+ props.options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "dsh-mem-pop-empty", children: "暂无可筛 Hall" }) : null,
4638
5105
  props.options.map((o) => {
4639
5106
  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 })
5107
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => toggle(o.id), "aria-selected": active, children: [
5108
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-check", children: active ? "✓" : "" }),
5109
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-label", children: o.label })
4643
5110
  ] }, o.id);
4644
5111
  }),
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: "清除筛选" })
5112
+ props.selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "dsh-mem-pop-opt", onClick: () => props.onChange([]), children: [
5113
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-check" }),
5114
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "dsh-mem-pop-label", children: "清除筛选" })
4648
5115
  ] }) : null
4649
5116
  ] }) : null
4650
5117
  ] });
4651
5118
  }
4652
5119
 
4653
5120
  // client/src/tabs/RoomsTab.tsx
4654
- var import_react19 = require("react");
4655
- var import_jsx_runtime19 = require("react/jsx-runtime");
5121
+ var import_react21 = require("react");
5122
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4656
5123
  function majorOf(slug) {
4657
5124
  const i = slug.indexOf("/");
4658
5125
  return i === -1 ? slug : slug.slice(0, i);
@@ -4681,26 +5148,26 @@ var __defProp = Object.defineProperty;
4681
5148
  };
4682
5149
  function RoomsTab(props) {
4683
5150
  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)(() => {
5151
+ const [registry, setRegistry] = (0, import_react21.useState)([]);
5152
+ const [rooms, setRooms] = (0, import_react21.useState)([]);
5153
+ const [orphanCount, setOrphanCount] = (0, import_react21.useState)(0);
5154
+ const [busy, setBusy] = (0, import_react21.useState)(false);
5155
+ const [msg, setMsg] = (0, import_react21.useState)(null);
5156
+ const [error, setError] = (0, import_react21.useState)(null);
5157
+ const [hiPriv, setHiPriv] = (0, import_react21.useState)(false);
5158
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react21.useState)(false);
5159
+ const [regSlug, setRegSlug] = (0, import_react21.useState)("");
5160
+ const [regLabel, setRegLabel] = (0, import_react21.useState)("");
5161
+ const [regDesc, setRegDesc] = (0, import_react21.useState)("");
5162
+ const [form, setForm] = (0, import_react21.useState)(null);
5163
+ const [preview, setPreview] = (0, import_react21.useState)(null);
5164
+ const [grownOpen, setGrownOpen] = (0, import_react21.useState)(false);
5165
+ const [dragOverHall, setDragOverHall] = (0, import_react21.useState)(null);
5166
+ const [picking, setPicking] = (0, import_react21.useState)(null);
5167
+ const [editing, setEditing] = (0, import_react21.useState)(null);
5168
+ const [expandedRooms, setExpandedRooms] = (0, import_react21.useState)(/* @__PURE__ */ new Set());
5169
+ const [roomRecords, setRoomRecords] = (0, import_react21.useState)({});
5170
+ const [expandedHalls, setExpandedHalls] = (0, import_react21.useState)(() => {
4704
5171
  try {
4705
5172
  const v = window.localStorage.getItem("dsh.memory.halls.open");
4706
5173
  return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
@@ -4708,9 +5175,9 @@ var __defProp = Object.defineProperty;
4708
5175
  return /* @__PURE__ */ new Set();
4709
5176
  }
4710
5177
  });
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);
5178
+ const [filter, setFilter] = (0, import_react21.useState)("");
5179
+ const dragRef = (0, import_react21.useRef)(null);
5180
+ const [ghost, setGhost] = (0, import_react21.useState)(null);
4714
5181
  const onDragLabelDown = (ev, slug) => {
4715
5182
  if (!hiPriv || busy || ev.button !== 0) return;
4716
5183
  ev.currentTarget.setPointerCapture(ev.pointerId);
@@ -4735,7 +5202,7 @@ var __defProp = Object.defineProperty;
4735
5202
  setDragOverHall(null);
4736
5203
  if (hall) beginReclass(d.from, hall);
4737
5204
  };
4738
- const loadAll = (0, import_react19.useCallback)(() => {
5205
+ const loadAll = (0, import_react21.useCallback)(() => {
4739
5206
  rpc("dsh-memory/rooms-get", {}).then((r) => {
4740
5207
  if (r && r.ok) {
4741
5208
  setRooms(r.value.rooms ?? []);
@@ -4744,13 +5211,13 @@ var __defProp = Object.defineProperty;
4744
5211
  }
4745
5212
  }).catch(() => void 0);
4746
5213
  }, [rpc]);
4747
- const loadHiPriv = (0, import_react19.useCallback)(() => {
5214
+ const loadHiPriv = (0, import_react21.useCallback)(() => {
4748
5215
  rpc("dsh-memory/settings-get", {}).then((r) => {
4749
5216
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
4750
5217
  }).catch(() => {
4751
5218
  });
4752
5219
  }, [rpc]);
4753
- (0, import_react19.useEffect)(() => {
5220
+ (0, import_react21.useEffect)(() => {
4754
5221
  loadAll();
4755
5222
  loadHiPriv();
4756
5223
  }, [loadAll, loadHiPriv]);
@@ -4905,7 +5372,7 @@ var __defProp = Object.defineProperty;
4905
5372
  if (r.value.csv) downloadCsv(r.value.csv, `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`);
4906
5373
  else setError("导出为空");
4907
5374
  });
4908
- const groups = (0, import_react19.useMemo)(() => {
5375
+ const groups = (0, import_react21.useMemo)(() => {
4909
5376
  const countOf = new Map(rooms.map((r) => [r.room, r.count]));
4910
5377
  const byHall = /* @__PURE__ */ new Map();
4911
5378
  for (const e of registry) {
@@ -4922,7 +5389,7 @@ var __defProp = Object.defineProperty;
4922
5389
  total: entries.reduce((s2, e) => s2 + (countOf.get(e.slug) ?? 0), 0)
4923
5390
  })).sort((a, b) => a.hall.localeCompare(b.hall));
4924
5391
  }, [registry, rooms]);
4925
- const grownOnly = (0, import_react19.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
5392
+ const grownOnly = (0, import_react21.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
4926
5393
  const persistHalls = (next) => {
4927
5394
  try {
4928
5395
  window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
@@ -4942,7 +5409,7 @@ var __defProp = Object.defineProperty;
4942
5409
  persistHalls(next);
4943
5410
  };
4944
5411
  const normFilter = filter.trim().toLowerCase();
4945
- const visibleGroups = (0, import_react19.useMemo)(() => {
5412
+ const visibleGroups = (0, import_react21.useMemo)(() => {
4946
5413
  if (!normFilter) return groups;
4947
5414
  return groups.map((g) => {
4948
5415
  const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
@@ -4952,15 +5419,15 @@ var __defProp = Object.defineProperty;
4952
5419
  return { ...g, entries };
4953
5420
  }).filter((g) => g.entries.length > 0);
4954
5421
  }, [groups, normFilter]);
4955
- const visibleGrown = (0, import_react19.useMemo)(
5422
+ const visibleGrown = (0, import_react21.useMemo)(
4956
5423
  () => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
4957
5424
  [grownOnly, normFilter]
4958
5425
  );
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)(
5426
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
5427
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
5428
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
5429
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5430
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4964
5431
  "button",
4965
5432
  {
4966
5433
  type: "button",
@@ -4977,7 +5444,7 @@ var __defProp = Object.defineProperty;
4977
5444
  children: "导出词表"
4978
5445
  }
4979
5446
  ),
4980
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5447
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4981
5448
  "button",
4982
5449
  {
4983
5450
  type: "button",
@@ -4997,7 +5464,7 @@ var __defProp = Object.defineProperty;
4997
5464
  ]
4998
5465
  }
4999
5466
  ),
5000
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5467
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5001
5468
  "button",
5002
5469
  {
5003
5470
  type: "button",
@@ -5012,10 +5479,10 @@ var __defProp = Object.defineProperty;
5012
5479
  children: hiPriv ? "高权限:开" : "高权限:关"
5013
5480
  }
5014
5481
  ),
5015
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
5482
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
5016
5483
  ] }),
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)(
5484
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
5485
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5019
5486
  "input",
5020
5487
  {
5021
5488
  value: filter,
@@ -5024,14 +5491,14 @@ var __defProp = Object.defineProperty;
5024
5491
  style: { ...S.input, width: 250, fontSize: 12 }
5025
5492
  }
5026
5493
  ),
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: "收起全部" })
5494
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
5495
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
5496
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5497
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
5498
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
5032
5499
  ] }),
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)(
5500
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
5501
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5035
5502
  "input",
5036
5503
  {
5037
5504
  value: regSlug,
@@ -5041,7 +5508,7 @@ var __defProp = Object.defineProperty;
5041
5508
  style: { ...S.input, width: 210, fontSize: 12 }
5042
5509
  }
5043
5510
  ),
5044
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5511
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5045
5512
  "input",
5046
5513
  {
5047
5514
  value: regLabel,
@@ -5051,7 +5518,7 @@ var __defProp = Object.defineProperty;
5051
5518
  style: { ...S.input, width: 110, fontSize: 12 }
5052
5519
  }
5053
5520
  ),
5054
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5521
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5055
5522
  "input",
5056
5523
  {
5057
5524
  value: regDesc,
@@ -5061,7 +5528,7 @@ var __defProp = Object.defineProperty;
5061
5528
  style: { ...S.input, width: 170, fontSize: 12 }
5062
5529
  }
5063
5530
  ),
5064
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5531
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5065
5532
  "button",
5066
5533
  {
5067
5534
  type: "button",
@@ -5071,26 +5538,26 @@ var __defProp = Object.defineProperty;
5071
5538
  children: "注册"
5072
5539
  }
5073
5540
  ),
5074
- !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5541
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5075
5542
  ] }),
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: [
5543
+ 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: [
5544
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5078
5545
  "编辑 ",
5079
5546
  editing.slug
5080
5547
  ] }),
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: "取消" })
5548
+ /* @__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 } }),
5549
+ /* @__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 } }),
5550
+ /* @__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: "保存" }),
5551
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
5085
5552
  ] }) : 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: [
5553
+ 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: [
5554
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: S.muted, children: [
5088
5555
  form.action === "merge" ? "合并" : "归类/改名",
5089
5556
  " ",
5090
5557
  form.from,
5091
5558
  " →"
5092
5559
  ] }),
5093
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5560
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5094
5561
  "input",
5095
5562
  {
5096
5563
  value: form.to,
@@ -5100,7 +5567,7 @@ var __defProp = Object.defineProperty;
5100
5567
  style: { ...S.input, width: 190, fontSize: 12 }
5101
5568
  }
5102
5569
  ),
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)(
5570
+ 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
5571
  "button",
5105
5572
  {
5106
5573
  type: "button",
@@ -5111,32 +5578,32 @@ var __defProp = Object.defineProperty;
5111
5578
  },
5112
5579
  gg.hall
5113
5580
  )) }) : 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: () => {
5581
+ /* @__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: "预览" }),
5582
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => {
5116
5583
  setForm(null);
5117
5584
  setPreview(null);
5118
5585
  setPicking(null);
5119
5586
  }, 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: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5587
+ picking ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
5588
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5122
5589
  ] }) : 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: [
5590
+ 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: [
5591
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { children: preview.notice }),
5592
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
5593
+ /* @__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
5594
  "确认执行",
5128
5595
  preview.action === "merge" ? "合并" : "归类/改名"
5129
5596
  ] }),
5130
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5597
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
5131
5598
  ] })
5132
5599
  ] }) : 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) => {
5600
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.hint, children: msg }) : null,
5601
+ error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.error, children: error }) : null,
5602
+ 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,
5603
+ 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
5604
  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)(
5605
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
5606
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5140
5607
  "div",
5141
5608
  {
5142
5609
  "data-hall": g.hall,
@@ -5177,7 +5644,7 @@ var __defProp = Object.defineProperty;
5177
5644
  },
5178
5645
  title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
5179
5646
  children: [
5180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5647
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5181
5648
  "button",
5182
5649
  {
5183
5650
  type: "button",
@@ -5190,13 +5657,13 @@ var __defProp = Object.defineProperty;
5190
5657
  children: hallOpen ? "▾" : "▸"
5191
5658
  }
5192
5659
  ),
5193
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5660
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
5194
5661
  g.hall,
5195
- g.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5662
+ g.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
5196
5663
  ] }),
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)(
5664
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
5665
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5666
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5200
5667
  "button",
5201
5668
  {
5202
5669
  type: "button",
@@ -5217,10 +5684,10 @@ var __defProp = Object.defineProperty;
5217
5684
  const standalone = e.slug === g.hall;
5218
5685
  const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
5219
5686
  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)(
5687
+ 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: [
5688
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5689
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
5690
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5224
5691
  "button",
5225
5692
  {
5226
5693
  type: "button",
@@ -5230,7 +5697,7 @@ var __defProp = Object.defineProperty;
5230
5697
  children: expandedRooms.has(e.slug) ? "▾" : "▸"
5231
5698
  }
5232
5699
  ),
5233
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5700
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5234
5701
  "span",
5235
5702
  {
5236
5703
  style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
@@ -5244,20 +5711,20 @@ var __defProp = Object.defineProperty;
5244
5711
  ]
5245
5712
  }
5246
5713
  ),
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
5714
+ e.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: e.label }) : null,
5715
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: count + " 条" }),
5716
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
5717
+ (e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
5251
5718
  ] }),
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: () => {
5719
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
5720
+ !hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5721
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5255
5722
  setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
5256
5723
  setForm(null);
5257
5724
  setPreview(null);
5258
5725
  setPicking(null);
5259
5726
  }, style: btn, children: "编辑" }),
5260
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5727
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5261
5728
  "button",
5262
5729
  {
5263
5730
  type: "button",
@@ -5278,43 +5745,43 @@ var __defProp = Object.defineProperty;
5278
5745
  children: picking === e.slug ? "选 hall…" : "归类"
5279
5746
  }
5280
5747
  ),
5281
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5748
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
5282
5749
  setForm({ action: "rename", from: e.slug, to: "" });
5283
5750
  setPreview(null);
5284
5751
  }, style: btn, children: "改名" }),
5285
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5752
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
5286
5753
  setForm({ action: "merge", from: e.slug, to: "" });
5287
5754
  setPreview(null);
5288
5755
  }, 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
5756
+ /* @__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 ? "恢复" : "退役" }),
5757
+ !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
5758
  ] }),
5292
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5759
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
5293
5760
  ] })
5294
5761
  ] }),
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) }),
5762
+ 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: [
5763
+ (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: [
5764
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5298
5765
  " ",
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 })
5766
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
5767
+ /* @__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
5768
  ] }, 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
5769
+ (roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
5770
+ (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
5771
  ] }) : null
5305
5772
  ] }, e.slug);
5306
5773
  }) : null
5307
5774
  ] }, g.hall);
5308
5775
  }),
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: [
5776
+ visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginTop: 4 }, children: [
5777
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
5311
5778
  grownOpen ? "▾" : "▸",
5312
5779
  " 自生长未注册 · 共 ",
5313
5780
  visibleGrown.length
5314
5781
  ] }),
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)(
5782
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
5783
+ 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: [
5784
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5318
5785
  "span",
5319
5786
  {
5320
5787
  style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
@@ -5325,8 +5792,8 @@ var __defProp = Object.defineProperty;
5325
5792
  children: r.room + " · " + r.count
5326
5793
  }
5327
5794
  ),
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)(
5795
+ /* @__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: "收编" }),
5796
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5330
5797
  "button",
5331
5798
  {
5332
5799
  type: "button",
@@ -5353,8 +5820,8 @@ var __defProp = Object.defineProperty;
5353
5820
  }
5354
5821
 
5355
5822
  // client/src/tabs/RoomTab.tsx
5356
- var import_react20 = require("react");
5357
- var import_jsx_runtime20 = require("react/jsx-runtime");
5823
+ var import_react22 = require("react");
5824
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5358
5825
  var btn2 = {
5359
5826
  cursor: "pointer",
5360
5827
  fontSize: 12,
@@ -5375,22 +5842,22 @@ var __defProp = Object.defineProperty;
5375
5842
  }
5376
5843
  function RoomTab(props) {
5377
5844
  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)(() => {
5845
+ const [registry, setRegistry] = (0, import_react22.useState)([]);
5846
+ const [counts, setCounts] = (0, import_react22.useState)([]);
5847
+ const [orphanCount, setOrphanCount] = (0, import_react22.useState)(0);
5848
+ const [busy, setBusy] = (0, import_react22.useState)(false);
5849
+ const [msg, setMsg] = (0, import_react22.useState)(null);
5850
+ const [error, setError] = (0, import_react22.useState)(null);
5851
+ const [hiPriv, setHiPriv] = (0, import_react22.useState)(false);
5852
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react22.useState)(false);
5853
+ const [reg, setReg] = (0, import_react22.useState)({ slug: "", label: "", description: "" });
5854
+ const [editing, setEditing] = (0, import_react22.useState)(null);
5855
+ const [renaming, setRenaming] = (0, import_react22.useState)(null);
5856
+ const [expanded, setExpanded] = (0, import_react22.useState)(/* @__PURE__ */ new Set());
5857
+ const [retiredFilter, setRetiredFilter] = (0, import_react22.useState)("");
5858
+ const [filter, setFilter] = (0, import_react22.useState)("");
5859
+ const [records, setRecords] = (0, import_react22.useState)({});
5860
+ const loadAll = (0, import_react22.useCallback)(() => {
5394
5861
  rpc("dsh-memory/rooms-get", {}).then((r) => {
5395
5862
  if (r && r.ok) {
5396
5863
  setCounts(r.value.rooms ?? []);
@@ -5399,13 +5866,13 @@ var __defProp = Object.defineProperty;
5399
5866
  }
5400
5867
  }).catch(() => void 0);
5401
5868
  }, [rpc]);
5402
- const loadHiPriv = (0, import_react20.useCallback)(() => {
5869
+ const loadHiPriv = (0, import_react22.useCallback)(() => {
5403
5870
  rpc("dsh-memory/settings-get", {}).then((r) => {
5404
5871
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
5405
5872
  }).catch(() => {
5406
5873
  });
5407
5874
  }, [rpc]);
5408
- (0, import_react20.useEffect)(() => {
5875
+ (0, import_react22.useEffect)(() => {
5409
5876
  loadAll();
5410
5877
  loadHiPriv();
5411
5878
  }, [loadAll, loadHiPriv]);
@@ -5547,11 +6014,11 @@ var __defProp = Object.defineProperty;
5547
6014
  const visibleRows = normFilter ? rows.filter(
5548
6015
  (row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
5549
6016
  ) : 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 () => {
6017
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
6018
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
6019
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
6020
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
6021
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
5555
6022
  const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
5556
6023
  if (!r.ok) {
5557
6024
  setError(r.error.message);
@@ -5562,7 +6029,7 @@ var __defProp = Object.defineProperty;
5562
6029
  "导出孤儿 · ",
5563
6030
  orphanCount
5564
6031
  ] }),
5565
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6032
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5566
6033
  "button",
5567
6034
  {
5568
6035
  type: "button",
@@ -5573,35 +6040,35 @@ var __defProp = Object.defineProperty;
5573
6040
  children: hiPriv ? "高权限:开" : "高权限:关"
5574
6041
  }
5575
6042
  ),
5576
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
6043
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
5577
6044
  ] }),
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: [
6045
+ 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: [
6046
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: S.muted, children: [
5580
6047
  "编辑 ",
5581
6048
  editing.slug
5582
6049
  ] }),
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: "取消" })
6050
+ /* @__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 } }),
6051
+ /* @__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 } }),
6052
+ /* @__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: "保存" }),
6053
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
5587
6054
  ] }) : 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: [
6055
+ 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: [
6056
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: S.muted, children: [
5590
6057
  "改名 ",
5591
6058
  renaming.slug,
5592
6059
  " →"
5593
6060
  ] }),
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: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
6061
+ /* @__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 } }),
6062
+ /* @__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: "预览" }),
6063
+ /* @__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: "确认执行" }),
6064
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
6065
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
5599
6066
  ] }) : 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: "退场筛选" }),
6067
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
6068
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "退场筛选" }),
5602
6069
  [["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
5603
6070
  const on = retiredFilter === val;
5604
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6071
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5605
6072
  "button",
5606
6073
  {
5607
6074
  type: "button",
@@ -5621,8 +6088,8 @@ var __defProp = Object.defineProperty;
5621
6088
  val
5622
6089
  );
5623
6090
  }),
5624
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: S.grow }),
5625
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6091
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.grow }),
6092
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5626
6093
  "input",
5627
6094
  {
5628
6095
  value: filter,
@@ -5631,24 +6098,24 @@ var __defProp = Object.defineProperty;
5631
6098
  style: { ...S.input, width: 230, fontSize: 12 }
5632
6099
  }
5633
6100
  ),
5634
- filter ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
6101
+ filter ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
5635
6102
  ] }),
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: "管理操作需先开启高权限模式" })
6103
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
6104
+ /* @__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 } }),
6105
+ /* @__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 } }),
6106
+ /* @__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 } }),
6107
+ /* @__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: "注册" }),
6108
+ !hiPriv && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
5642
6109
  ] }),
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) => {
6110
+ msg ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.hint, children: msg }) : null,
6111
+ error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.error, children: error }) : null,
6112
+ 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
6113
  const e = row2.entry;
5647
6114
  const retired = e?.status === "retired";
5648
6115
  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)(
6116
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
6117
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
6118
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5652
6119
  "button",
5653
6120
  {
5654
6121
  type: "button",
@@ -5658,28 +6125,28 @@ var __defProp = Object.defineProperty;
5658
6125
  children: expanded.has(row2.slug) ? "▾" : "▸"
5659
6126
  }
5660
6127
  ),
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: [
6128
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
6129
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
5663
6130
  row2.slug,
5664
6131
  e?.source === "pre-registered" ? " ⭐" : ""
5665
6132
  ] }),
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
6133
+ e?.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: e.label }) : null,
6134
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
6135
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
6136
+ retired ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
6137
+ (e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
5671
6138
  ] }),
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: () => {
6139
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
6140
+ !hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6141
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
5675
6142
  setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
5676
6143
  setRenaming(null);
5677
6144
  }, style: btn2, children: "编辑" }),
5678
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
6145
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
5679
6146
  setRenaming({ slug: row2.slug, to: "" });
5680
6147
  setEditing(null);
5681
6148
  }, style: btn2, children: "改名" }),
5682
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6149
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5683
6150
  "button",
5684
6151
  {
5685
6152
  type: "button",
@@ -5690,29 +6157,29 @@ var __defProp = Object.defineProperty;
5690
6157
  children: retired ? "恢复" : "退役"
5691
6158
  }
5692
6159
  ),
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
6160
+ !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
6161
  ] }),
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: () => {
6162
+ grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6163
+ /* @__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: "收编" }),
6164
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
5698
6165
  setRenaming(null);
5699
6166
  retire(row2.slug, false, true);
5700
6167
  }, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
5701
6168
  ] }) : null,
5702
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
6169
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
5703
6170
  ] })
5704
6171
  ] }),
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) }),
6172
+ 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: [
6173
+ (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: [
6174
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: tagClass(it.type), children: typeLabel(it.type) }),
5708
6175
  " ",
5709
- it.retired ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
6176
+ it.retired ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
5710
6177
  " ",
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 })
6178
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
6179
+ /* @__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
6180
  ] }, 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
6181
+ (records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
6182
+ (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
6183
  ] }) : null
5717
6184
  ] }, row2.slug);
5718
6185
  })
@@ -5720,13 +6187,13 @@ var __defProp = Object.defineProperty;
5720
6187
  }
5721
6188
 
5722
6189
  // client/src/tabs/ScenesTab.tsx
5723
- var import_react21 = require("react");
5724
- var import_jsx_runtime21 = require("react/jsx-runtime");
6190
+ var import_react23 = require("react");
6191
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5725
6192
  function SceneCard(props) {
5726
6193
  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)(
6194
+ const [open, setOpen] = (0, import_react23.useState)(false);
6195
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
6196
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5730
6197
  "div",
5731
6198
  {
5732
6199
  style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
@@ -5734,23 +6201,23 @@ var __defProp = Object.defineProperty;
5734
6201
  setOpen(!open);
5735
6202
  },
5736
6203
  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) })
6204
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
6205
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.sceneTitle, children: s.path }),
6206
+ s.heat ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
6207
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.grow }),
6208
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
5742
6209
  ]
5743
6210
  }
5744
6211
  ),
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
6212
+ s.summary ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
6213
+ open ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
5747
6214
  ] });
5748
6215
  }
5749
6216
  function ScenesTab(props) {
5750
6217
  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)(() => {
6218
+ const [items, setItems] = (0, import_react23.useState)(null);
6219
+ const [error, setError] = (0, import_react23.useState)(null);
6220
+ const load = (0, import_react23.useCallback)(() => {
5754
6221
  rpc("dsh-memory/scenes", {}).then((r) => {
5755
6222
  if (r && r.ok) {
5756
6223
  setItems(r.value.items);
@@ -5760,25 +6227,25 @@ var __defProp = Object.defineProperty;
5760
6227
  setError(String(e && e.message || e));
5761
6228
  });
5762
6229
  }, [rpc]);
5763
- (0, import_react21.useEffect)(() => {
6230
+ (0, import_react23.useEffect)(() => {
5764
6231
  load();
5765
6232
  }, [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: "刷新" })
6233
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
6234
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
6235
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
6236
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.grow }),
6237
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NButton, { onClick: load, children: "刷新" })
5771
6238
  ] }),
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,
6239
+ error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.error, children: error }) : null,
6240
+ items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
5774
6241
  (items || []).map((s) => {
5775
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SceneCard, { s }, s.path);
6242
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SceneCard, { s }, s.path);
5776
6243
  })
5777
6244
  ] });
5778
6245
  }
5779
6246
 
5780
6247
  // client/src/panel.tsx
5781
- var import_jsx_runtime22 = require("react/jsx-runtime");
6248
+ var import_jsx_runtime23 = require("react/jsx-runtime");
5782
6249
  var TABS = [
5783
6250
  ["overview", "概览"],
5784
6251
  ["records", "记忆"],
@@ -5799,10 +6266,10 @@ var __defProp = Object.defineProperty;
5799
6266
  ];
5800
6267
  function MemoryPanel(props) {
5801
6268
  const rpc = props.rpc;
5802
- const [tab, setTab] = (0, import_react22.useState)("overview");
5803
- const [skin, setSkinState] = (0, import_react22.useState)(() => getSkin());
6269
+ const [tab, setTab] = (0, import_react24.useState)("overview");
6270
+ const [skin, setSkinState] = (0, import_react24.useState)(() => getSkin());
5804
6271
  ensureThemeStyle(skin);
5805
- (0, import_react22.useEffect)(() => {
6272
+ (0, import_react24.useEffect)(() => {
5806
6273
  applySkin(skin);
5807
6274
  watchSidebarIcon();
5808
6275
  }, [skin]);
@@ -5811,21 +6278,21 @@ var __defProp = Object.defineProperty;
5811
6278
  setSkinState(next);
5812
6279
  };
5813
6280
  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)(
6281
+ if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(OverviewTab, { rpc });
6282
+ else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RecordsTab, { rpc });
6283
+ else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ConflictsTab, { rpc });
6284
+ else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenesTab, { rpc });
6285
+ else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RoomsTab, { rpc });
6286
+ else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RoomTab, { rpc });
6287
+ else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PersonaTab, { rpc });
6288
+ else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CostTab, { rpc });
6289
+ else if (tab === "connect") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ConnectTab, { rpc });
6290
+ else if (tab === "skills") body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkillsTab, { rpc });
6291
+ else body = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LogTab, { rpc });
6292
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
6293
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
6294
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
6295
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5829
6296
  "div",
5830
6297
  {
5831
6298
  style: {
@@ -5837,8 +6304,8 @@ var __defProp = Object.defineProperty;
5837
6304
  marginBottom: 10
5838
6305
  },
5839
6306
  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)(
6307
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)", marginRight: 4 }, children: "皮肤" }),
6308
+ SKIN_OPTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5842
6309
  "button",
5843
6310
  {
5844
6311
  className: skin === s[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5851,8 +6318,8 @@ var __defProp = Object.defineProperty;
5851
6318
  ]
5852
6319
  }
5853
6320
  ),
5854
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
5855
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6321
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
6322
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5856
6323
  "button",
5857
6324
  {
5858
6325
  className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -5869,7 +6336,7 @@ var __defProp = Object.defineProperty;
5869
6336
  }
5870
6337
 
5871
6338
  // client/src/pill/MemoryModePill.tsx
5872
- var import_react25 = require("react");
6339
+ var import_react27 = require("react");
5873
6340
 
5874
6341
  // src/util/context-occupancy.ts
5875
6342
  var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
@@ -6185,23 +6652,23 @@ var __defProp = Object.defineProperty;
6185
6652
  }
6186
6653
 
6187
6654
  // client/src/pill/WingWheel.tsx
6188
- var import_react24 = require("react");
6655
+ var import_react26 = require("react");
6189
6656
 
6190
6657
  // client/src/pill/SessionInfoArea.tsx
6191
- var import_react23 = require("react");
6192
- var import_jsx_runtime23 = require("react/jsx-runtime");
6658
+ var import_react25 = require("react");
6659
+ var import_jsx_runtime24 = require("react/jsx-runtime");
6193
6660
  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 })
6661
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { title: title || void 0, children: [
6662
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
6663
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
6197
6664
  ] });
6198
6665
  }
6199
6666
  function SessionInfoArea(props) {
6200
6667
  const rpc = props.rpc;
6201
6668
  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)(() => {
6669
+ const [stats, setStats] = (0, import_react25.useState)(void 0);
6670
+ const busyRef = (0, import_react25.useRef)(false);
6671
+ (0, import_react25.useEffect)(() => {
6205
6672
  if (!rpc || !sessionId) return void 0;
6206
6673
  let alive = true;
6207
6674
  let timer = null;
@@ -6234,7 +6701,7 @@ var __defProp = Object.defineProperty;
6234
6701
  }, [rpc, sessionId]);
6235
6702
  if (stats === null) return null;
6236
6703
  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: [
6704
+ 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
6705
  sinfoCell("…", "召回命中"),
6239
6706
  sinfoCell("…", "攒批进度"),
6240
6707
  sinfoCell("…", "本会话记忆"),
@@ -6283,21 +6750,21 @@ var __defProp = Object.defineProperty;
6283
6750
  else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
6284
6751
  }
6285
6752
  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: [
6753
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo", children: [
6754
+ warn ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
6755
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
6289
6756
  sinfoCell(rcVal, rcLabel, rcTitle),
6290
6757
  sinfoCell(dVal, dLabel, dTitle),
6291
6758
  sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
6292
6759
  sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
6293
6760
  ] }),
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 || "尚未蒸馏") })
6761
+ note ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
6762
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
6296
6763
  ] });
6297
6764
  }
6298
6765
 
6299
6766
  // client/src/pill/WingWheel.tsx
6300
- var import_jsx_runtime24 = require("react/jsx-runtime");
6767
+ var import_jsx_runtime25 = require("react/jsx-runtime");
6301
6768
  var SIZE = 196;
6302
6769
  var CENTER = SIZE / 2;
6303
6770
  var R = 64;
@@ -6340,19 +6807,8 @@ var __defProp = Object.defineProperty;
6340
6807
  function WingWheel(props) {
6341
6808
  ensureThemeStyle();
6342
6809
  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)(() => {
6810
+ const [overview, setOverview] = (0, import_react26.useState)(null);
6811
+ (0, import_react26.useEffect)(() => {
6356
6812
  let alive = true;
6357
6813
  props.rpc("dsh-memory/wing-overview", {}).then((r) => {
6358
6814
  if (!alive) return;
@@ -6368,110 +6824,28 @@ var __defProp = Object.defineProperty;
6368
6824
  if (id === "general") return overview.general;
6369
6825
  return overview.corners.find((c) => c.id === id)?.count ?? 0;
6370
6826
  };
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);
6827
+ const boxRef = (0, import_react26.useRef)(null);
6828
+ const startRef = (0, import_react26.useRef)(null);
6829
+ const movedRef = (0, import_react26.useRef)(false);
6830
+ const downIndexRef = (0, import_react26.useRef)(null);
6831
+ const dragTargetRef = (0, import_react26.useRef)(null);
6832
+ const [drag, setDrag] = (0, import_react26.useState)(null);
6459
6833
  const lockedIndex = (() => {
6460
6834
  if (props.halls.length !== 1 || !overview) return null;
6461
6835
  const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
6462
6836
  return i >= 0 ? i : null;
6463
6837
  })();
6464
6838
  const activeCorner = drag ? drag.index : lockedIndex;
6465
- const blockPosRef = (0, import_react24.useRef)(
6839
+ const blockPosRef = (0, import_react26.useRef)(
6466
6840
  activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
6467
6841
  );
6468
- const blockTargetRef = (0, import_react24.useRef)(blockPosRef.current);
6469
- const [blockPos, setBlockPos] = (0, import_react24.useState)(blockPosRef.current);
6470
- (0, import_react24.useEffect)(() => {
6842
+ const blockTargetRef = (0, import_react26.useRef)(blockPosRef.current);
6843
+ const [blockPos, setBlockPos] = (0, import_react26.useState)(blockPosRef.current);
6844
+ (0, import_react26.useEffect)(() => {
6471
6845
  blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
6472
6846
  }, [activeCorner]);
6473
- const reducedMotionRef = (0, import_react24.useRef)(false);
6474
- (0, import_react24.useEffect)(() => {
6847
+ const reducedMotionRef = (0, import_react26.useRef)(false);
6848
+ (0, import_react26.useEffect)(() => {
6475
6849
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
6476
6850
  const apply2 = () => {
6477
6851
  reducedMotionRef.current = mq.matches;
@@ -6480,7 +6854,7 @@ var __defProp = Object.defineProperty;
6480
6854
  mq.addEventListener("change", apply2);
6481
6855
  return () => mq.removeEventListener("change", apply2);
6482
6856
  }, []);
6483
- (0, import_react24.useEffect)(() => {
6857
+ (0, import_react26.useEffect)(() => {
6484
6858
  let raf = 0;
6485
6859
  const loop = () => {
6486
6860
  const cur = blockPosRef.current;
@@ -6569,8 +6943,8 @@ var __defProp = Object.defineProperty;
6569
6943
  }).join(" ");
6570
6944
  const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
6571
6945
  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)(
6946
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { width: SIZE }, children: [
6947
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6574
6948
  "div",
6575
6949
  {
6576
6950
  ref: boxRef,
@@ -6580,7 +6954,7 @@ var __defProp = Object.defineProperty;
6580
6954
  onPointerUp: onBoxUp,
6581
6955
  onPointerCancel: onBoxUp,
6582
6956
  children: [
6583
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6957
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6584
6958
  "svg",
6585
6959
  {
6586
6960
  width: SIZE,
@@ -6588,7 +6962,7 @@ var __defProp = Object.defineProperty;
6588
6962
  style: { position: "absolute", inset: 0, pointerEvents: "none" },
6589
6963
  "aria-hidden": "true",
6590
6964
  children: [
6591
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6965
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6592
6966
  "polygon",
6593
6967
  {
6594
6968
  points: polyPoints,
@@ -6599,7 +6973,7 @@ var __defProp = Object.defineProperty;
6599
6973
  opacity: 0.45
6600
6974
  }
6601
6975
  ),
6602
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6976
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6603
6977
  "polygon",
6604
6978
  {
6605
6979
  points: polyPoints,
@@ -6610,7 +6984,7 @@ var __defProp = Object.defineProperty;
6610
6984
  ),
6611
6985
  [0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
6612
6986
  const p = cornerPos(i);
6613
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6987
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6614
6988
  "line",
6615
6989
  {
6616
6990
  x1: CENTER,
@@ -6626,7 +7000,7 @@ var __defProp = Object.defineProperty;
6626
7000
  ]
6627
7001
  }
6628
7002
  ),
6629
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7003
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6630
7004
  "div",
6631
7005
  {
6632
7006
  "aria-hidden": "true",
@@ -6645,7 +7019,7 @@ var __defProp = Object.defineProperty;
6645
7019
  }
6646
7020
  }
6647
7021
  ),
6648
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7022
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6649
7023
  "button",
6650
7024
  {
6651
7025
  type: "button",
@@ -6679,7 +7053,7 @@ var __defProp = Object.defineProperty;
6679
7053
  const dim = activeCorner != null && !active;
6680
7054
  const empty = count === 0;
6681
7055
  const p = cornerPos(i);
6682
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7056
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6683
7057
  "div",
6684
7058
  {
6685
7059
  title: id ? `「${label}」${count ?? 0} 条
@@ -6708,8 +7082,8 @@ var __defProp = Object.defineProperty;
6708
7082
  zIndex: 2
6709
7083
  },
6710
7084
  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} 条` })
7085
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }),
7086
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
6713
7087
  ]
6714
7088
  },
6715
7089
  id ?? i
@@ -6718,7 +7092,7 @@ var __defProp = Object.defineProperty;
6718
7092
  ]
6719
7093
  }
6720
7094
  ),
6721
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7095
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6722
7096
  "div",
6723
7097
  {
6724
7098
  title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
@@ -6732,9 +7106,9 @@ var __defProp = Object.defineProperty;
6732
7106
  pointerEvents: boundariesDisabled ? "none" : void 0
6733
7107
  },
6734
7108
  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)(
7109
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
7110
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
7111
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6738
7112
  Segmented,
6739
7113
  {
6740
7114
  value: props.hallIncludeUnlabeled ? "in" : "ex",
@@ -6745,7 +7119,7 @@ var __defProp = Object.defineProperty;
6745
7119
  onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
6746
7120
  }
6747
7121
  ),
6748
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7122
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6749
7123
  Segmented,
6750
7124
  {
6751
7125
  value: props.hallIncludeGeneral ? "in" : "ex",
@@ -6760,7 +7134,7 @@ var __defProp = Object.defineProperty;
6760
7134
  ]
6761
7135
  }
6762
7136
  ),
6763
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7137
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6764
7138
  Segmented,
6765
7139
  {
6766
7140
  value: isOff ? "off" : "on",
@@ -6775,7 +7149,7 @@ var __defProp = Object.defineProperty;
6775
7149
  onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
6776
7150
  }
6777
7151
  ) }),
6778
- props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7152
+ props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6779
7153
  Segmented,
6780
7154
  {
6781
7155
  value: props.recall === null ? "follow" : props.recall ? "on" : "off",
@@ -6788,60 +7162,12 @@ var __defProp = Object.defineProperty;
6788
7162
  onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
6789
7163
  }
6790
7164
  ) }) : 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 })
7165
+ props.error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error }) : null,
7166
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
6841
7167
  ] });
6842
7168
  }
6843
7169
  function Row(props) {
6844
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7170
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6845
7171
  "div",
6846
7172
  {
6847
7173
  style: {
@@ -6851,7 +7177,7 @@ var __defProp = Object.defineProperty;
6851
7177
  marginTop: 10
6852
7178
  },
6853
7179
  children: [
6854
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
7180
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
6855
7181
  props.children
6856
7182
  ]
6857
7183
  }
@@ -6859,9 +7185,9 @@ var __defProp = Object.defineProperty;
6859
7185
  }
6860
7186
  var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
6861
7187
  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)(() => {
7188
+ const shiftRef = (0, import_react26.useRef)(0);
7189
+ const [shiftX, setShiftX] = (0, import_react26.useState)(0);
7190
+ (0, import_react26.useEffect)(() => {
6865
7191
  const clamp = () => {
6866
7192
  const el = popRef.current;
6867
7193
  if (!el) return;
@@ -6891,24 +7217,24 @@ var __defProp = Object.defineProperty;
6891
7217
  }
6892
7218
 
6893
7219
  // client/src/pill/MemoryModePill.tsx
6894
- var import_jsx_runtime25 = require("react/jsx-runtime");
7220
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6895
7221
  function MemoryModePill(props) {
6896
7222
  const rpc = props.rpc;
6897
7223
  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);
7224
+ const [mode, setMode] = (0, import_react27.useState)(null);
7225
+ const [recall, setRecall] = (0, import_react27.useState)(null);
7226
+ const [recallResolved, setRecallResolved] = (0, import_react27.useState)(true);
7227
+ const [halls, setWings] = (0, import_react27.useState)([]);
7228
+ const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react27.useState)(true);
7229
+ const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react27.useState)(false);
7230
+ const [wingLabels, setHallLabels] = (0, import_react27.useState)({});
7231
+ const [error, setError] = (0, import_react27.useState)(null);
7232
+ const [open, setOpen] = (0, import_react27.useState)(false);
7233
+ const wrapRef = (0, import_react27.useRef)(null);
7234
+ const popRef = (0, import_react27.useRef)(null);
6909
7235
  const shiftX = useViewportClamp(popRef);
6910
- const seqRef = (0, import_react25.useRef)(0);
6911
- const load = (0, import_react25.useCallback)(() => {
7236
+ const seqRef = (0, import_react27.useRef)(0);
7237
+ const load = (0, import_react27.useCallback)(() => {
6912
7238
  if (!sessionId || !rpc) return;
6913
7239
  const token = ++seqRef.current;
6914
7240
  setError(null);
@@ -6933,13 +7259,13 @@ var __defProp = Object.defineProperty;
6933
7259
  }).catch(() => {
6934
7260
  });
6935
7261
  }, [sessionId, rpc]);
6936
- (0, import_react25.useEffect)(() => {
7262
+ (0, import_react27.useEffect)(() => {
6937
7263
  load();
6938
7264
  }, [load]);
6939
- (0, import_react25.useEffect)(() => {
7265
+ (0, import_react27.useEffect)(() => {
6940
7266
  watchSidebarIcon();
6941
7267
  }, []);
6942
- (0, import_react25.useEffect)(() => {
7268
+ (0, import_react27.useEffect)(() => {
6943
7269
  initOccupancyIndicator(
6944
7270
  (endpoint, payload) => rpc(endpoint, payload)
6945
7271
  );
@@ -6947,7 +7273,7 @@ var __defProp = Object.defineProperty;
6947
7273
  watchContextMeter();
6948
7274
  noteOccupancySession(sessionId ?? null);
6949
7275
  }, [sessionId, rpc]);
6950
- (0, import_react25.useEffect)(() => {
7276
+ (0, import_react27.useEffect)(() => {
6951
7277
  if (!open) return;
6952
7278
  const onDown = (e) => {
6953
7279
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -7087,8 +7413,8 @@ var __defProp = Object.defineProperty;
7087
7413
  pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
7088
7414
  pillStyle["--dsh-mem-pill-tint"] = info.color;
7089
7415
  }
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)(
7416
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
7417
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
7092
7418
  "button",
7093
7419
  {
7094
7420
  type: "button",
@@ -7101,11 +7427,11 @@ var __defProp = Object.defineProperty;
7101
7427
  style: pillStyle,
7102
7428
  children: [
7103
7429
  "记忆 · ",
7104
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: faceLabel })
7430
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: faceLabel })
7105
7431
  ]
7106
7432
  }
7107
7433
  ),
7108
- open ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7434
+ open ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7109
7435
  "div",
7110
7436
  {
7111
7437
  ref: popRef,
@@ -7116,12 +7442,12 @@ var __defProp = Object.defineProperty;
7116
7442
  transform: "translateX(calc(-50% + " + shiftX + "px))",
7117
7443
  zIndex: 1e3
7118
7444
  },
7119
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7445
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7120
7446
  "div",
7121
7447
  {
7122
7448
  className: "dsh-mem-popover",
7123
7449
  style: { position: "relative", padding: "10px 12px" },
7124
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7450
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7125
7451
  WingWheel,
7126
7452
  {
7127
7453
  mode: mode || "auto",