dsh-prime-memory 0.20.0-beta.9 → 0.20.2
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/CHANGELOG.md +183 -0
- package/ENGINEERING-NOTES.md +17 -0
- package/dist/client.js +1017 -447
- package/dist/config.d.ts +0 -120
- package/dist/config.js +1 -21
- package/dist/contract.d.ts +28 -57
- package/dist/hooks/recall.d.ts +4 -1
- package/dist/hooks/recall.js +7 -1
- package/dist/hooks/slot-recall.js +24 -1
- package/dist/index.d.ts +0 -78
- package/dist/index.js +9 -21
- package/dist/metadata-validators.d.ts +5 -0
- package/dist/metadata-validators.js +11 -1
- package/dist/pipeline/recluster.js +1 -1
- package/dist/projection/slots.d.ts +23 -1
- package/dist/projection/slots.js +65 -21
- package/dist/room-review.d.ts +8 -1
- package/dist/room-review.js +10 -4
- package/dist/stats.d.ts +15 -33
- package/dist/stats.js +72 -204
- package/dist/store/l1.d.ts +2 -0
- package/dist/store/l1.js +4 -0
- package/dist/store/recall-usage.d.ts +43 -0
- package/dist/store/recall-usage.js +149 -0
- package/dist/store/rooms-registry.d.ts +11 -4
- package/dist/store/rooms-registry.js +33 -16
- package/dist/store/session-modes.d.ts +0 -8
- package/dist/store/session-modes.js +0 -52
- package/dist/store/slots.d.ts +3 -1
- package/dist/store/slots.js +2 -1
- package/dist/tools/index.js +21 -0
- package/package.json +1 -1
- package/dist/hooks/long-task.d.ts +0 -31
- package/dist/hooks/long-task.js +0 -93
- package/dist/store/context-usage.d.ts +0 -28
- package/dist/store/context-usage.js +0 -47
- package/dist/store/todo-ref.d.ts +0 -41
- package/dist/store/todo-ref.js +0 -65
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
|
|
35
|
+
var import_react19 = 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>';
|
|
@@ -1645,8 +1645,8 @@ var __defProp = Object.defineProperty;
|
|
|
1645
1645
|
setOpen(false);
|
|
1646
1646
|
setIdx(-1);
|
|
1647
1647
|
if (refocus && wrapRef.current) {
|
|
1648
|
-
const
|
|
1649
|
-
if (
|
|
1648
|
+
const btn3 = wrapRef.current.querySelector("button");
|
|
1649
|
+
if (btn3 && btn3.focus) btn3.focus();
|
|
1650
1650
|
}
|
|
1651
1651
|
};
|
|
1652
1652
|
const pick = (id) => {
|
|
@@ -3268,7 +3268,6 @@ var __defProp = Object.defineProperty;
|
|
|
3268
3268
|
"work_artifact"
|
|
3269
3269
|
];
|
|
3270
3270
|
var DELETE_LIMIT = 200;
|
|
3271
|
-
var ROOM_PAGE_SIZE = 40;
|
|
3272
3271
|
function RecordsTab(props) {
|
|
3273
3272
|
const rpc = props.rpc;
|
|
3274
3273
|
const limit = 50;
|
|
@@ -3289,18 +3288,8 @@ var __defProp = Object.defineProperty;
|
|
|
3289
3288
|
const [hallFilter, setHallFilter] = (0, import_react15.useState)([]);
|
|
3290
3289
|
const [tagFilter, setTagFilter] = (0, import_react15.useState)("");
|
|
3291
3290
|
const [untaggedOnly, setUntaggedOnly] = (0, import_react15.useState)(false);
|
|
3292
|
-
const [roomsOpen, setRoomsOpen] = (0, import_react15.useState)(() => {
|
|
3293
|
-
try {
|
|
3294
|
-
return window.localStorage.getItem("dsh.memory.rooms.open") === "1";
|
|
3295
|
-
} catch {
|
|
3296
|
-
return false;
|
|
3297
|
-
}
|
|
3298
|
-
});
|
|
3299
|
-
const [roomPage, setRoomPage] = (0, import_react15.useState)(0);
|
|
3300
3291
|
const [orphanCount, setOrphanCount] = (0, import_react15.useState)(0);
|
|
3301
|
-
const [roomRegistry, setRoomRegistry] = (0, import_react15.useState)([]);
|
|
3302
3292
|
const [retiredFilter, setRetiredFilter] = (0, import_react15.useState)("");
|
|
3303
|
-
const [rooms, setRooms] = (0, import_react15.useState)([]);
|
|
3304
3293
|
const [wingCatalog, setHallCatalog] = (0, import_react15.useState)(null);
|
|
3305
3294
|
const [last, setLast] = (0, import_react15.useState)({ query: "", type: "", scene: "", halls: [], tag: "", untagged: false, retired: "" });
|
|
3306
3295
|
const seqRef = (0, import_react15.useRef)(0);
|
|
@@ -3327,6 +3316,7 @@ var __defProp = Object.defineProperty;
|
|
|
3327
3316
|
}
|
|
3328
3317
|
const v = r.value;
|
|
3329
3318
|
setItems((prev) => append ? prev.concat(v.items) : v.items);
|
|
3319
|
+
if (v.usageSummary) setUsageSummary(v.usageSummary);
|
|
3330
3320
|
if (!append) setSel(/* @__PURE__ */ new Set());
|
|
3331
3321
|
setHasMore(!!v.hasMore);
|
|
3332
3322
|
setTotal(v.total === void 0 || v.total === null ? null : v.total);
|
|
@@ -3354,11 +3344,7 @@ var __defProp = Object.defineProperty;
|
|
|
3354
3344
|
};
|
|
3355
3345
|
const loadRooms = (0, import_react15.useCallback)(() => {
|
|
3356
3346
|
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
3357
|
-
if (r && r.ok)
|
|
3358
|
-
setRooms(r.value.rooms ?? []);
|
|
3359
|
-
setOrphanCount(r.value.orphanCount ?? 0);
|
|
3360
|
-
setRoomRegistry(r.value.registry ?? []);
|
|
3361
|
-
}
|
|
3347
|
+
if (r && r.ok) setOrphanCount(r.value.orphanCount ?? 0);
|
|
3362
3348
|
}).catch(() => {
|
|
3363
3349
|
});
|
|
3364
3350
|
}, [rpc]);
|
|
@@ -3466,6 +3452,7 @@ var __defProp = Object.defineProperty;
|
|
|
3466
3452
|
unknown: "已退场"
|
|
3467
3453
|
};
|
|
3468
3454
|
const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
|
|
3455
|
+
const [usageSummary, setUsageSummary] = (0, import_react15.useState)(null);
|
|
3469
3456
|
const selCount = sel.size;
|
|
3470
3457
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
3471
3458
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.toolbar, children: [
|
|
@@ -3532,222 +3519,86 @@ var __defProp = Object.defineProperty;
|
|
|
3532
3519
|
}
|
|
3533
3520
|
)
|
|
3534
3521
|
] }),
|
|
3535
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { marginBottom: 10 }, children: [
|
|
3536
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
]
|
|
3565
|
-
}
|
|
3566
|
-
),
|
|
3567
|
-
rooms.length > 0 || orphanCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
3568
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3569
|
-
"button",
|
|
3570
|
-
{
|
|
3571
|
-
type: "button",
|
|
3572
|
-
title: "导出分类数据 CSV(Room 词表+计数)",
|
|
3573
|
-
onClick: () => {
|
|
3574
|
-
rpc("dsh-memory/rooms-export", { kind: "rooms" }).then((r) => {
|
|
3575
|
-
if (!r || !r.ok || !r.value?.csv) return;
|
|
3576
|
-
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
3577
|
-
const url = URL.createObjectURL(blob);
|
|
3578
|
-
const a = document.createElement("a");
|
|
3579
|
-
a.href = url;
|
|
3580
|
-
a.download = "dsh-memory-rooms.csv";
|
|
3581
|
-
a.click();
|
|
3582
|
-
URL.revokeObjectURL(url);
|
|
3583
|
-
}).catch(() => void 0);
|
|
3584
|
-
},
|
|
3585
|
-
style: {
|
|
3586
|
-
cursor: "pointer",
|
|
3587
|
-
fontSize: 12,
|
|
3588
|
-
padding: "2px 8px",
|
|
3589
|
-
borderRadius: 6,
|
|
3590
|
-
border: "1px solid var(--dsh-mem-border)",
|
|
3591
|
-
background: "transparent",
|
|
3592
|
-
color: "var(--dsh-mem-text-2)"
|
|
3593
|
-
},
|
|
3594
|
-
children: "导出 CSV"
|
|
3595
|
-
}
|
|
3596
|
-
),
|
|
3597
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3598
|
-
"button",
|
|
3599
|
-
{
|
|
3600
|
-
type: "button",
|
|
3601
|
-
title: "导出无 Room 绑定的孤儿清单(含候选)",
|
|
3602
|
-
onClick: () => {
|
|
3603
|
-
rpc("dsh-memory/rooms-export", { kind: "orphans" }).then((r) => {
|
|
3604
|
-
if (!r || !r.ok || !r.value?.csv) return;
|
|
3605
|
-
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
3606
|
-
const url = URL.createObjectURL(blob);
|
|
3607
|
-
const a = document.createElement("a");
|
|
3608
|
-
a.href = url;
|
|
3609
|
-
a.download = "dsh-memory-room-orphans.csv";
|
|
3610
|
-
a.click();
|
|
3611
|
-
URL.revokeObjectURL(url);
|
|
3612
|
-
}).catch(() => void 0);
|
|
3613
|
-
},
|
|
3614
|
-
style: {
|
|
3615
|
-
cursor: "pointer",
|
|
3616
|
-
fontSize: 12,
|
|
3617
|
-
padding: "2px 8px",
|
|
3618
|
-
borderRadius: 6,
|
|
3619
|
-
border: "1px solid var(--dsh-mem-border)",
|
|
3620
|
-
background: "transparent",
|
|
3621
|
-
color: "var(--dsh-mem-text-2)"
|
|
3622
|
-
},
|
|
3623
|
-
children: "导出孤儿"
|
|
3624
|
-
}
|
|
3625
|
-
)
|
|
3626
|
-
] }) : null,
|
|
3522
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { marginBottom: 10, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
|
|
3523
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3524
|
+
"button",
|
|
3525
|
+
{
|
|
3526
|
+
type: "button",
|
|
3527
|
+
title: untaggedOnly ? "取消孤儿筛选" : "只看没有任何 Room 绑定的记忆",
|
|
3528
|
+
onClick: () => {
|
|
3529
|
+
const next = !untaggedOnly;
|
|
3530
|
+
setUntaggedOnly(next);
|
|
3531
|
+
if (next) setTagFilter("");
|
|
3532
|
+
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: next ? "" : tagFilter, untagged: next, retired: retiredFilter };
|
|
3533
|
+
setLast(conds);
|
|
3534
|
+
fetchPage(conds, 0, false);
|
|
3535
|
+
},
|
|
3536
|
+
style: {
|
|
3537
|
+
cursor: "pointer",
|
|
3538
|
+
fontSize: 12,
|
|
3539
|
+
padding: "2px 8px",
|
|
3540
|
+
borderRadius: 999,
|
|
3541
|
+
border: untaggedOnly ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
3542
|
+
background: untaggedOnly ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
3543
|
+
color: untaggedOnly ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
3544
|
+
},
|
|
3545
|
+
children: "无绑定 · " + orphanCount
|
|
3546
|
+
}
|
|
3547
|
+
),
|
|
3548
|
+
(tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: S.muted, children: [
|
|
3549
|
+
"筛选中:",
|
|
3550
|
+
untaggedOnly ? "无绑定" : tagFilter,
|
|
3627
3551
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3628
3552
|
"button",
|
|
3629
3553
|
{
|
|
3630
3554
|
type: "button",
|
|
3631
|
-
title:
|
|
3555
|
+
title: "清除 Room/孤儿筛选",
|
|
3632
3556
|
onClick: () => {
|
|
3633
|
-
|
|
3634
|
-
setUntaggedOnly(
|
|
3635
|
-
|
|
3636
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: next ? "" : tagFilter, untagged: next, retired: retiredFilter };
|
|
3557
|
+
setTagFilter("");
|
|
3558
|
+
setUntaggedOnly(false);
|
|
3559
|
+
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: "", untagged: false, retired: retiredFilter };
|
|
3637
3560
|
setLast(conds);
|
|
3638
3561
|
fetchPage(conds, 0, false);
|
|
3639
3562
|
},
|
|
3640
|
-
style: {
|
|
3641
|
-
|
|
3642
|
-
fontSize: 12,
|
|
3643
|
-
padding: "2px 8px",
|
|
3644
|
-
borderRadius: 999,
|
|
3645
|
-
border: untaggedOnly ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
3646
|
-
background: untaggedOnly ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
3647
|
-
color: untaggedOnly ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
3648
|
-
},
|
|
3649
|
-
children: "无绑定 · " + orphanCount
|
|
3563
|
+
style: { cursor: "pointer", marginLeft: 6, background: "transparent", border: "none", color: "var(--dsh-mem-accent)", fontSize: 12 },
|
|
3564
|
+
children: "×清除"
|
|
3650
3565
|
}
|
|
3651
|
-
)
|
|
3652
|
-
(tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: S.muted, children: [
|
|
3653
|
-
"筛选中:",
|
|
3654
|
-
untaggedOnly ? "无绑定" : tagFilter,
|
|
3655
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3656
|
-
"button",
|
|
3657
|
-
{
|
|
3658
|
-
type: "button",
|
|
3659
|
-
title: "清除 Room/孤儿筛选",
|
|
3660
|
-
onClick: () => {
|
|
3661
|
-
setTagFilter("");
|
|
3662
|
-
setUntaggedOnly(false);
|
|
3663
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: "", untagged: false, retired: retiredFilter };
|
|
3664
|
-
setLast(conds);
|
|
3665
|
-
fetchPage(conds, 0, false);
|
|
3666
|
-
},
|
|
3667
|
-
style: { cursor: "pointer", marginLeft: 6, background: "transparent", border: "none", color: "var(--dsh-mem-accent)", fontSize: 12 },
|
|
3668
|
-
children: "×清除"
|
|
3669
|
-
}
|
|
3670
|
-
)
|
|
3671
|
-
] })
|
|
3566
|
+
)
|
|
3672
3567
|
] }),
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
},
|
|
3704
|
-
r.room
|
|
3705
|
-
);
|
|
3706
|
-
}),
|
|
3707
|
-
!roomsOpen && rooms.length > 8 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: S.muted, children: [
|
|
3708
|
-
"(收拢中,共 ",
|
|
3709
|
-
rooms.length,
|
|
3710
|
-
" 个)"
|
|
3711
|
-
] }) : null
|
|
3712
|
-
] }),
|
|
3713
|
-
roomsOpen && rooms.length > ROOM_PAGE_SIZE ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
|
|
3714
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: S.muted, children: [
|
|
3715
|
-
"第 ",
|
|
3716
|
-
roomPage + 1,
|
|
3717
|
-
" / ",
|
|
3718
|
-
Math.ceil(rooms.length / ROOM_PAGE_SIZE),
|
|
3719
|
-
" 页(共 ",
|
|
3720
|
-
rooms.length,
|
|
3721
|
-
")"
|
|
3722
|
-
] }),
|
|
3723
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3724
|
-
"button",
|
|
3725
|
-
{
|
|
3726
|
-
type: "button",
|
|
3727
|
-
title: "上一页",
|
|
3728
|
-
disabled: roomPage === 0,
|
|
3729
|
-
onClick: () => setRoomPage((p) => Math.max(0, p - 1)),
|
|
3730
|
-
style: { cursor: roomPage === 0 ? "default" : "pointer", fontSize: 12, padding: "2px 8px", borderRadius: 6, border: "1px solid var(--dsh-mem-border)", background: "transparent", color: "var(--dsh-mem-text-2)" },
|
|
3731
|
-
children: "◀"
|
|
3732
|
-
}
|
|
3733
|
-
),
|
|
3734
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3735
|
-
"button",
|
|
3736
|
-
{
|
|
3737
|
-
type: "button",
|
|
3738
|
-
title: "下一页",
|
|
3739
|
-
disabled: (roomPage + 1) * ROOM_PAGE_SIZE >= rooms.length,
|
|
3740
|
-
onClick: () => setRoomPage((p) => (p + 1) * ROOM_PAGE_SIZE < rooms.length ? p + 1 : p),
|
|
3741
|
-
style: { cursor: (roomPage + 1) * ROOM_PAGE_SIZE >= rooms.length ? "default" : "pointer", fontSize: 12, padding: "2px 8px", borderRadius: 6, border: "1px solid var(--dsh-mem-border)", background: "transparent", color: "var(--dsh-mem-text-2)" },
|
|
3742
|
-
children: "▶"
|
|
3743
|
-
}
|
|
3744
|
-
)
|
|
3745
|
-
] }) : null,
|
|
3746
|
-
roomsOpen && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: 8, paddingTop: 8, borderTop: "1px solid var(--dsh-mem-border)" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "分类管理(注册 / 收编 / 合并 / 改名 / 退役 / 按 Room 导出):请前往「Hall」标签页。" }) })
|
|
3747
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.muted, children: "Room 分类:暂无(由反刍涌现的标签自动生成,无需手工建立)" })
|
|
3568
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3569
|
+
"button",
|
|
3570
|
+
{
|
|
3571
|
+
type: "button",
|
|
3572
|
+
title: "导出无 Room 绑定的孤儿清单 CSV(含候选)",
|
|
3573
|
+
onClick: () => {
|
|
3574
|
+
rpc("dsh-memory/rooms-export", { kind: "orphans" }).then((r) => {
|
|
3575
|
+
if (!r || !r.ok || !r.value?.csv) return;
|
|
3576
|
+
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
3577
|
+
const url = URL.createObjectURL(blob);
|
|
3578
|
+
const a = document.createElement("a");
|
|
3579
|
+
a.href = url;
|
|
3580
|
+
a.download = "dsh-memory-room-orphans.csv";
|
|
3581
|
+
a.click();
|
|
3582
|
+
URL.revokeObjectURL(url);
|
|
3583
|
+
}).catch(() => void 0);
|
|
3584
|
+
},
|
|
3585
|
+
style: {
|
|
3586
|
+
cursor: "pointer",
|
|
3587
|
+
fontSize: 12,
|
|
3588
|
+
padding: "2px 8px",
|
|
3589
|
+
borderRadius: 6,
|
|
3590
|
+
border: "1px solid var(--dsh-mem-border)",
|
|
3591
|
+
background: "transparent",
|
|
3592
|
+
color: "var(--dsh-mem-text-2)"
|
|
3593
|
+
},
|
|
3594
|
+
children: "导出孤儿"
|
|
3595
|
+
}
|
|
3596
|
+
),
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "Room 标签/分类管理:见「Hall」「Room」标签页。" })
|
|
3748
3598
|
] }),
|
|
3749
3599
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
|
|
3750
3600
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
|
|
3601
|
+
usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
|
|
3751
3602
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "退场筛查" }),
|
|
3752
3603
|
[["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
|
|
3753
3604
|
const on = retiredFilter === val;
|
|
@@ -3851,6 +3702,29 @@ var __defProp = Object.defineProperty;
|
|
|
3851
3702
|
}
|
|
3852
3703
|
) : null,
|
|
3853
3704
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
|
|
3705
|
+
m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3706
|
+
"span",
|
|
3707
|
+
{
|
|
3708
|
+
style: {
|
|
3709
|
+
fontSize: 11,
|
|
3710
|
+
padding: "1px 6px",
|
|
3711
|
+
borderRadius: 999,
|
|
3712
|
+
whiteSpace: "nowrap",
|
|
3713
|
+
border: "1px solid " + (m.agingWeight <= 0.6 ? "var(--dsh-mem-danger)" : "var(--dsh-mem-border)"),
|
|
3714
|
+
color: m.agingWeight <= 0.6 ? "var(--dsh-mem-danger)" : "var(--dsh-mem-text-2)"
|
|
3715
|
+
},
|
|
3716
|
+
title: "老化权重 " + Math.round(m.agingWeight * 100) + "%(读路径衰减系数 max(0.5, 0.5^(Δ天/半衰期)));越低越老",
|
|
3717
|
+
children: "老化 " + Math.round(m.agingWeight * 100) + "%"
|
|
3718
|
+
}
|
|
3719
|
+
) : null,
|
|
3720
|
+
m.usage ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3721
|
+
"span",
|
|
3722
|
+
{
|
|
3723
|
+
style: S.muted,
|
|
3724
|
+
title: "召回使用 " + m.usage.used + "/" + m.usage.attempts + "(进 topN 才算 used)" + (m.usage.lastUsedAt ? ";最近使用 " + fmtTime(new Date(m.usage.lastUsedAt).toISOString()) : "") + (m.usage.lastAttemptAt ? ";最近尝试 " + fmtTime(new Date(m.usage.lastAttemptAt).toISOString()) : ""),
|
|
3725
|
+
children: "用 " + m.usage.used + "/" + m.usage.attempts
|
|
3726
|
+
}
|
|
3727
|
+
) : null,
|
|
3854
3728
|
m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
|
|
3855
3729
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
|
|
3856
3730
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
|
|
@@ -3980,6 +3854,10 @@ var __defProp = Object.defineProperty;
|
|
|
3980
3854
|
const i = slug.indexOf("/");
|
|
3981
3855
|
return i === -1 ? slug : slug.slice(0, i);
|
|
3982
3856
|
}
|
|
3857
|
+
function suffixOf(slug) {
|
|
3858
|
+
const i = slug.indexOf("/");
|
|
3859
|
+
return i === -1 ? slug : slug.slice(i + 1);
|
|
3860
|
+
}
|
|
3983
3861
|
function downloadCsv(csv, name) {
|
|
3984
3862
|
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
|
|
3985
3863
|
const url = URL.createObjectURL(blob);
|
|
@@ -4014,6 +3892,46 @@ var __defProp = Object.defineProperty;
|
|
|
4014
3892
|
const [form, setForm] = (0, import_react16.useState)(null);
|
|
4015
3893
|
const [preview, setPreview] = (0, import_react16.useState)(null);
|
|
4016
3894
|
const [grownOpen, setGrownOpen] = (0, import_react16.useState)(false);
|
|
3895
|
+
const [dragOverHall, setDragOverHall] = (0, import_react16.useState)(null);
|
|
3896
|
+
const [picking, setPicking] = (0, import_react16.useState)(null);
|
|
3897
|
+
const [editing, setEditing] = (0, import_react16.useState)(null);
|
|
3898
|
+
const [expandedRooms, setExpandedRooms] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
|
|
3899
|
+
const [roomRecords, setRoomRecords] = (0, import_react16.useState)({});
|
|
3900
|
+
const [expandedHalls, setExpandedHalls] = (0, import_react16.useState)(() => {
|
|
3901
|
+
try {
|
|
3902
|
+
const v = window.localStorage.getItem("dsh.memory.halls.open");
|
|
3903
|
+
return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
|
|
3904
|
+
} catch {
|
|
3905
|
+
return /* @__PURE__ */ new Set();
|
|
3906
|
+
}
|
|
3907
|
+
});
|
|
3908
|
+
const [filter, setFilter] = (0, import_react16.useState)("");
|
|
3909
|
+
const dragRef = (0, import_react16.useRef)(null);
|
|
3910
|
+
const [ghost, setGhost] = (0, import_react16.useState)(null);
|
|
3911
|
+
const onDragLabelDown = (ev, slug) => {
|
|
3912
|
+
if (!hiPriv || busy || ev.button !== 0) return;
|
|
3913
|
+
ev.currentTarget.setPointerCapture(ev.pointerId);
|
|
3914
|
+
dragRef.current = { from: slug, x: ev.clientX, y: ev.clientY, active: false };
|
|
3915
|
+
};
|
|
3916
|
+
const onDragLabelMove = (ev) => {
|
|
3917
|
+
const d = dragRef.current;
|
|
3918
|
+
if (!d) return;
|
|
3919
|
+
if (!d.active && Math.hypot(ev.clientX - d.x, ev.clientY - d.y) > 6) d.active = true;
|
|
3920
|
+
if (!d.active) return;
|
|
3921
|
+
setGhost({ x: ev.clientX, y: ev.clientY, text: d.from });
|
|
3922
|
+
const hall = document.elementFromPoint(ev.clientX, ev.clientY)?.closest?.("[data-hall]")?.getAttribute("data-hall") ?? null;
|
|
3923
|
+
setDragOverHall(hall);
|
|
3924
|
+
};
|
|
3925
|
+
const onDragLabelUp = (ev) => {
|
|
3926
|
+
const d = dragRef.current;
|
|
3927
|
+
dragRef.current = null;
|
|
3928
|
+
setGhost(null);
|
|
3929
|
+
if (!d) return;
|
|
3930
|
+
if (!d.active) return;
|
|
3931
|
+
const hall = document.elementFromPoint(ev.clientX, ev.clientY)?.closest?.("[data-hall]")?.getAttribute("data-hall");
|
|
3932
|
+
setDragOverHall(null);
|
|
3933
|
+
if (hall) beginReclass(d.from, hall);
|
|
3934
|
+
};
|
|
4017
3935
|
const loadAll = (0, import_react16.useCallback)(() => {
|
|
4018
3936
|
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
4019
3937
|
if (r && r.ok) {
|
|
@@ -4075,24 +3993,55 @@ var __defProp = Object.defineProperty;
|
|
|
4075
3993
|
loadAll();
|
|
4076
3994
|
} else setError(r && r.error ? r.error.message : "收编失败");
|
|
4077
3995
|
});
|
|
4078
|
-
const previewMerge = () => run(async () => {
|
|
4079
|
-
|
|
4080
|
-
|
|
3996
|
+
const previewMerge = (override) => run(async () => {
|
|
3997
|
+
const fm = override ?? form;
|
|
3998
|
+
if (!fm) return;
|
|
3999
|
+
const to = fm.to.trim();
|
|
4081
4000
|
if (!to) {
|
|
4082
4001
|
setError("目标 slug 不能为空");
|
|
4083
4002
|
return;
|
|
4084
4003
|
}
|
|
4085
|
-
if (to ===
|
|
4004
|
+
if (to === fm.from) {
|
|
4086
4005
|
setError("目标与源相同");
|
|
4087
4006
|
return;
|
|
4088
4007
|
}
|
|
4089
|
-
const r = await rpc("dsh-memory/room-admin", { action:
|
|
4008
|
+
const r = await rpc("dsh-memory/room-admin", { action: fm.action, from: fm.from, to });
|
|
4090
4009
|
if (r && r.ok) {
|
|
4091
|
-
setPreview({ action:
|
|
4010
|
+
setPreview({ action: fm.action, from: fm.from, to, notice: String(r.value?.notice ?? "") });
|
|
4092
4011
|
} else setError(r && r.error ? r.error.message : "预览失败");
|
|
4093
4012
|
});
|
|
4013
|
+
const beginReclass = (from, hall) => {
|
|
4014
|
+
if (!busy) {
|
|
4015
|
+
setMsg(null);
|
|
4016
|
+
setError(null);
|
|
4017
|
+
}
|
|
4018
|
+
if (!hall) {
|
|
4019
|
+
setError("尚无 hall:先注册一个(如 dsh-plugin),再归类。");
|
|
4020
|
+
return;
|
|
4021
|
+
}
|
|
4022
|
+
if (majorOf(from) === hall) {
|
|
4023
|
+
if (registry.some((e) => e.slug === from)) {
|
|
4024
|
+
setMsg(`${from} 已在 ${hall} 下。`);
|
|
4025
|
+
return;
|
|
4026
|
+
}
|
|
4027
|
+
setPicking(null);
|
|
4028
|
+
void adopt(from);
|
|
4029
|
+
return;
|
|
4030
|
+
}
|
|
4031
|
+
const f = { action: "rename", from, to: `${hall}/${suffixOf(from)}` };
|
|
4032
|
+
setForm(f);
|
|
4033
|
+
setPreview(null);
|
|
4034
|
+
void previewMerge(f);
|
|
4035
|
+
};
|
|
4094
4036
|
const execMerge = () => run(async () => {
|
|
4095
4037
|
if (!preview) return;
|
|
4038
|
+
if (preview.action === "rename" && !registry.some((e) => e.slug === preview.from)) {
|
|
4039
|
+
const rr = await rpc("dsh-memory/room-register", { slug: preview.from, source: "grown" });
|
|
4040
|
+
if (!rr || !rr.ok) {
|
|
4041
|
+
setError(rr && rr.error ? rr.error.message : "收编源失败");
|
|
4042
|
+
return;
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4096
4045
|
const r = await rpc("dsh-memory/room-admin", { action: preview.action, from: preview.from, to: preview.to, dryRun: false });
|
|
4097
4046
|
if (r && r.ok) {
|
|
4098
4047
|
setMsg(String(r.value?.notice ?? "完成"));
|
|
@@ -4101,16 +4050,45 @@ var __defProp = Object.defineProperty;
|
|
|
4101
4050
|
loadAll();
|
|
4102
4051
|
} else setError(r && r.error ? r.error.message : "执行失败");
|
|
4103
4052
|
});
|
|
4104
|
-
const retire = (slug, active) => run(async () => {
|
|
4105
|
-
if (!active
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4053
|
+
const retire = (slug, active, withRecords = false) => run(async () => {
|
|
4054
|
+
if (!active) {
|
|
4055
|
+
const tip = withRecords ? `退役 Room:${slug} 并退场其下全部记忆?(记录为软删,可在记忆页「已退场」区逐条恢复)` : `退役 Room:${slug}?(存量记录的 tags 不动,仅词表不再推荐;可随时恢复)`;
|
|
4056
|
+
if (!window.confirm(tip)) return;
|
|
4057
|
+
}
|
|
4058
|
+
const r = await rpc("dsh-memory/room-admin", { action: "retire", slug, active, withRecords: withRecords || void 0 });
|
|
4109
4059
|
if (r && r.ok) {
|
|
4110
4060
|
setMsg(String(r.value?.notice ?? "完成"));
|
|
4111
4061
|
loadAll();
|
|
4062
|
+
if (expandedRooms.has(slug)) {
|
|
4063
|
+
const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4064
|
+
if (rr && rr.ok) setRoomRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
|
|
4065
|
+
}
|
|
4112
4066
|
} else setError(r && r.error ? r.error.message : "操作失败");
|
|
4113
4067
|
});
|
|
4068
|
+
const saveEditing = () => run(async () => {
|
|
4069
|
+
if (!editing) return;
|
|
4070
|
+
const r = await rpc("dsh-memory/room-admin", { action: "update", slug: editing.slug, label: editing.label, description: editing.description });
|
|
4071
|
+
if (r && r.ok) {
|
|
4072
|
+
setMsg(String(r.value?.notice ?? "已更新"));
|
|
4073
|
+
setEditing(null);
|
|
4074
|
+
loadAll();
|
|
4075
|
+
} else setError(r && r.error ? r.error.message : "更新失败");
|
|
4076
|
+
});
|
|
4077
|
+
const toggleRoomExpand = (slug) => run(async () => {
|
|
4078
|
+
if (expandedRooms.has(slug)) {
|
|
4079
|
+
const next = new Set(expandedRooms);
|
|
4080
|
+
next.delete(slug);
|
|
4081
|
+
setExpandedRooms(next);
|
|
4082
|
+
return;
|
|
4083
|
+
}
|
|
4084
|
+
const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4085
|
+
if (r && r.ok) {
|
|
4086
|
+
const next = new Set(expandedRooms);
|
|
4087
|
+
next.add(slug);
|
|
4088
|
+
setExpandedRooms(next);
|
|
4089
|
+
setRoomRecords((m) => ({ ...m, [slug]: { items: r.value.items, total: r.value.total ?? null } }));
|
|
4090
|
+
} else setError(r && r.error ? r.error.message : "加载失败");
|
|
4091
|
+
});
|
|
4114
4092
|
const exportRecords = (slug) => run(async () => {
|
|
4115
4093
|
const r = await rpc("dsh-memory/rooms-export", { kind: "records", tag: slug });
|
|
4116
4094
|
if (!r.ok) {
|
|
@@ -4124,6 +4102,7 @@ var __defProp = Object.defineProperty;
|
|
|
4124
4102
|
const countOf = new Map(rooms.map((r) => [r.room, r.count]));
|
|
4125
4103
|
const byHall = /* @__PURE__ */ new Map();
|
|
4126
4104
|
for (const e of registry) {
|
|
4105
|
+
if (e.status !== "active") continue;
|
|
4127
4106
|
const hall = majorOf(e.slug);
|
|
4128
4107
|
const list = byHall.get(hall);
|
|
4129
4108
|
if (list) list.push(e);
|
|
@@ -4137,6 +4116,39 @@ var __defProp = Object.defineProperty;
|
|
|
4137
4116
|
})).sort((a, b) => a.hall.localeCompare(b.hall));
|
|
4138
4117
|
}, [registry, rooms]);
|
|
4139
4118
|
const grownOnly = (0, import_react16.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
|
|
4119
|
+
const persistHalls = (next) => {
|
|
4120
|
+
try {
|
|
4121
|
+
window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
|
|
4122
|
+
} catch {
|
|
4123
|
+
}
|
|
4124
|
+
};
|
|
4125
|
+
const toggleHall = (hall) => setExpandedHalls((cur) => {
|
|
4126
|
+
const next = new Set(cur);
|
|
4127
|
+
if (next.has(hall)) next.delete(hall);
|
|
4128
|
+
else next.add(hall);
|
|
4129
|
+
persistHalls(next);
|
|
4130
|
+
return next;
|
|
4131
|
+
});
|
|
4132
|
+
const setAllHalls = (open) => {
|
|
4133
|
+
const next = open ? new Set(groups.map((g) => g.hall)) : /* @__PURE__ */ new Set();
|
|
4134
|
+
setExpandedHalls(next);
|
|
4135
|
+
persistHalls(next);
|
|
4136
|
+
};
|
|
4137
|
+
const normFilter = filter.trim().toLowerCase();
|
|
4138
|
+
const visibleGroups = (0, import_react16.useMemo)(() => {
|
|
4139
|
+
if (!normFilter) return groups;
|
|
4140
|
+
return groups.map((g) => {
|
|
4141
|
+
const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
|
|
4142
|
+
const entries = hallHit ? g.entries : g.entries.filter(
|
|
4143
|
+
(e) => e.slug.toLowerCase().includes(normFilter) || (e.label ?? "").toLowerCase().includes(normFilter) || (e.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
|
|
4144
|
+
);
|
|
4145
|
+
return { ...g, entries };
|
|
4146
|
+
}).filter((g) => g.entries.length > 0);
|
|
4147
|
+
}, [groups, normFilter]);
|
|
4148
|
+
const visibleGrown = (0, import_react16.useMemo)(
|
|
4149
|
+
() => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
|
|
4150
|
+
[grownOnly, normFilter]
|
|
4151
|
+
);
|
|
4140
4152
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
4141
4153
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
|
|
4142
4154
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
|
|
@@ -4195,6 +4207,22 @@ var __defProp = Object.defineProperty;
|
|
|
4195
4207
|
),
|
|
4196
4208
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
|
|
4197
4209
|
] }),
|
|
4210
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4211
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4212
|
+
"input",
|
|
4213
|
+
{
|
|
4214
|
+
value: filter,
|
|
4215
|
+
onChange: (e) => setFilter(e.target.value),
|
|
4216
|
+
placeholder: "搜索 hall/room(slug、显示名、别名)",
|
|
4217
|
+
style: { ...S.input, width: 250, fontSize: 12 }
|
|
4218
|
+
}
|
|
4219
|
+
),
|
|
4220
|
+
filter ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
|
|
4221
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
|
|
4222
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4223
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
|
|
4224
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
|
|
4225
|
+
] }),
|
|
4198
4226
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
|
|
4199
4227
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4200
4228
|
"input",
|
|
@@ -4238,116 +4266,656 @@ var __defProp = Object.defineProperty;
|
|
|
4238
4266
|
),
|
|
4239
4267
|
!hiPriv && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
|
|
4240
4268
|
] }),
|
|
4269
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime16.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: [
|
|
4270
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: S.muted, children: [
|
|
4271
|
+
"编辑 ",
|
|
4272
|
+
editing.slug
|
|
4273
|
+
] }),
|
|
4274
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { value: editing.label, onChange: (ev) => setEditing({ ...editing, label: ev.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
|
|
4275
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { value: editing.description, onChange: (ev) => setEditing({ ...editing, description: ev.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
|
|
4276
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
|
|
4277
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
|
|
4278
|
+
] }) : null,
|
|
4279
|
+
form ? /* @__PURE__ */ (0, import_jsx_runtime16.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: [
|
|
4280
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: S.muted, children: [
|
|
4281
|
+
form.action === "merge" ? "合并" : "归类/改名",
|
|
4282
|
+
" ",
|
|
4283
|
+
form.from,
|
|
4284
|
+
" →"
|
|
4285
|
+
] }),
|
|
4286
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4287
|
+
"input",
|
|
4288
|
+
{
|
|
4289
|
+
value: form.to,
|
|
4290
|
+
onChange: (ev) => setForm({ ...form, to: ev.target.value }),
|
|
4291
|
+
placeholder: "目标 slug",
|
|
4292
|
+
disabled: busy,
|
|
4293
|
+
style: { ...S.input, width: 190, fontSize: 12 }
|
|
4294
|
+
}
|
|
4295
|
+
),
|
|
4296
|
+
form.action === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime16.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_runtime16.jsx)(
|
|
4297
|
+
"button",
|
|
4298
|
+
{
|
|
4299
|
+
type: "button",
|
|
4300
|
+
title: `归入 ${gg.hall} 下(${gg.hall}/${suffixOf(form.from)})`,
|
|
4301
|
+
onClick: () => setForm({ ...form, to: `${gg.hall}/${suffixOf(form.from)}` }),
|
|
4302
|
+
style: { ...btn, borderRadius: 999, padding: "1px 8px" },
|
|
4303
|
+
children: gg.hall
|
|
4304
|
+
},
|
|
4305
|
+
gg.hall
|
|
4306
|
+
)) }) : null,
|
|
4307
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => previewMerge(), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
|
|
4308
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => {
|
|
4309
|
+
setForm(null);
|
|
4310
|
+
setPreview(null);
|
|
4311
|
+
setPicking(null);
|
|
4312
|
+
}, style: btn, children: "取消" }),
|
|
4313
|
+
picking ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
|
|
4314
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
|
|
4315
|
+
] }) : null,
|
|
4316
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime16.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: [
|
|
4317
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children: preview.notice }),
|
|
4318
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
|
|
4319
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", disabled: busy, onClick: execMerge, style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: [
|
|
4320
|
+
"确认执行",
|
|
4321
|
+
preview.action === "merge" ? "合并" : "归类/改名"
|
|
4322
|
+
] }),
|
|
4323
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
|
|
4324
|
+
] })
|
|
4325
|
+
] }) : null,
|
|
4241
4326
|
msg ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.hint, children: msg }) : null,
|
|
4242
4327
|
error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: error }) : null,
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
|
|
4250
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4251
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4252
|
-
"button",
|
|
4328
|
+
ghost ? /* @__PURE__ */ (0, import_jsx_runtime16.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,
|
|
4329
|
+
visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: normFilter ? "无匹配的 hall/room。" : "注册表为空。在上方注册 Hall/Room(如 dsh-plugin),或把自生长 slug「收编」进词表 —— 之后候选标注器会优先把相关记忆挂到这些 slug 上。" }) : visibleGroups.map((g) => {
|
|
4330
|
+
const hallOpen = !!normFilter || expandedHalls.has(g.hall);
|
|
4331
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
|
|
4332
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4333
|
+
"div",
|
|
4253
4334
|
{
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4278
|
-
!hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
4279
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
|
|
4280
|
-
setForm({ action: "rename", from: e.slug, to: "" });
|
|
4281
|
-
setPreview(null);
|
|
4282
|
-
}, style: btn, children: "改名" }),
|
|
4283
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
|
|
4284
|
-
setForm({ action: "merge", from: e.slug, to: "" });
|
|
4285
|
-
setPreview(null);
|
|
4286
|
-
}, style: btn, children: "合并" }),
|
|
4287
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.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 ? "恢复" : "退役" })
|
|
4288
|
-
] }),
|
|
4289
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
|
|
4290
|
-
] }),
|
|
4291
|
-
form && form.from === e.slug ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, marginTop: 4, flexWrap: "wrap" }, children: [
|
|
4292
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: S.muted, children: [
|
|
4293
|
-
form.action === "merge" ? "合并" : "改名",
|
|
4294
|
-
" ",
|
|
4295
|
-
form.from,
|
|
4296
|
-
" →"
|
|
4297
|
-
] }),
|
|
4298
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4299
|
-
"input",
|
|
4300
|
-
{
|
|
4301
|
-
value: form.to,
|
|
4302
|
-
onChange: (ev) => setForm({ ...form, to: ev.target.value }),
|
|
4303
|
-
placeholder: "目标 slug",
|
|
4304
|
-
disabled: busy,
|
|
4305
|
-
style: { ...S.input, width: 180, fontSize: 12 }
|
|
4335
|
+
"data-hall": g.hall,
|
|
4336
|
+
onDragOver: (ev) => {
|
|
4337
|
+
if (!hiPriv || busy) return;
|
|
4338
|
+
ev.preventDefault();
|
|
4339
|
+
ev.dataTransfer.dropEffect = "move";
|
|
4340
|
+
setDragOverHall(g.hall);
|
|
4341
|
+
},
|
|
4342
|
+
onDragLeave: () => setDragOverHall((cur) => cur === g.hall ? null : cur),
|
|
4343
|
+
onDrop: (ev) => {
|
|
4344
|
+
ev.preventDefault();
|
|
4345
|
+
setDragOverHall(null);
|
|
4346
|
+
if (!hiPriv || busy) return;
|
|
4347
|
+
const from = ev.dataTransfer.getData("text/dsh-room");
|
|
4348
|
+
if (from) beginReclass(from, g.hall);
|
|
4349
|
+
},
|
|
4350
|
+
onClick: () => {
|
|
4351
|
+
if (picking) {
|
|
4352
|
+
if (!busy) {
|
|
4353
|
+
const from = picking;
|
|
4354
|
+
setPicking(null);
|
|
4355
|
+
beginReclass(from, g.hall);
|
|
4356
|
+
}
|
|
4357
|
+
return;
|
|
4306
4358
|
}
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4359
|
+
toggleHall(g.hall);
|
|
4360
|
+
},
|
|
4361
|
+
style: {
|
|
4362
|
+
display: "flex",
|
|
4363
|
+
alignItems: "center",
|
|
4364
|
+
gap: 8,
|
|
4365
|
+
padding: "5px 10px",
|
|
4366
|
+
background: "var(--dsh-mem-bg-inset)",
|
|
4367
|
+
outline: dragOverHall === g.hall || picking !== null ? "2px dashed var(--dsh-mem-accent)" : void 0,
|
|
4368
|
+
outlineOffset: dragOverHall === g.hall || picking !== null ? "-2px" : void 0,
|
|
4369
|
+
cursor: "pointer"
|
|
4370
|
+
},
|
|
4371
|
+
title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
|
|
4372
|
+
children: [
|
|
4373
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4374
|
+
"button",
|
|
4375
|
+
{
|
|
4376
|
+
type: "button",
|
|
4377
|
+
title: hallOpen ? "收起子 room" : "展开子 room(默认折叠)",
|
|
4378
|
+
onClick: (ev) => {
|
|
4379
|
+
ev.stopPropagation();
|
|
4380
|
+
toggleHall(g.hall);
|
|
4381
|
+
},
|
|
4382
|
+
style: { ...btn, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4383
|
+
children: hallOpen ? "▾" : "▸"
|
|
4384
|
+
}
|
|
4385
|
+
),
|
|
4386
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
|
|
4387
|
+
g.hall,
|
|
4388
|
+
g.label ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
|
|
4321
4389
|
] }),
|
|
4322
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4390
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
|
|
4391
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4392
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4393
|
+
"button",
|
|
4394
|
+
{
|
|
4395
|
+
type: "button",
|
|
4396
|
+
disabled: !hiPriv || busy,
|
|
4397
|
+
title: `预填注册表单为 ${g.hall}/…(注册该 hall 下的小类)`,
|
|
4398
|
+
onClick: (ev) => {
|
|
4399
|
+
ev.stopPropagation();
|
|
4400
|
+
setRegSlug(g.hall + "/");
|
|
4401
|
+
},
|
|
4402
|
+
style: btn,
|
|
4403
|
+
children: "+小类"
|
|
4404
|
+
}
|
|
4405
|
+
)
|
|
4406
|
+
]
|
|
4407
|
+
}
|
|
4408
|
+
),
|
|
4409
|
+
hallOpen ? g.entries.map((e) => {
|
|
4410
|
+
const standalone = e.slug === g.hall;
|
|
4411
|
+
const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
|
|
4412
|
+
const retired = e.status === "retired";
|
|
4413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "4px 10px", borderTop: "1px solid var(--dsh-mem-border)", opacity: retired ? 0.55 : 1 }, children: [
|
|
4414
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
4415
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
|
|
4416
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4417
|
+
"button",
|
|
4418
|
+
{
|
|
4419
|
+
type: "button",
|
|
4420
|
+
title: expandedRooms.has(e.slug) ? "收起内容" : "展开查看该 Room 的记录内容(默认收起)",
|
|
4421
|
+
onClick: () => void toggleRoomExpand(e.slug),
|
|
4422
|
+
style: { ...btn, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4423
|
+
children: expandedRooms.has(e.slug) ? "▾" : "▸"
|
|
4424
|
+
}
|
|
4425
|
+
),
|
|
4426
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4427
|
+
"span",
|
|
4428
|
+
{
|
|
4429
|
+
style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
|
|
4430
|
+
onPointerDown: (ev) => onDragLabelDown(ev, e.slug),
|
|
4431
|
+
onPointerMove: onDragLabelMove,
|
|
4432
|
+
onPointerUp: onDragLabelUp,
|
|
4433
|
+
title: hiPriv && !busy ? "按住拖到某个 hall 头上归类(major/minor;记录随迁,旧名进别名)" : e.description ? `${e.slug} — ${e.description}` : e.slug,
|
|
4434
|
+
children: [
|
|
4435
|
+
standalone ? e.slug : "· " + e.slug.slice(g.hall.length + 1),
|
|
4436
|
+
e.source === "pre-registered" ? " ⭐" : ""
|
|
4437
|
+
]
|
|
4438
|
+
}
|
|
4439
|
+
),
|
|
4440
|
+
e.label ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: e.label }) : null,
|
|
4441
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: count + " 条" }),
|
|
4442
|
+
retired ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
|
|
4443
|
+
(e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
|
|
4444
|
+
] }),
|
|
4445
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
|
|
4446
|
+
!hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
4447
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
|
|
4448
|
+
setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
|
|
4449
|
+
setForm(null);
|
|
4450
|
+
setPreview(null);
|
|
4451
|
+
setPicking(null);
|
|
4452
|
+
}, style: btn, children: "编辑" }),
|
|
4453
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4454
|
+
"button",
|
|
4455
|
+
{
|
|
4456
|
+
type: "button",
|
|
4457
|
+
disabled: busy,
|
|
4458
|
+
title: picking === e.slug ? "再点一次取消挑选;然后点击目标 hall 头完成归类" : "归类到已有 hall 下:点击后选目标 hall(记录随迁,旧名进别名)",
|
|
4459
|
+
onClick: () => {
|
|
4460
|
+
if (picking === e.slug) {
|
|
4461
|
+
setPicking(null);
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4464
|
+
setForm({ action: "rename", from: e.slug, to: "" });
|
|
4465
|
+
setPreview(null);
|
|
4466
|
+
setPicking(e.slug);
|
|
4467
|
+
setMsg(null);
|
|
4468
|
+
setError(null);
|
|
4469
|
+
},
|
|
4470
|
+
style: { ...btn, ...picking === e.slug ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : {} },
|
|
4471
|
+
children: picking === e.slug ? "选 hall…" : "归类"
|
|
4472
|
+
}
|
|
4473
|
+
),
|
|
4474
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
|
|
4475
|
+
setForm({ action: "rename", from: e.slug, to: "" });
|
|
4476
|
+
setPreview(null);
|
|
4477
|
+
}, style: btn, children: "改名" }),
|
|
4478
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
|
|
4479
|
+
setForm({ action: "merge", from: e.slug, to: "" });
|
|
4480
|
+
setPreview(null);
|
|
4481
|
+
}, style: btn, children: "合并" }),
|
|
4482
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.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 ? "恢复" : "退役" }),
|
|
4483
|
+
!retired ? /* @__PURE__ */ (0, import_jsx_runtime16.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
|
|
4484
|
+
] }),
|
|
4485
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
|
|
4486
|
+
] })
|
|
4487
|
+
] }),
|
|
4488
|
+
expandedRooms.has(e.slug) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { margin: "4px 0 2px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
|
|
4489
|
+
(roomRecords[e.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
|
|
4490
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
|
|
4491
|
+
" ",
|
|
4492
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
|
|
4493
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.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 })
|
|
4494
|
+
] }, it.id)),
|
|
4495
|
+
(roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
|
|
4496
|
+
(roomRecords[e.slug]?.total ?? 0) > (roomRecords[e.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + roomRecords[e.slug].total + " 条,仅显示前 " + roomRecords[e.slug].items.length + " 条" }) : null
|
|
4497
|
+
] }) : null
|
|
4498
|
+
] }, e.slug);
|
|
4499
|
+
}) : null
|
|
4500
|
+
] }, g.hall);
|
|
4501
|
+
}),
|
|
4502
|
+
visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginTop: 4 }, children: [
|
|
4329
4503
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
|
|
4330
4504
|
grownOpen ? "▾" : "▸",
|
|
4331
4505
|
" 自生长未注册 · 共 ",
|
|
4332
|
-
|
|
4506
|
+
visibleGrown.length
|
|
4333
4507
|
] }),
|
|
4334
4508
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
|
|
4335
|
-
grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children:
|
|
4336
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4337
|
-
|
|
4509
|
+
grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children: visibleGrown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
|
|
4510
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4511
|
+
"span",
|
|
4512
|
+
{
|
|
4513
|
+
style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
|
|
4514
|
+
onPointerDown: (ev) => onDragLabelDown(ev, r.room),
|
|
4515
|
+
onPointerMove: onDragLabelMove,
|
|
4516
|
+
onPointerUp: onDragLabelUp,
|
|
4517
|
+
title: hiPriv && !busy ? "自生长 slug(未注册)——按住拖到某个 hall 头上 = 收编并归为其子类" : "自生长 slug(未注册)",
|
|
4518
|
+
children: r.room + " · " + r.count
|
|
4519
|
+
}
|
|
4520
|
+
),
|
|
4521
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.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: "收编" }),
|
|
4522
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4523
|
+
"button",
|
|
4524
|
+
{
|
|
4525
|
+
type: "button",
|
|
4526
|
+
disabled: !hiPriv || busy,
|
|
4527
|
+
title: "归类到已有 hall 下:点击后选目标 hall(收编+子类一步,记录随迁)",
|
|
4528
|
+
onClick: () => {
|
|
4529
|
+
if (picking === r.room) {
|
|
4530
|
+
setPicking(null);
|
|
4531
|
+
return;
|
|
4532
|
+
}
|
|
4533
|
+
setForm({ action: "rename", from: r.room, to: "" });
|
|
4534
|
+
setPreview(null);
|
|
4535
|
+
setPicking(r.room);
|
|
4536
|
+
setMsg(null);
|
|
4537
|
+
setError(null);
|
|
4538
|
+
},
|
|
4539
|
+
style: { ...btn, opacity: !hiPriv || busy ? 0.5 : 1, ...picking === r.room ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : {} },
|
|
4540
|
+
children: picking === r.room ? "选 hall…" : "归"
|
|
4541
|
+
}
|
|
4542
|
+
)
|
|
4338
4543
|
] }, r.room)) }) : null
|
|
4339
4544
|
] }) : null
|
|
4340
4545
|
] });
|
|
4341
4546
|
}
|
|
4342
4547
|
|
|
4343
|
-
// client/src/tabs/
|
|
4548
|
+
// client/src/tabs/RoomTab.tsx
|
|
4344
4549
|
var import_react17 = require("react");
|
|
4345
4550
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4551
|
+
var btn2 = {
|
|
4552
|
+
cursor: "pointer",
|
|
4553
|
+
fontSize: 12,
|
|
4554
|
+
padding: "2px 8px",
|
|
4555
|
+
borderRadius: 6,
|
|
4556
|
+
border: "1px solid var(--dsh-mem-border)",
|
|
4557
|
+
background: "transparent",
|
|
4558
|
+
color: "var(--dsh-mem-text-2)"
|
|
4559
|
+
};
|
|
4560
|
+
function downloadCsv2(csv, name) {
|
|
4561
|
+
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
|
|
4562
|
+
const url = URL.createObjectURL(blob);
|
|
4563
|
+
const a = document.createElement("a");
|
|
4564
|
+
a.href = url;
|
|
4565
|
+
a.download = name;
|
|
4566
|
+
a.click();
|
|
4567
|
+
URL.revokeObjectURL(url);
|
|
4568
|
+
}
|
|
4569
|
+
function RoomTab(props) {
|
|
4570
|
+
const rpc = props.rpc;
|
|
4571
|
+
const [registry, setRegistry] = (0, import_react17.useState)([]);
|
|
4572
|
+
const [counts, setCounts] = (0, import_react17.useState)([]);
|
|
4573
|
+
const [orphanCount, setOrphanCount] = (0, import_react17.useState)(0);
|
|
4574
|
+
const [busy, setBusy] = (0, import_react17.useState)(false);
|
|
4575
|
+
const [msg, setMsg] = (0, import_react17.useState)(null);
|
|
4576
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
4577
|
+
const [hiPriv, setHiPriv] = (0, import_react17.useState)(false);
|
|
4578
|
+
const [hiPrivBusy, setHiPrivBusy] = (0, import_react17.useState)(false);
|
|
4579
|
+
const [reg, setReg] = (0, import_react17.useState)({ slug: "", label: "", description: "" });
|
|
4580
|
+
const [editing, setEditing] = (0, import_react17.useState)(null);
|
|
4581
|
+
const [renaming, setRenaming] = (0, import_react17.useState)(null);
|
|
4582
|
+
const [expanded, setExpanded] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
|
|
4583
|
+
const [retiredFilter, setRetiredFilter] = (0, import_react17.useState)("");
|
|
4584
|
+
const [filter, setFilter] = (0, import_react17.useState)("");
|
|
4585
|
+
const [records, setRecords] = (0, import_react17.useState)({});
|
|
4586
|
+
const loadAll = (0, import_react17.useCallback)(() => {
|
|
4587
|
+
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
4588
|
+
if (r && r.ok) {
|
|
4589
|
+
setCounts(r.value.rooms ?? []);
|
|
4590
|
+
setRegistry(r.value.registry ?? []);
|
|
4591
|
+
setOrphanCount(r.value.orphanCount ?? 0);
|
|
4592
|
+
}
|
|
4593
|
+
}).catch(() => void 0);
|
|
4594
|
+
}, [rpc]);
|
|
4595
|
+
const loadHiPriv = (0, import_react17.useCallback)(() => {
|
|
4596
|
+
rpc("dsh-memory/settings-get", {}).then((r) => {
|
|
4597
|
+
if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
|
|
4598
|
+
}).catch(() => {
|
|
4599
|
+
});
|
|
4600
|
+
}, [rpc]);
|
|
4601
|
+
(0, import_react17.useEffect)(() => {
|
|
4602
|
+
loadAll();
|
|
4603
|
+
loadHiPriv();
|
|
4604
|
+
}, [loadAll, loadHiPriv]);
|
|
4605
|
+
const toggleHiPriv = () => {
|
|
4606
|
+
const next = !hiPriv;
|
|
4607
|
+
if (next && !window.confirm("开启高权限模式:模型获得写入/删除记忆工具,并解锁 Room 管理操作。确定开启?")) return;
|
|
4608
|
+
rpc("dsh-memory/settings-set", { memoryMutate: next }).then((r) => {
|
|
4609
|
+
if (r && r.ok) setHiPriv(next);
|
|
4610
|
+
setHiPrivBusy(false);
|
|
4611
|
+
loadHiPriv();
|
|
4612
|
+
}).catch(() => setHiPrivBusy(false));
|
|
4613
|
+
};
|
|
4614
|
+
const run = (fn) => {
|
|
4615
|
+
if (busy) return;
|
|
4616
|
+
setBusy(true);
|
|
4617
|
+
setError(null);
|
|
4618
|
+
setMsg(null);
|
|
4619
|
+
fn().finally(() => setBusy(false));
|
|
4620
|
+
};
|
|
4621
|
+
const register = () => run(async () => {
|
|
4622
|
+
const r = await rpc("dsh-memory/room-register", { slug: reg.slug.trim(), label: reg.label.trim() || void 0, description: reg.description.trim() || void 0 });
|
|
4623
|
+
if (r && r.ok) {
|
|
4624
|
+
setMsg(r.value?.notice ?? `已注册:${reg.slug.trim()}`);
|
|
4625
|
+
setReg({ slug: "", label: "", description: "" });
|
|
4626
|
+
loadAll();
|
|
4627
|
+
} else setError(r && r.error ? r.error.message : "注册失败");
|
|
4628
|
+
});
|
|
4629
|
+
const adopt = (slug) => run(async () => {
|
|
4630
|
+
const r = await rpc("dsh-memory/room-register", { slug, source: "grown" });
|
|
4631
|
+
if (r && r.ok) {
|
|
4632
|
+
setMsg(`已收编:${slug}(source=grown)`);
|
|
4633
|
+
loadAll();
|
|
4634
|
+
} else setError(r && r.error ? r.error.message : "收编失败");
|
|
4635
|
+
});
|
|
4636
|
+
const previewRename = () => run(async () => {
|
|
4637
|
+
if (!renaming) return;
|
|
4638
|
+
const to = renaming.to.trim();
|
|
4639
|
+
if (!to) {
|
|
4640
|
+
setError("目标 slug 不能为空");
|
|
4641
|
+
return;
|
|
4642
|
+
}
|
|
4643
|
+
if (to === renaming.slug) {
|
|
4644
|
+
setError("目标与源相同");
|
|
4645
|
+
return;
|
|
4646
|
+
}
|
|
4647
|
+
if (!registry.some((e) => e.slug === renaming.slug)) {
|
|
4648
|
+
const rr = await rpc("dsh-memory/room-register", { slug: renaming.slug, source: "grown" });
|
|
4649
|
+
if (!rr || !rr.ok) {
|
|
4650
|
+
setError(rr && rr.error ? rr.error.message : "收编源失败");
|
|
4651
|
+
return;
|
|
4652
|
+
}
|
|
4653
|
+
loadAll();
|
|
4654
|
+
}
|
|
4655
|
+
const r = await rpc("dsh-memory/room-admin", { action: "rename", from: renaming.slug, to });
|
|
4656
|
+
if (r && r.ok) setMsg(String(r.value?.notice ?? ""));
|
|
4657
|
+
else setError(r && r.error ? r.error.message : "预览失败");
|
|
4658
|
+
});
|
|
4659
|
+
const execRename = () => run(async () => {
|
|
4660
|
+
if (!renaming) return;
|
|
4661
|
+
if (!registry.some((e) => e.slug === renaming.slug)) {
|
|
4662
|
+
await rpc("dsh-memory/room-register", { slug: renaming.slug, source: "grown" });
|
|
4663
|
+
}
|
|
4664
|
+
const r = await rpc("dsh-memory/room-admin", { action: "rename", from: renaming.slug, to: renaming.to.trim(), dryRun: false });
|
|
4665
|
+
if (r && r.ok) {
|
|
4666
|
+
setMsg(String(r.value?.notice ?? "完成"));
|
|
4667
|
+
setRenaming(null);
|
|
4668
|
+
loadAll();
|
|
4669
|
+
} else setError(r && r.error ? r.error.message : "执行失败");
|
|
4670
|
+
});
|
|
4671
|
+
const saveEditing = () => run(async () => {
|
|
4672
|
+
if (!editing) return;
|
|
4673
|
+
const r = await rpc("dsh-memory/room-admin", { action: "update", slug: editing.slug, label: editing.label, description: editing.description });
|
|
4674
|
+
if (r && r.ok) {
|
|
4675
|
+
setMsg(String(r.value?.notice ?? "已更新"));
|
|
4676
|
+
setEditing(null);
|
|
4677
|
+
loadAll();
|
|
4678
|
+
} else setError(r && r.error ? r.error.message : "更新失败");
|
|
4679
|
+
});
|
|
4680
|
+
const retire = (slug, active, withRecords = false) => run(async () => {
|
|
4681
|
+
if (!active) {
|
|
4682
|
+
const tip = withRecords ? `退役 Room:${slug} 并退场其下全部记忆?(记录为软删,可在记忆页「已退场」区逐条恢复)` : `退役 Room:${slug}?(存量记录的 tags 不动,仅词表不再推荐;可随时恢复)`;
|
|
4683
|
+
if (!window.confirm(tip)) return;
|
|
4684
|
+
}
|
|
4685
|
+
const r = await rpc("dsh-memory/room-admin", { action: "retire", slug, active, withRecords: withRecords || void 0 });
|
|
4686
|
+
if (r && r.ok) {
|
|
4687
|
+
setMsg(String(r.value?.notice ?? "完成"));
|
|
4688
|
+
loadAll();
|
|
4689
|
+
if (expanded.has(slug)) {
|
|
4690
|
+
const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4691
|
+
if (rr && rr.ok) setRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
|
|
4692
|
+
}
|
|
4693
|
+
} else setError(r && r.error ? r.error.message : "操作失败");
|
|
4694
|
+
});
|
|
4695
|
+
const exportRecords = (slug) => run(async () => {
|
|
4696
|
+
const r = await rpc("dsh-memory/rooms-export", { kind: "records", tag: slug });
|
|
4697
|
+
if (!r.ok) {
|
|
4698
|
+
setError(r.error.message);
|
|
4699
|
+
return;
|
|
4700
|
+
}
|
|
4701
|
+
if (r.value.csv) {
|
|
4702
|
+
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
4703
|
+
const url = URL.createObjectURL(blob);
|
|
4704
|
+
const a = document.createElement("a");
|
|
4705
|
+
a.href = url;
|
|
4706
|
+
a.download = `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`;
|
|
4707
|
+
a.click();
|
|
4708
|
+
URL.revokeObjectURL(url);
|
|
4709
|
+
}
|
|
4710
|
+
});
|
|
4711
|
+
const toggleExpand = (slug) => run(async () => {
|
|
4712
|
+
if (expanded.has(slug)) {
|
|
4713
|
+
const next = new Set(expanded);
|
|
4714
|
+
next.delete(slug);
|
|
4715
|
+
setExpanded(next);
|
|
4716
|
+
return;
|
|
4717
|
+
}
|
|
4718
|
+
const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4719
|
+
if (r && r.ok) {
|
|
4720
|
+
const next = new Set(expanded);
|
|
4721
|
+
next.add(slug);
|
|
4722
|
+
setExpanded(next);
|
|
4723
|
+
setRecords((m) => ({ ...m, [slug]: { items: r.value.items, total: r.value.total ?? null } }));
|
|
4724
|
+
} else setError(r && r.error ? r.error.message : "加载失败");
|
|
4725
|
+
});
|
|
4726
|
+
const countOf = (slug) => counts.find((c) => c.room === slug)?.count ?? 0;
|
|
4727
|
+
const rows = [
|
|
4728
|
+
...registry.map((e) => ({ slug: e.slug, count: countOf(e.slug), entry: e })),
|
|
4729
|
+
...counts.filter((c) => !registry.some((e) => e.slug === c.room)).map((c) => ({ slug: c.room, count: c.count }))
|
|
4730
|
+
].filter((row2) => {
|
|
4731
|
+
if (retiredFilter === "active") return row2.entry?.status !== "retired";
|
|
4732
|
+
if (retiredFilter === "retired") return row2.entry?.status === "retired";
|
|
4733
|
+
return true;
|
|
4734
|
+
});
|
|
4735
|
+
const normFilter = filter.trim().toLowerCase();
|
|
4736
|
+
const visibleRows = normFilter ? rows.filter(
|
|
4737
|
+
(row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
|
|
4738
|
+
) : rows;
|
|
4739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
4740
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4741
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
|
|
4742
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
|
|
4743
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
|
|
4744
|
+
const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
|
|
4745
|
+
if (!r.ok) {
|
|
4746
|
+
setError(r.error.message);
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4749
|
+
if (r.value.csv) downloadCsv2(r.value.csv, "dsh-memory-room-orphans.csv");
|
|
4750
|
+
}), children: [
|
|
4751
|
+
"导出孤儿 · ",
|
|
4752
|
+
orphanCount
|
|
4753
|
+
] }),
|
|
4754
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4755
|
+
"button",
|
|
4756
|
+
{
|
|
4757
|
+
type: "button",
|
|
4758
|
+
style: { ...btn2, color: hiPriv ? "var(--dsh-mem-danger)" : void 0, border: hiPriv ? "1px solid var(--dsh-mem-danger)" : btn2.border },
|
|
4759
|
+
disabled: hiPrivBusy,
|
|
4760
|
+
title: hiPriv ? "关闭高权限模式" : "开启高权限模式以解锁 Room 管理操作",
|
|
4761
|
+
onClick: toggleHiPriv,
|
|
4762
|
+
children: hiPriv ? "高权限:开" : "高权限:关"
|
|
4763
|
+
}
|
|
4764
|
+
),
|
|
4765
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
|
|
4766
|
+
] }),
|
|
4767
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime17.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: [
|
|
4768
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
|
|
4769
|
+
"编辑 ",
|
|
4770
|
+
editing.slug
|
|
4771
|
+
] }),
|
|
4772
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: editing.label, onChange: (e) => setEditing({ ...editing, label: e.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
|
|
4773
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: editing.description, onChange: (e) => setEditing({ ...editing, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
|
|
4774
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
|
|
4775
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
|
|
4776
|
+
] }) : null,
|
|
4777
|
+
renaming ? /* @__PURE__ */ (0, import_jsx_runtime17.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: [
|
|
4778
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
|
|
4779
|
+
"改名 ",
|
|
4780
|
+
renaming.slug,
|
|
4781
|
+
" →"
|
|
4782
|
+
] }),
|
|
4783
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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 } }),
|
|
4784
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: previewRename, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
|
|
4785
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: execRename, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "确认执行" }),
|
|
4786
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
|
|
4787
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
|
|
4788
|
+
] }) : null,
|
|
4789
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4790
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "退场筛选" }),
|
|
4791
|
+
[["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
|
|
4792
|
+
const on = retiredFilter === val;
|
|
4793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4794
|
+
"button",
|
|
4795
|
+
{
|
|
4796
|
+
type: "button",
|
|
4797
|
+
title: val === "" ? "全部 room" : val === "active" ? "只看词表未退役的 room" : "只看已退役的 room",
|
|
4798
|
+
onClick: () => setRetiredFilter(val),
|
|
4799
|
+
style: {
|
|
4800
|
+
cursor: "pointer",
|
|
4801
|
+
fontSize: 12,
|
|
4802
|
+
padding: "2px 10px",
|
|
4803
|
+
borderRadius: 999,
|
|
4804
|
+
border: on ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
4805
|
+
background: on ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
4806
|
+
color: on ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
4807
|
+
},
|
|
4808
|
+
children: label
|
|
4809
|
+
},
|
|
4810
|
+
val
|
|
4811
|
+
);
|
|
4812
|
+
}),
|
|
4813
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
|
|
4814
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4815
|
+
"input",
|
|
4816
|
+
{
|
|
4817
|
+
value: filter,
|
|
4818
|
+
onChange: (e) => setFilter(e.target.value),
|
|
4819
|
+
placeholder: "搜索 room(slug、显示名、别名)",
|
|
4820
|
+
style: { ...S.input, width: 230, fontSize: 12 }
|
|
4821
|
+
}
|
|
4822
|
+
),
|
|
4823
|
+
filter ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
|
|
4824
|
+
] }),
|
|
4825
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
|
|
4826
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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 } }),
|
|
4827
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: reg.label, onChange: (e) => setReg({ ...reg, label: e.target.value }), placeholder: "名称(可中文)", disabled: !hiPriv || busy, style: { ...S.input, width: 110, fontSize: 12 } }),
|
|
4828
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: reg.description, onChange: (e) => setReg({ ...reg, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: !hiPriv || busy, style: { ...S.input, width: 170, fontSize: 12 } }),
|
|
4829
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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: "注册" }),
|
|
4830
|
+
!hiPriv && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
|
|
4831
|
+
] }),
|
|
4832
|
+
msg ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.hint, children: msg }) : null,
|
|
4833
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.error, children: error }) : null,
|
|
4834
|
+
visibleRows.length === 0 ? normFilter ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "无匹配的 Room。" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "暂无 Room:对话/反刍会从标签涌现,或在上方注册。" }) : visibleRows.map((row2) => {
|
|
4835
|
+
const e = row2.entry;
|
|
4836
|
+
const retired = e?.status === "retired";
|
|
4837
|
+
const grownOnly = !e;
|
|
4838
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
|
|
4839
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
|
|
4840
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4841
|
+
"button",
|
|
4842
|
+
{
|
|
4843
|
+
type: "button",
|
|
4844
|
+
title: expanded.has(row2.slug) ? "收起记忆条目" : "展开查看该 Room 的记忆条目(默认收起)",
|
|
4845
|
+
onClick: () => void toggleExpand(row2.slug),
|
|
4846
|
+
style: { ...btn2, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4847
|
+
children: expanded.has(row2.slug) ? "▾" : "▸"
|
|
4848
|
+
}
|
|
4849
|
+
),
|
|
4850
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
|
|
4851
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
|
|
4852
|
+
row2.slug,
|
|
4853
|
+
e?.source === "pre-registered" ? " ⭐" : ""
|
|
4854
|
+
] }),
|
|
4855
|
+
e?.label ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: e.label }) : null,
|
|
4856
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
|
|
4857
|
+
grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
|
|
4858
|
+
retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
|
|
4859
|
+
(e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
|
|
4860
|
+
] }),
|
|
4861
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
|
|
4862
|
+
!hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
4863
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
|
|
4864
|
+
setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
|
|
4865
|
+
setRenaming(null);
|
|
4866
|
+
}, style: btn2, children: "编辑" }),
|
|
4867
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
|
|
4868
|
+
setRenaming({ slug: row2.slug, to: "" });
|
|
4869
|
+
setEditing(null);
|
|
4870
|
+
}, style: btn2, children: "改名" }),
|
|
4871
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4872
|
+
"button",
|
|
4873
|
+
{
|
|
4874
|
+
type: "button",
|
|
4875
|
+
disabled: busy,
|
|
4876
|
+
title: retired ? "恢复该 Room 到词表" : "退役该 Room(存量 tags 不动)",
|
|
4877
|
+
onClick: () => retire(row2.slug, retired),
|
|
4878
|
+
style: { ...btn2, ...retired ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : { color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" } },
|
|
4879
|
+
children: retired ? "恢复" : "退役"
|
|
4880
|
+
}
|
|
4881
|
+
),
|
|
4882
|
+
!retired ? /* @__PURE__ */ (0, import_jsx_runtime17.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
|
|
4883
|
+
] }),
|
|
4884
|
+
grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
4885
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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: "收编" }),
|
|
4886
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
|
|
4887
|
+
setRenaming(null);
|
|
4888
|
+
retire(row2.slug, false, true);
|
|
4889
|
+
}, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
|
|
4890
|
+
] }) : null,
|
|
4891
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
|
|
4892
|
+
] })
|
|
4893
|
+
] }),
|
|
4894
|
+
expanded.has(row2.slug) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { margin: "0 10px 6px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
|
|
4895
|
+
(records[row2.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
|
|
4896
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
|
|
4897
|
+
" ",
|
|
4898
|
+
it.retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
|
|
4899
|
+
" ",
|
|
4900
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
|
|
4901
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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 })
|
|
4902
|
+
] }, it.id)),
|
|
4903
|
+
(records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
|
|
4904
|
+
(records[row2.slug]?.total ?? 0) > (records[row2.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + records[row2.slug].total + " 条,仅显示前 " + records[row2.slug].items.length + " 条" }) : null
|
|
4905
|
+
] }) : null
|
|
4906
|
+
] }, row2.slug);
|
|
4907
|
+
})
|
|
4908
|
+
] });
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
// client/src/tabs/ScenesTab.tsx
|
|
4912
|
+
var import_react18 = require("react");
|
|
4913
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
4346
4914
|
function SceneCard(props) {
|
|
4347
4915
|
const s = props.s;
|
|
4348
|
-
const [open, setOpen] = (0,
|
|
4349
|
-
return /* @__PURE__ */ (0,
|
|
4350
|
-
/* @__PURE__ */ (0,
|
|
4916
|
+
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
4917
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
|
|
4918
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4351
4919
|
"div",
|
|
4352
4920
|
{
|
|
4353
4921
|
style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
|
|
@@ -4355,23 +4923,23 @@ var __defProp = Object.defineProperty;
|
|
|
4355
4923
|
setOpen(!open);
|
|
4356
4924
|
},
|
|
4357
4925
|
children: [
|
|
4358
|
-
/* @__PURE__ */ (0,
|
|
4359
|
-
/* @__PURE__ */ (0,
|
|
4360
|
-
s.heat ? /* @__PURE__ */ (0,
|
|
4361
|
-
/* @__PURE__ */ (0,
|
|
4362
|
-
/* @__PURE__ */ (0,
|
|
4926
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
|
|
4927
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.sceneTitle, children: s.path }),
|
|
4928
|
+
s.heat ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
|
|
4929
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
|
|
4930
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
|
|
4363
4931
|
]
|
|
4364
4932
|
}
|
|
4365
4933
|
),
|
|
4366
|
-
s.summary ? /* @__PURE__ */ (0,
|
|
4367
|
-
open ? /* @__PURE__ */ (0,
|
|
4934
|
+
s.summary ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
|
|
4935
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
|
|
4368
4936
|
] });
|
|
4369
4937
|
}
|
|
4370
4938
|
function ScenesTab(props) {
|
|
4371
4939
|
const rpc = props.rpc;
|
|
4372
|
-
const [items, setItems] = (0,
|
|
4373
|
-
const [error, setError] = (0,
|
|
4374
|
-
const load = (0,
|
|
4940
|
+
const [items, setItems] = (0, import_react18.useState)(null);
|
|
4941
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
4942
|
+
const load = (0, import_react18.useCallback)(() => {
|
|
4375
4943
|
rpc("dsh-memory/scenes", {}).then((r) => {
|
|
4376
4944
|
if (r && r.ok) {
|
|
4377
4945
|
setItems(r.value.items);
|
|
@@ -4381,56 +4949,58 @@ var __defProp = Object.defineProperty;
|
|
|
4381
4949
|
setError(String(e && e.message || e));
|
|
4382
4950
|
});
|
|
4383
4951
|
}, [rpc]);
|
|
4384
|
-
(0,
|
|
4952
|
+
(0, import_react18.useEffect)(() => {
|
|
4385
4953
|
load();
|
|
4386
4954
|
}, [load]);
|
|
4387
|
-
return /* @__PURE__ */ (0,
|
|
4388
|
-
/* @__PURE__ */ (0,
|
|
4389
|
-
/* @__PURE__ */ (0,
|
|
4390
|
-
/* @__PURE__ */ (0,
|
|
4391
|
-
/* @__PURE__ */ (0,
|
|
4955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
4956
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
|
|
4957
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
|
|
4958
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.grow }),
|
|
4959
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NButton, { onClick: load, children: "刷新" })
|
|
4392
4960
|
] }),
|
|
4393
|
-
error ? /* @__PURE__ */ (0,
|
|
4394
|
-
items && items.length === 0 ? /* @__PURE__ */ (0,
|
|
4961
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: S.error, children: error }) : null,
|
|
4962
|
+
items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
|
|
4395
4963
|
(items || []).map((s) => {
|
|
4396
|
-
return /* @__PURE__ */ (0,
|
|
4964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SceneCard, { s }, s.path);
|
|
4397
4965
|
})
|
|
4398
4966
|
] });
|
|
4399
4967
|
}
|
|
4400
4968
|
|
|
4401
4969
|
// client/src/panel.tsx
|
|
4402
|
-
var
|
|
4970
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4403
4971
|
var TABS = [
|
|
4404
4972
|
["overview", "概览"],
|
|
4405
4973
|
["records", "记忆"],
|
|
4406
4974
|
["conflicts", "冲突"],
|
|
4407
4975
|
["scenes", "场景"],
|
|
4408
4976
|
["rooms", "Hall"],
|
|
4977
|
+
["room", "Room"],
|
|
4409
4978
|
["persona", "画像"],
|
|
4410
4979
|
["cost", "成本"],
|
|
4411
4980
|
["log", "日志"]
|
|
4412
4981
|
];
|
|
4413
4982
|
function MemoryPanel(props) {
|
|
4414
4983
|
const rpc = props.rpc;
|
|
4415
|
-
const [tab, setTab] = (0,
|
|
4984
|
+
const [tab, setTab] = (0, import_react19.useState)("overview");
|
|
4416
4985
|
ensureThemeStyle();
|
|
4417
|
-
(0,
|
|
4986
|
+
(0, import_react19.useEffect)(() => {
|
|
4418
4987
|
watchSidebarIcon();
|
|
4419
4988
|
}, []);
|
|
4420
4989
|
let body;
|
|
4421
|
-
if (tab === "overview") body = /* @__PURE__ */ (0,
|
|
4422
|
-
else if (tab === "records") body = /* @__PURE__ */ (0,
|
|
4423
|
-
else if (tab === "conflicts") body = /* @__PURE__ */ (0,
|
|
4424
|
-
else if (tab === "scenes") body = /* @__PURE__ */ (0,
|
|
4425
|
-
else if (tab === "rooms") body = /* @__PURE__ */ (0,
|
|
4426
|
-
else if (tab === "
|
|
4427
|
-
else if (tab === "
|
|
4428
|
-
else body = /* @__PURE__ */ (0,
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
/* @__PURE__ */ (0,
|
|
4432
|
-
/* @__PURE__ */ (0,
|
|
4433
|
-
|
|
4990
|
+
if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(OverviewTab, { rpc });
|
|
4991
|
+
else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RecordsTab, { rpc });
|
|
4992
|
+
else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConflictsTab, { rpc });
|
|
4993
|
+
else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ScenesTab, { rpc });
|
|
4994
|
+
else if (tab === "rooms") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RoomsTab, { rpc });
|
|
4995
|
+
else if (tab === "room") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(RoomTab, { rpc });
|
|
4996
|
+
else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PersonaTab, { rpc });
|
|
4997
|
+
else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CostTab, { rpc });
|
|
4998
|
+
else body = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LogTab, { rpc });
|
|
4999
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
|
|
5000
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
|
|
5001
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
|
|
5002
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
|
|
5003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4434
5004
|
"button",
|
|
4435
5005
|
{
|
|
4436
5006
|
className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
|
|
@@ -4447,7 +5017,7 @@ var __defProp = Object.defineProperty;
|
|
|
4447
5017
|
}
|
|
4448
5018
|
|
|
4449
5019
|
// client/src/pill/MemoryModePill.tsx
|
|
4450
|
-
var
|
|
5020
|
+
var import_react22 = require("react");
|
|
4451
5021
|
|
|
4452
5022
|
// src/util/context-occupancy.ts
|
|
4453
5023
|
var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
|
|
@@ -4763,23 +5333,23 @@ var __defProp = Object.defineProperty;
|
|
|
4763
5333
|
}
|
|
4764
5334
|
|
|
4765
5335
|
// client/src/pill/WingWheel.tsx
|
|
4766
|
-
var
|
|
5336
|
+
var import_react21 = require("react");
|
|
4767
5337
|
|
|
4768
5338
|
// client/src/pill/SessionInfoArea.tsx
|
|
4769
|
-
var
|
|
4770
|
-
var
|
|
5339
|
+
var import_react20 = require("react");
|
|
5340
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
4771
5341
|
function sinfoCell(val, label, title) {
|
|
4772
|
-
return /* @__PURE__ */ (0,
|
|
4773
|
-
/* @__PURE__ */ (0,
|
|
4774
|
-
/* @__PURE__ */ (0,
|
|
5342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { title: title || void 0, children: [
|
|
5343
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
|
|
5344
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
|
|
4775
5345
|
] });
|
|
4776
5346
|
}
|
|
4777
5347
|
function SessionInfoArea(props) {
|
|
4778
5348
|
const rpc = props.rpc;
|
|
4779
5349
|
const sessionId = props.sessionId;
|
|
4780
|
-
const [stats, setStats] = (0,
|
|
4781
|
-
const busyRef = (0,
|
|
4782
|
-
(0,
|
|
5350
|
+
const [stats, setStats] = (0, import_react20.useState)(void 0);
|
|
5351
|
+
const busyRef = (0, import_react20.useRef)(false);
|
|
5352
|
+
(0, import_react20.useEffect)(() => {
|
|
4783
5353
|
if (!rpc || !sessionId) return void 0;
|
|
4784
5354
|
let alive = true;
|
|
4785
5355
|
let timer = null;
|
|
@@ -4812,7 +5382,7 @@ var __defProp = Object.defineProperty;
|
|
|
4812
5382
|
}, [rpc, sessionId]);
|
|
4813
5383
|
if (stats === null) return null;
|
|
4814
5384
|
if (stats === void 0) {
|
|
4815
|
-
return /* @__PURE__ */ (0,
|
|
5385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
|
|
4816
5386
|
sinfoCell("…", "召回命中"),
|
|
4817
5387
|
sinfoCell("…", "攒批进度"),
|
|
4818
5388
|
sinfoCell("…", "本会话记忆"),
|
|
@@ -4861,21 +5431,21 @@ var __defProp = Object.defineProperty;
|
|
|
4861
5431
|
else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
|
|
4862
5432
|
}
|
|
4863
5433
|
const ago = fmtAgo(gl.lastExtractAt);
|
|
4864
|
-
return /* @__PURE__ */ (0,
|
|
4865
|
-
warn ? /* @__PURE__ */ (0,
|
|
4866
|
-
/* @__PURE__ */ (0,
|
|
5434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "dsh-mem-sinfo", children: [
|
|
5435
|
+
warn ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
|
|
5436
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
|
|
4867
5437
|
sinfoCell(rcVal, rcLabel, rcTitle),
|
|
4868
5438
|
sinfoCell(dVal, dLabel, dTitle),
|
|
4869
5439
|
sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
|
|
4870
5440
|
sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
|
|
4871
5441
|
] }),
|
|
4872
|
-
note ? /* @__PURE__ */ (0,
|
|
4873
|
-
/* @__PURE__ */ (0,
|
|
5442
|
+
note ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
|
|
5443
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
|
|
4874
5444
|
] });
|
|
4875
5445
|
}
|
|
4876
5446
|
|
|
4877
5447
|
// client/src/pill/WingWheel.tsx
|
|
4878
|
-
var
|
|
5448
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4879
5449
|
var SIZE = 196;
|
|
4880
5450
|
var CENTER = SIZE / 2;
|
|
4881
5451
|
var R = 64;
|
|
@@ -4918,17 +5488,17 @@ var __defProp = Object.defineProperty;
|
|
|
4918
5488
|
function WingWheel(props) {
|
|
4919
5489
|
ensureThemeStyle();
|
|
4920
5490
|
const isOff = props.mode === "off";
|
|
4921
|
-
const [overview, setOverview] = (0,
|
|
4922
|
-
const [backfillBusy, setBackfillBusy] = (0,
|
|
4923
|
-
const [localError, setLocalError] = (0,
|
|
4924
|
-
const timersRef = (0,
|
|
4925
|
-
(0,
|
|
5491
|
+
const [overview, setOverview] = (0, import_react21.useState)(null);
|
|
5492
|
+
const [backfillBusy, setBackfillBusy] = (0, import_react21.useState)(false);
|
|
5493
|
+
const [localError, setLocalError] = (0, import_react21.useState)(null);
|
|
5494
|
+
const timersRef = (0, import_react21.useRef)([]);
|
|
5495
|
+
(0, import_react21.useEffect)(
|
|
4926
5496
|
() => () => {
|
|
4927
5497
|
for (const t of timersRef.current) window.clearTimeout(t);
|
|
4928
5498
|
},
|
|
4929
5499
|
[]
|
|
4930
5500
|
);
|
|
4931
|
-
(0,
|
|
5501
|
+
(0, import_react21.useEffect)(() => {
|
|
4932
5502
|
let alive = true;
|
|
4933
5503
|
props.rpc("dsh-memory/wing-overview", {}).then((r) => {
|
|
4934
5504
|
if (!alive) return;
|
|
@@ -4974,28 +5544,28 @@ var __defProp = Object.defineProperty;
|
|
|
4974
5544
|
finish();
|
|
4975
5545
|
});
|
|
4976
5546
|
};
|
|
4977
|
-
const boxRef = (0,
|
|
4978
|
-
const startRef = (0,
|
|
4979
|
-
const movedRef = (0,
|
|
4980
|
-
const downIndexRef = (0,
|
|
4981
|
-
const dragTargetRef = (0,
|
|
4982
|
-
const [drag, setDrag] = (0,
|
|
5547
|
+
const boxRef = (0, import_react21.useRef)(null);
|
|
5548
|
+
const startRef = (0, import_react21.useRef)(null);
|
|
5549
|
+
const movedRef = (0, import_react21.useRef)(false);
|
|
5550
|
+
const downIndexRef = (0, import_react21.useRef)(null);
|
|
5551
|
+
const dragTargetRef = (0, import_react21.useRef)(null);
|
|
5552
|
+
const [drag, setDrag] = (0, import_react21.useState)(null);
|
|
4983
5553
|
const lockedIndex = (() => {
|
|
4984
5554
|
if (props.halls.length !== 1 || !overview) return null;
|
|
4985
5555
|
const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
|
|
4986
5556
|
return i >= 0 ? i : null;
|
|
4987
5557
|
})();
|
|
4988
5558
|
const activeCorner = drag ? drag.index : lockedIndex;
|
|
4989
|
-
const blockPosRef = (0,
|
|
5559
|
+
const blockPosRef = (0, import_react21.useRef)(
|
|
4990
5560
|
activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
|
|
4991
5561
|
);
|
|
4992
|
-
const blockTargetRef = (0,
|
|
4993
|
-
const [blockPos, setBlockPos] = (0,
|
|
4994
|
-
(0,
|
|
5562
|
+
const blockTargetRef = (0, import_react21.useRef)(blockPosRef.current);
|
|
5563
|
+
const [blockPos, setBlockPos] = (0, import_react21.useState)(blockPosRef.current);
|
|
5564
|
+
(0, import_react21.useEffect)(() => {
|
|
4995
5565
|
blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
|
|
4996
5566
|
}, [activeCorner]);
|
|
4997
|
-
const reducedMotionRef = (0,
|
|
4998
|
-
(0,
|
|
5567
|
+
const reducedMotionRef = (0, import_react21.useRef)(false);
|
|
5568
|
+
(0, import_react21.useEffect)(() => {
|
|
4999
5569
|
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
5000
5570
|
const apply2 = () => {
|
|
5001
5571
|
reducedMotionRef.current = mq.matches;
|
|
@@ -5004,7 +5574,7 @@ var __defProp = Object.defineProperty;
|
|
|
5004
5574
|
mq.addEventListener("change", apply2);
|
|
5005
5575
|
return () => mq.removeEventListener("change", apply2);
|
|
5006
5576
|
}, []);
|
|
5007
|
-
(0,
|
|
5577
|
+
(0, import_react21.useEffect)(() => {
|
|
5008
5578
|
let raf = 0;
|
|
5009
5579
|
const loop = () => {
|
|
5010
5580
|
const cur = blockPosRef.current;
|
|
@@ -5093,8 +5663,8 @@ var __defProp = Object.defineProperty;
|
|
|
5093
5663
|
}).join(" ");
|
|
5094
5664
|
const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
|
|
5095
5665
|
const boundariesDisabled = props.halls.length === 0 || isOff;
|
|
5096
|
-
return /* @__PURE__ */ (0,
|
|
5097
|
-
/* @__PURE__ */ (0,
|
|
5666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { width: SIZE }, children: [
|
|
5667
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5098
5668
|
"div",
|
|
5099
5669
|
{
|
|
5100
5670
|
ref: boxRef,
|
|
@@ -5104,7 +5674,7 @@ var __defProp = Object.defineProperty;
|
|
|
5104
5674
|
onPointerUp: onBoxUp,
|
|
5105
5675
|
onPointerCancel: onBoxUp,
|
|
5106
5676
|
children: [
|
|
5107
|
-
/* @__PURE__ */ (0,
|
|
5677
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5108
5678
|
"svg",
|
|
5109
5679
|
{
|
|
5110
5680
|
width: SIZE,
|
|
@@ -5112,7 +5682,7 @@ var __defProp = Object.defineProperty;
|
|
|
5112
5682
|
style: { position: "absolute", inset: 0, pointerEvents: "none" },
|
|
5113
5683
|
"aria-hidden": "true",
|
|
5114
5684
|
children: [
|
|
5115
|
-
/* @__PURE__ */ (0,
|
|
5685
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5116
5686
|
"polygon",
|
|
5117
5687
|
{
|
|
5118
5688
|
points: polyPoints,
|
|
@@ -5123,7 +5693,7 @@ var __defProp = Object.defineProperty;
|
|
|
5123
5693
|
opacity: 0.45
|
|
5124
5694
|
}
|
|
5125
5695
|
),
|
|
5126
|
-
/* @__PURE__ */ (0,
|
|
5696
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5127
5697
|
"polygon",
|
|
5128
5698
|
{
|
|
5129
5699
|
points: polyPoints,
|
|
@@ -5134,7 +5704,7 @@ var __defProp = Object.defineProperty;
|
|
|
5134
5704
|
),
|
|
5135
5705
|
[0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
|
|
5136
5706
|
const p = cornerPos(i);
|
|
5137
|
-
return /* @__PURE__ */ (0,
|
|
5707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5138
5708
|
"line",
|
|
5139
5709
|
{
|
|
5140
5710
|
x1: CENTER,
|
|
@@ -5150,7 +5720,7 @@ var __defProp = Object.defineProperty;
|
|
|
5150
5720
|
]
|
|
5151
5721
|
}
|
|
5152
5722
|
),
|
|
5153
|
-
/* @__PURE__ */ (0,
|
|
5723
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5154
5724
|
"div",
|
|
5155
5725
|
{
|
|
5156
5726
|
"aria-hidden": "true",
|
|
@@ -5169,7 +5739,7 @@ var __defProp = Object.defineProperty;
|
|
|
5169
5739
|
}
|
|
5170
5740
|
}
|
|
5171
5741
|
),
|
|
5172
|
-
/* @__PURE__ */ (0,
|
|
5742
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5173
5743
|
"button",
|
|
5174
5744
|
{
|
|
5175
5745
|
type: "button",
|
|
@@ -5203,7 +5773,7 @@ var __defProp = Object.defineProperty;
|
|
|
5203
5773
|
const dim = activeCorner != null && !active;
|
|
5204
5774
|
const empty = count === 0;
|
|
5205
5775
|
const p = cornerPos(i);
|
|
5206
|
-
return /* @__PURE__ */ (0,
|
|
5776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5207
5777
|
"div",
|
|
5208
5778
|
{
|
|
5209
5779
|
title: id ? `「${label}」${count ?? 0} 条
|
|
@@ -5232,8 +5802,8 @@ var __defProp = Object.defineProperty;
|
|
|
5232
5802
|
zIndex: 2
|
|
5233
5803
|
},
|
|
5234
5804
|
children: [
|
|
5235
|
-
/* @__PURE__ */ (0,
|
|
5236
|
-
/* @__PURE__ */ (0,
|
|
5805
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: label }),
|
|
5806
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
|
|
5237
5807
|
]
|
|
5238
5808
|
},
|
|
5239
5809
|
id ?? i
|
|
@@ -5242,7 +5812,7 @@ var __defProp = Object.defineProperty;
|
|
|
5242
5812
|
]
|
|
5243
5813
|
}
|
|
5244
5814
|
),
|
|
5245
|
-
/* @__PURE__ */ (0,
|
|
5815
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5246
5816
|
"div",
|
|
5247
5817
|
{
|
|
5248
5818
|
title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
|
|
@@ -5256,9 +5826,9 @@ var __defProp = Object.defineProperty;
|
|
|
5256
5826
|
pointerEvents: boundariesDisabled ? "none" : void 0
|
|
5257
5827
|
},
|
|
5258
5828
|
children: [
|
|
5259
|
-
/* @__PURE__ */ (0,
|
|
5260
|
-
/* @__PURE__ */ (0,
|
|
5261
|
-
/* @__PURE__ */ (0,
|
|
5829
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
|
|
5830
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
5831
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5262
5832
|
Segmented,
|
|
5263
5833
|
{
|
|
5264
5834
|
value: props.hallIncludeUnlabeled ? "in" : "ex",
|
|
@@ -5269,7 +5839,7 @@ var __defProp = Object.defineProperty;
|
|
|
5269
5839
|
onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
|
|
5270
5840
|
}
|
|
5271
5841
|
),
|
|
5272
|
-
/* @__PURE__ */ (0,
|
|
5842
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5273
5843
|
Segmented,
|
|
5274
5844
|
{
|
|
5275
5845
|
value: props.hallIncludeGeneral ? "in" : "ex",
|
|
@@ -5284,7 +5854,7 @@ var __defProp = Object.defineProperty;
|
|
|
5284
5854
|
]
|
|
5285
5855
|
}
|
|
5286
5856
|
),
|
|
5287
|
-
/* @__PURE__ */ (0,
|
|
5857
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5288
5858
|
Segmented,
|
|
5289
5859
|
{
|
|
5290
5860
|
value: isOff ? "off" : "on",
|
|
@@ -5299,7 +5869,7 @@ var __defProp = Object.defineProperty;
|
|
|
5299
5869
|
onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
|
|
5300
5870
|
}
|
|
5301
5871
|
) }),
|
|
5302
|
-
props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0,
|
|
5872
|
+
props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5303
5873
|
Segmented,
|
|
5304
5874
|
{
|
|
5305
5875
|
value: props.recall === null ? "follow" : props.recall ? "on" : "off",
|
|
@@ -5312,7 +5882,7 @@ var __defProp = Object.defineProperty;
|
|
|
5312
5882
|
onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
|
|
5313
5883
|
}
|
|
5314
5884
|
) }) : null,
|
|
5315
|
-
/* @__PURE__ */ (0,
|
|
5885
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5316
5886
|
"div",
|
|
5317
5887
|
{
|
|
5318
5888
|
style: {
|
|
@@ -5323,8 +5893,8 @@ var __defProp = Object.defineProperty;
|
|
|
5323
5893
|
marginTop: 10
|
|
5324
5894
|
},
|
|
5325
5895
|
children: [
|
|
5326
|
-
/* @__PURE__ */ (0,
|
|
5327
|
-
/* @__PURE__ */ (0,
|
|
5896
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
|
|
5897
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5328
5898
|
ActionButton,
|
|
5329
5899
|
{
|
|
5330
5900
|
label: backfillBusy ? "回填中…" : "回填",
|
|
@@ -5336,12 +5906,12 @@ var __defProp = Object.defineProperty;
|
|
|
5336
5906
|
]
|
|
5337
5907
|
}
|
|
5338
5908
|
),
|
|
5339
|
-
props.error || localError ? /* @__PURE__ */ (0,
|
|
5340
|
-
/* @__PURE__ */ (0,
|
|
5909
|
+
props.error || localError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error || localError }) : null,
|
|
5910
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
|
|
5341
5911
|
] });
|
|
5342
5912
|
}
|
|
5343
5913
|
function Row(props) {
|
|
5344
|
-
return /* @__PURE__ */ (0,
|
|
5914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
5345
5915
|
"div",
|
|
5346
5916
|
{
|
|
5347
5917
|
style: {
|
|
@@ -5351,7 +5921,7 @@ var __defProp = Object.defineProperty;
|
|
|
5351
5921
|
marginTop: 10
|
|
5352
5922
|
},
|
|
5353
5923
|
children: [
|
|
5354
|
-
/* @__PURE__ */ (0,
|
|
5924
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
|
|
5355
5925
|
props.children
|
|
5356
5926
|
]
|
|
5357
5927
|
}
|
|
@@ -5359,9 +5929,9 @@ var __defProp = Object.defineProperty;
|
|
|
5359
5929
|
}
|
|
5360
5930
|
var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
|
|
5361
5931
|
function useViewportClamp(popRef) {
|
|
5362
|
-
const shiftRef = (0,
|
|
5363
|
-
const [shiftX, setShiftX] = (0,
|
|
5364
|
-
(0,
|
|
5932
|
+
const shiftRef = (0, import_react21.useRef)(0);
|
|
5933
|
+
const [shiftX, setShiftX] = (0, import_react21.useState)(0);
|
|
5934
|
+
(0, import_react21.useEffect)(() => {
|
|
5365
5935
|
const clamp = () => {
|
|
5366
5936
|
const el = popRef.current;
|
|
5367
5937
|
if (!el) return;
|
|
@@ -5391,24 +5961,24 @@ var __defProp = Object.defineProperty;
|
|
|
5391
5961
|
}
|
|
5392
5962
|
|
|
5393
5963
|
// client/src/pill/MemoryModePill.tsx
|
|
5394
|
-
var
|
|
5964
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5395
5965
|
function MemoryModePill(props) {
|
|
5396
5966
|
const rpc = props.rpc;
|
|
5397
5967
|
const sessionId = props.sessionId || props.session && props.session.sessionId;
|
|
5398
|
-
const [mode, setMode] = (0,
|
|
5399
|
-
const [recall, setRecall] = (0,
|
|
5400
|
-
const [recallResolved, setRecallResolved] = (0,
|
|
5401
|
-
const [halls, setWings] = (0,
|
|
5402
|
-
const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0,
|
|
5403
|
-
const [hallIncludeGeneral, setWingIncludeGeneral] = (0,
|
|
5404
|
-
const [wingLabels, setHallLabels] = (0,
|
|
5405
|
-
const [error, setError] = (0,
|
|
5406
|
-
const [open, setOpen] = (0,
|
|
5407
|
-
const wrapRef = (0,
|
|
5408
|
-
const popRef = (0,
|
|
5968
|
+
const [mode, setMode] = (0, import_react22.useState)(null);
|
|
5969
|
+
const [recall, setRecall] = (0, import_react22.useState)(null);
|
|
5970
|
+
const [recallResolved, setRecallResolved] = (0, import_react22.useState)(true);
|
|
5971
|
+
const [halls, setWings] = (0, import_react22.useState)([]);
|
|
5972
|
+
const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react22.useState)(true);
|
|
5973
|
+
const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react22.useState)(false);
|
|
5974
|
+
const [wingLabels, setHallLabels] = (0, import_react22.useState)({});
|
|
5975
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
5976
|
+
const [open, setOpen] = (0, import_react22.useState)(false);
|
|
5977
|
+
const wrapRef = (0, import_react22.useRef)(null);
|
|
5978
|
+
const popRef = (0, import_react22.useRef)(null);
|
|
5409
5979
|
const shiftX = useViewportClamp(popRef);
|
|
5410
|
-
const seqRef = (0,
|
|
5411
|
-
const load = (0,
|
|
5980
|
+
const seqRef = (0, import_react22.useRef)(0);
|
|
5981
|
+
const load = (0, import_react22.useCallback)(() => {
|
|
5412
5982
|
if (!sessionId || !rpc) return;
|
|
5413
5983
|
const token = ++seqRef.current;
|
|
5414
5984
|
setError(null);
|
|
@@ -5433,13 +6003,13 @@ var __defProp = Object.defineProperty;
|
|
|
5433
6003
|
}).catch(() => {
|
|
5434
6004
|
});
|
|
5435
6005
|
}, [sessionId, rpc]);
|
|
5436
|
-
(0,
|
|
6006
|
+
(0, import_react22.useEffect)(() => {
|
|
5437
6007
|
load();
|
|
5438
6008
|
}, [load]);
|
|
5439
|
-
(0,
|
|
6009
|
+
(0, import_react22.useEffect)(() => {
|
|
5440
6010
|
watchSidebarIcon();
|
|
5441
6011
|
}, []);
|
|
5442
|
-
(0,
|
|
6012
|
+
(0, import_react22.useEffect)(() => {
|
|
5443
6013
|
initOccupancyIndicator(
|
|
5444
6014
|
(endpoint, payload) => rpc(endpoint, payload)
|
|
5445
6015
|
);
|
|
@@ -5447,7 +6017,7 @@ var __defProp = Object.defineProperty;
|
|
|
5447
6017
|
watchContextMeter();
|
|
5448
6018
|
noteOccupancySession(sessionId ?? null);
|
|
5449
6019
|
}, [sessionId, rpc]);
|
|
5450
|
-
(0,
|
|
6020
|
+
(0, import_react22.useEffect)(() => {
|
|
5451
6021
|
if (!open) return;
|
|
5452
6022
|
const onDown = (e) => {
|
|
5453
6023
|
if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
|
|
@@ -5587,8 +6157,8 @@ var __defProp = Object.defineProperty;
|
|
|
5587
6157
|
pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
|
|
5588
6158
|
pillStyle["--dsh-mem-pill-tint"] = info.color;
|
|
5589
6159
|
}
|
|
5590
|
-
return /* @__PURE__ */ (0,
|
|
5591
|
-
/* @__PURE__ */ (0,
|
|
6160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
|
|
6161
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
5592
6162
|
"button",
|
|
5593
6163
|
{
|
|
5594
6164
|
type: "button",
|
|
@@ -5601,11 +6171,11 @@ var __defProp = Object.defineProperty;
|
|
|
5601
6171
|
style: pillStyle,
|
|
5602
6172
|
children: [
|
|
5603
6173
|
"记忆 · ",
|
|
5604
|
-
/* @__PURE__ */ (0,
|
|
6174
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: faceLabel })
|
|
5605
6175
|
]
|
|
5606
6176
|
}
|
|
5607
6177
|
),
|
|
5608
|
-
open ? /* @__PURE__ */ (0,
|
|
6178
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5609
6179
|
"div",
|
|
5610
6180
|
{
|
|
5611
6181
|
ref: popRef,
|
|
@@ -5616,12 +6186,12 @@ var __defProp = Object.defineProperty;
|
|
|
5616
6186
|
transform: "translateX(calc(-50% + " + shiftX + "px))",
|
|
5617
6187
|
zIndex: 1e3
|
|
5618
6188
|
},
|
|
5619
|
-
children: /* @__PURE__ */ (0,
|
|
6189
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5620
6190
|
"div",
|
|
5621
6191
|
{
|
|
5622
6192
|
className: "dsh-mem-popover",
|
|
5623
6193
|
style: { position: "relative", padding: "10px 12px" },
|
|
5624
|
-
children: /* @__PURE__ */ (0,
|
|
6194
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5625
6195
|
WingWheel,
|
|
5626
6196
|
{
|
|
5627
6197
|
mode: mode || "auto",
|