dsh-remember 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/README.zh-CN.md +1 -2
- package/lib/client.js +150 -80
- package/lib/client.js.map +1 -1
- package/lib/index.js +231 -7345
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ The memory entry at the bottom of the sidebar opens the status panel.
|
|
|
29
29
|
<img src="docs/shots/01-sidebar-panel.png" width="420" alt="Sidebar entry and status panel">
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
|
-
The memory viewer: overview,
|
|
32
|
+
The memory viewer: overview (stats, most-cited, records), summary, and registry.
|
|
33
33
|
|
|
34
34
|
<p align="center">
|
|
35
35
|
<img src="docs/shots/02-viewer-overview.png" width="330" alt="Overview">
|
|
@@ -38,7 +38,6 @@ The memory viewer: overview, summary, index, and records.
|
|
|
38
38
|
|
|
39
39
|
<p align="center">
|
|
40
40
|
<img src="docs/shots/04-viewer-index.png" width="330" alt="Index">
|
|
41
|
-
<img src="docs/shots/05-viewer-records.png" width="330" alt="Records">
|
|
42
41
|
</p>
|
|
43
42
|
|
|
44
43
|
## Install
|
package/README.zh-CN.md
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<img src="docs/shots/01-sidebar-panel.png" width="420" alt="侧栏入口与状态面板">
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
记忆浏览页:概览(统计、最常引用、记录)、摘要、注册表。
|
|
33
33
|
|
|
34
34
|
<p align="center">
|
|
35
35
|
<img src="docs/shots/02-viewer-overview.png" width="330" alt="概览">
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
|
|
39
39
|
<p align="center">
|
|
40
40
|
<img src="docs/shots/04-viewer-index.png" width="330" alt="注册表">
|
|
41
|
-
<img src="docs/shots/05-viewer-records.png" width="330" alt="记录">
|
|
42
41
|
</p>
|
|
43
42
|
|
|
44
43
|
## 安装
|
package/lib/client.js
CHANGED
|
@@ -583,62 +583,101 @@ function ModelSelect(props) {
|
|
|
583
583
|
style: inputStyle(false)
|
|
584
584
|
}, options);
|
|
585
585
|
}
|
|
586
|
+
/** Upper bound for an import traveling base64 through the settings mirror. */
|
|
587
|
+
const IMPORT_LIMIT_BYTES = 32 * 1024 * 1024;
|
|
588
|
+
/** Save bundle bytes: native save dialog where available, download fallback. */
|
|
589
|
+
async function saveBundleFile(name$1, base64) {
|
|
590
|
+
const binary = atob(base64);
|
|
591
|
+
const bytes = new Uint8Array(binary.length);
|
|
592
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
593
|
+
const picker = window.showSaveFilePicker;
|
|
594
|
+
if (picker != null) try {
|
|
595
|
+
const writable = await (await picker.call(window, { suggestedName: name$1 })).createWritable();
|
|
596
|
+
await writable.write(bytes);
|
|
597
|
+
await writable.close();
|
|
598
|
+
return;
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (error?.name === "AbortError") return;
|
|
601
|
+
}
|
|
602
|
+
const url = URL.createObjectURL(new Blob([bytes]));
|
|
603
|
+
const anchor = document.createElement("a");
|
|
604
|
+
anchor.href = url;
|
|
605
|
+
anchor.download = name$1;
|
|
606
|
+
anchor.click();
|
|
607
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
608
|
+
}
|
|
586
609
|
/**
|
|
587
|
-
* Import/export entry: the host
|
|
588
|
-
*
|
|
589
|
-
*
|
|
610
|
+
* Import/export entry: export asks the host for the bundle and saves it via
|
|
611
|
+
* the browser's file dialog; import reads a picked file and ships it base64
|
|
612
|
+
* through the memory-commands channel. Outcomes come back as `transfer:`-
|
|
613
|
+
* prefixed status detail lines.
|
|
590
614
|
*/
|
|
591
615
|
function TransferSection(props) {
|
|
592
616
|
const { t, commands } = props;
|
|
593
|
-
const [exportPath, setExportPath] = (0, react.useState)("");
|
|
594
|
-
const [importPath, setImportPath] = (0, react.useState)("");
|
|
595
617
|
const [requested, setRequested] = (0, react.useState)(null);
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
618
|
+
const [localError, setLocalError] = (0, react.useState)("");
|
|
619
|
+
const fileInput = (0, react.useRef)(null);
|
|
620
|
+
const lastExportAt = (0, react.useRef)(0);
|
|
621
|
+
const send = (action, path = "", payload = "") => {
|
|
622
|
+
if (commands == null) return;
|
|
599
623
|
(async () => {
|
|
600
|
-
await commands.set("path",
|
|
624
|
+
await commands.set("path", path);
|
|
625
|
+
await commands.set("payload", payload);
|
|
601
626
|
await commands.set("action", action);
|
|
602
627
|
await commands.set("requestedAt", Date.now());
|
|
603
628
|
})();
|
|
604
629
|
};
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}), (0, react.createElement)("button", {
|
|
629
|
-
type: "button",
|
|
630
|
-
disabled: commands == null || empty,
|
|
631
|
-
className: "dshm-btn",
|
|
632
|
-
onClick: () => send(action, value),
|
|
633
|
-
style: primaryButtonStyle(commands == null || empty)
|
|
634
|
-
}, t(`transfer_${action}`))));
|
|
630
|
+
(0, react.useEffect)(() => {
|
|
631
|
+
const bundle = props.exportBundle;
|
|
632
|
+
if (bundle == null || bundle.data === "" || bundle.at <= lastExportAt.current) return void 0;
|
|
633
|
+
lastExportAt.current = bundle.at;
|
|
634
|
+
saveBundleFile(bundle.name, bundle.data).finally(() => send("export-done"));
|
|
635
|
+
}, [props.exportBundle?.at ?? 0]);
|
|
636
|
+
const pickImport = (event) => {
|
|
637
|
+
const file = event.target.files?.[0];
|
|
638
|
+
event.target.value = "";
|
|
639
|
+
if (file == null) return;
|
|
640
|
+
if (file.size > IMPORT_LIMIT_BYTES) {
|
|
641
|
+
setLocalError(t("transfer_tooBig"));
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
setLocalError("");
|
|
645
|
+
setRequested("import");
|
|
646
|
+
const reader = new FileReader();
|
|
647
|
+
reader.onload = () => {
|
|
648
|
+
const result = String(reader.result ?? "");
|
|
649
|
+
send("import", "", result.slice(result.indexOf(",") + 1));
|
|
650
|
+
};
|
|
651
|
+
reader.onerror = () => setLocalError(t("transfer_readFailed"));
|
|
652
|
+
reader.readAsDataURL(file);
|
|
635
653
|
};
|
|
636
|
-
|
|
654
|
+
const feedback = localError !== "" ? localError : props.statusDetail?.startsWith("transfer:") === true ? props.statusDetail.slice(9).trim() : null;
|
|
655
|
+
const feedbackIsError = feedback != null && (localError !== "" || /fail|need|must|unsupported|error/iu.test(feedback));
|
|
656
|
+
const transferRow = (labelKey, descKey, action) => (0, react.createElement)("div", {
|
|
657
|
+
className: "dshm-row",
|
|
658
|
+
style: rowStyle()
|
|
659
|
+
}, (0, react.createElement)("div", { style: labelStackStyle() }, (0, react.createElement)("span", { style: { fontSize: 13 } }, t(labelKey)), (0, react.createElement)("span", { style: {
|
|
637
660
|
fontSize: 11.5,
|
|
638
|
-
opacity: .5
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
661
|
+
opacity: .5
|
|
662
|
+
} }, t(descKey))), (0, react.createElement)("button", {
|
|
663
|
+
type: "button",
|
|
664
|
+
disabled: commands == null,
|
|
665
|
+
className: "dshm-btn",
|
|
666
|
+
onClick: () => {
|
|
667
|
+
setLocalError("");
|
|
668
|
+
setRequested(action);
|
|
669
|
+
if (action === "export") send("export");
|
|
670
|
+
else fileInput.current?.click();
|
|
671
|
+
},
|
|
672
|
+
style: primaryButtonStyle(commands == null)
|
|
673
|
+
}, t(`transfer_${action}`)));
|
|
674
|
+
return (0, react.createElement)("section", { style: sectionStyle() }, (0, react.createElement)("h3", { style: sectionHeaderStyle() }, t("group_transfer")), (0, react.createElement)("div", { style: { borderTop: `1px solid ${BORDER$1}` } }, transferRow("transfer_exportLabel", "transfer_exportDesc", "export"), transferRow("transfer_importLabel", "transfer_importDesc", "import")), (0, react.createElement)("input", {
|
|
675
|
+
type: "file",
|
|
676
|
+
accept: ".json,.gz,.dshmem",
|
|
677
|
+
ref: fileInput,
|
|
678
|
+
style: { display: "none" },
|
|
679
|
+
onChange: pickImport
|
|
680
|
+
}), (0, react.createElement)("div", { style: {
|
|
642
681
|
minHeight: 18,
|
|
643
682
|
margin: "4px 2px 0"
|
|
644
683
|
} }, feedback != null ? (0, react.createElement)("span", { style: {
|
|
@@ -731,6 +770,13 @@ function renderMemoryPage(props) {
|
|
|
731
770
|
} }, t("unavailable"));
|
|
732
771
|
const disabled = !state.writable;
|
|
733
772
|
const status = statusSnapshot?.status === "ready" ? statusSnapshot.value : void 0;
|
|
773
|
+
const viewSnapshot = props.useMemoryView != null ? props.useMemoryView((value) => value) : void 0;
|
|
774
|
+
const viewValue = viewSnapshot?.status === "ready" ? viewSnapshot.value : void 0;
|
|
775
|
+
const exportBundle = viewValue != null && (viewValue.exportData ?? "") !== "" ? {
|
|
776
|
+
name: viewValue.exportName ?? "memory.dshmem",
|
|
777
|
+
data: viewValue.exportData,
|
|
778
|
+
at: viewValue.exportAt ?? 0
|
|
779
|
+
} : void 0;
|
|
734
780
|
const active = status?.phase === "phase1" || status?.phase === "phase2";
|
|
735
781
|
const statusLabel = active ? status?.phase === "phase1" ? t("phase1") : t("phase2") : t("statusIdle");
|
|
736
782
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -824,7 +870,8 @@ function renderMemoryPage(props) {
|
|
|
824
870
|
} }, status?.updatedAt ? new Date(status.updatedAt).toLocaleTimeString() : "")), fieldSection("general"), fieldSection("models"), fieldSection("schedule"), fieldSection("recall"), (0, react.createElement)(TransferSection, {
|
|
825
871
|
t,
|
|
826
872
|
commands: props.commands,
|
|
827
|
-
statusDetail: status?.detail
|
|
873
|
+
statusDetail: status?.detail,
|
|
874
|
+
exportBundle
|
|
828
875
|
}), (0, react.createElement)(AdvancedSection, {
|
|
829
876
|
t,
|
|
830
877
|
fields: groups.get("advanced") ?? [],
|
|
@@ -1322,7 +1369,11 @@ function ensureViewerStyles() {
|
|
|
1322
1369
|
".dshmv-usage { display: flex; align-items: center; gap: 6px; }",
|
|
1323
1370
|
".dshmv-usage-bar { height: 5px; border-radius: 3px; background: var(--dsw-alias-brand-primary, #4d6bfe); min-width: 2px; transition: width 200ms ease; }",
|
|
1324
1371
|
".dshmv-empty { color: var(--dsw-alias-label-tertiary, rgba(0,0,0,0.45)); padding: 24px 0; text-align: center; font-size: 12px; }",
|
|
1325
|
-
".dshmv-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; color: var(--dsw-alias-label-tertiary, rgba(0,0,0,0.45)); }"
|
|
1372
|
+
".dshmv-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; color: var(--dsw-alias-label-tertiary, rgba(0,0,0,0.45)); }",
|
|
1373
|
+
".dshmv-section { margin: 2px 0 8px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-secondary, rgba(0,0,0,0.65)); }",
|
|
1374
|
+
".dshmv-toprow { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 8px; border: 0.5px solid var(--dsw-alias-border-l2, rgba(0,0,0,0.1)); background: var(--dsw-alias-fill-tertiary, rgba(0,0,0,0.04)); margin-bottom: 6px; }",
|
|
1375
|
+
".dshmv-toprow-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; font-size: 12px; }",
|
|
1376
|
+
".dshmv-toprow-meta { flex: 0 0 auto; font-size: 11px; color: var(--dsw-alias-label-tertiary, rgba(0,0,0,0.45)); font-variant-numeric: tabular-nums; }"
|
|
1326
1377
|
].join("\n");
|
|
1327
1378
|
document.head.appendChild(tag);
|
|
1328
1379
|
styleInjected = true;
|
|
@@ -1406,12 +1457,10 @@ function renderViewer(props) {
|
|
|
1406
1457
|
await commands.set("requestedAt", Date.now());
|
|
1407
1458
|
})();
|
|
1408
1459
|
};
|
|
1409
|
-
const effectiveText = showTranslated && hasTranslation ? texts.translatedSummary : texts.summary;
|
|
1410
1460
|
return (0, react.createElement)("div", { className: "dshmv-root" }, (0, react.createElement)("div", { className: "dshmv-tabs" }, ...[
|
|
1411
1461
|
"overview",
|
|
1412
1462
|
"summary",
|
|
1413
|
-
"index"
|
|
1414
|
-
"records"
|
|
1463
|
+
"index"
|
|
1415
1464
|
].map((id) => (0, react.createElement)("button", {
|
|
1416
1465
|
key: id,
|
|
1417
1466
|
type: "button",
|
|
@@ -1457,30 +1506,54 @@ function renderViewer(props) {
|
|
|
1457
1506
|
}, t("viewer_rebuild")), showTranslated && hasTranslation && view.translatedStale === true ? (0, react.createElement)("span", { className: "dshmv-badge dshmv-badge-stale" }, t("viewer_stale")) : null, showTranslated && hasTranslation && view.translatedStale !== true ? (0, react.createElement)("span", { className: "dshmv-badge dshmv-badge-ok" }, t("viewer_fresh")) : null, (0, react.createElement)("span", { className: "dshmv-status" }, status.detail ?? "")), (0, react.createElement)("div", {
|
|
1458
1507
|
className: "dshmv-body",
|
|
1459
1508
|
"data-fill": "true"
|
|
1460
|
-
}, tab === "overview" ?
|
|
1509
|
+
}, tab === "overview" ? (0, react.createElement)(OverviewView, {
|
|
1461
1510
|
t,
|
|
1462
1511
|
texts,
|
|
1463
|
-
showTranslated
|
|
1464
|
-
|
|
1465
|
-
t,
|
|
1512
|
+
showTranslated,
|
|
1513
|
+
status,
|
|
1466
1514
|
records
|
|
1467
|
-
}))
|
|
1515
|
+
}) : tab === "summary" ? (0, react.createElement)(SummaryView, {
|
|
1516
|
+
t,
|
|
1517
|
+
texts,
|
|
1518
|
+
showTranslated
|
|
1519
|
+
}) : renderIndex(t, texts, showTranslated)));
|
|
1468
1520
|
}
|
|
1469
|
-
|
|
1521
|
+
/** Overview dashboard: stat cards, status, most-cited, and the records table. */
|
|
1522
|
+
function OverviewView(props) {
|
|
1523
|
+
const { t, texts, showTranslated, status, records } = props;
|
|
1524
|
+
const [query, setQuery] = (0, react.useState)("");
|
|
1470
1525
|
const totalUsage = records.reduce((sum, record) => sum + record.usageCount, 0);
|
|
1471
1526
|
const consolidated = records.filter((record) => record.selectedForPhase2).length;
|
|
1527
|
+
const topCited = records.filter((record) => record.usageCount > 0).sort((a, b) => b.usageCount - a.usageCount).slice(0, 5);
|
|
1472
1528
|
const phase = status.phase ?? "idle";
|
|
1473
1529
|
const active = phase === "phase1" || phase === "phase2";
|
|
1530
|
+
const needle = query.trim().toLowerCase();
|
|
1531
|
+
const filtered = needle === "" ? records : records.filter((record) => record.sessionId.toLowerCase().includes(needle) || record.rolloutSlug.toLowerCase().includes(needle) || record.workspacePath.toLowerCase().includes(needle));
|
|
1532
|
+
const maxUsage = Math.max(1, ...records.map((record) => record.usageCount));
|
|
1474
1533
|
const card = (num, label) => (0, react.createElement)("div", {
|
|
1475
1534
|
className: "dshmv-card",
|
|
1476
1535
|
key: label
|
|
1477
1536
|
}, (0, react.createElement)("div", { className: "dshmv-card-num" }, num), (0, react.createElement)("div", { className: "dshmv-card-label" }, label));
|
|
1478
|
-
return (0, react.createElement)("div", { className: "dshmv-fill" }, (0, react.createElement)("div", { className: "dshmv-cards" }, card(records.length, t("viewer_stat_records")), card(consolidated, t("viewer_stat_consolidated")), card(totalUsage, t("viewer_stat_citations")), card(formatBytes(texts.summary.length), t("viewer_stat_summarySize"))), (0, react.createElement)("div", { style: {
|
|
1537
|
+
return (0, react.createElement)("div", { className: "dshmv-scroll-fill" }, (0, react.createElement)("div", { className: "dshmv-cards" }, card(records.length, t("viewer_stat_records")), card(consolidated, t("viewer_stat_consolidated")), card(totalUsage, t("viewer_stat_citations")), card(formatBytes(texts.summary.length), t("viewer_stat_summarySize")), card(formatBytes(texts.index.length), t("viewer_stat_indexSize"))), (0, react.createElement)("div", { style: {
|
|
1479
1538
|
display: "flex",
|
|
1480
1539
|
alignItems: "center",
|
|
1481
1540
|
gap: 8,
|
|
1482
1541
|
marginBottom: 10
|
|
1483
|
-
} }, (0, react.createElement)("span", { className: `dshmv-badge ${active ? "dshmv-badge-stale" : "dshmv-badge-ok"}` }, active ? phase === "phase1" ? t("phase1") : t("phase2") : t("statusIdle")), status.updatedAt != null && status.updatedAt > 0 ? (0, react.createElement)("span", { className: "dshmv-mono" }, new Date(status.updatedAt).toLocaleString()) : null, showTranslated ? (0, react.createElement)("span", { className: "dshmv-badge dshmv-badge-ok" }, t("viewer_badgeTranslated")) : null),
|
|
1542
|
+
} }, (0, react.createElement)("span", { className: `dshmv-badge ${active ? "dshmv-badge-stale" : "dshmv-badge-ok"}` }, active ? phase === "phase1" ? t("phase1") : t("phase2") : t("statusIdle")), status.updatedAt != null && status.updatedAt > 0 ? (0, react.createElement)("span", { className: "dshmv-mono" }, new Date(status.updatedAt).toLocaleString()) : null, showTranslated ? (0, react.createElement)("span", { className: "dshmv-badge dshmv-badge-ok" }, t("viewer_badgeTranslated")) : null), records.length === 0 ? null : (0, react.createElement)("div", { className: "dshmv-section" }, t("viewer_topCited")), ...topCited.map((record) => (0, react.createElement)("div", {
|
|
1543
|
+
className: "dshmv-toprow",
|
|
1544
|
+
key: record.sessionId
|
|
1545
|
+
}, (0, react.createElement)("span", { className: "dshmv-toprow-name" }, record.rolloutSlug || record.sessionId.slice(0, 8)), (0, react.createElement)("span", { className: "dshmv-toprow-meta" }, `${record.usageCount} · ${formatTime(record.lastUsage ?? record.sourceUpdatedAt)}`))), records.length > 0 && topCited.length === 0 ? (0, react.createElement)("div", { className: "dshmv-empty" }, t("viewer_noCitations")) : null, records.length === 0 ? null : (0, react.createElement)("div", {
|
|
1546
|
+
className: "dshmv-section",
|
|
1547
|
+
style: { marginTop: 14 }
|
|
1548
|
+
}, t("viewer_tab_records")), records.length === 0 ? null : (0, react.createElement)("input", {
|
|
1549
|
+
className: "dshmv-search",
|
|
1550
|
+
placeholder: t("viewer_search"),
|
|
1551
|
+
value: query,
|
|
1552
|
+
onChange: (event) => setQuery(event.target.value)
|
|
1553
|
+
}), records.length === 0 ? (0, react.createElement)("div", { className: "dshmv-empty" }, t("viewer_empty")) : (0, react.createElement)("table", { className: "dshmv-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, t("viewer_col_session")), (0, react.createElement)("th", null, t("viewer_col_usage")), (0, react.createElement)("th", null, t("viewer_col_updated")))), (0, react.createElement)("tbody", null, ...filtered.map((record) => (0, react.createElement)("tr", { key: record.sessionId }, (0, react.createElement)("td", null, (0, react.createElement)("div", { style: { fontWeight: 600 } }, record.rolloutSlug || record.sessionId.slice(0, 8)), (0, react.createElement)("div", { className: "dshmv-mono" }, record.workspacePath)), (0, react.createElement)("td", null, (0, react.createElement)("div", { className: "dshmv-usage" }, (0, react.createElement)("span", {
|
|
1554
|
+
className: "dshmv-usage-bar",
|
|
1555
|
+
style: { width: `${Math.round(record.usageCount / maxUsage * 48)}px` }
|
|
1556
|
+
}), (0, react.createElement)("span", null, String(record.usageCount))), record.lastUsage != null ? (0, react.createElement)("div", { className: "dshmv-mono" }, `${t("viewer_col_lastUsed")}: ${formatTime(record.lastUsage)}`) : null), (0, react.createElement)("td", { className: "dshmv-mono" }, formatTime(record.sourceUpdatedAt)))))));
|
|
1484
1557
|
}
|
|
1485
1558
|
function SummaryView(props) {
|
|
1486
1559
|
const { t, texts, showTranslated } = props;
|
|
@@ -1491,22 +1564,6 @@ function renderIndex(t, texts, showTranslated) {
|
|
|
1491
1564
|
const text = showTranslated && texts.translatedIndex !== "" ? texts.translatedIndex : texts.index;
|
|
1492
1565
|
return text !== "" ? (0, react.createElement)("div", { className: "dshmv-md dshmv-md-fill" }, text) : (0, react.createElement)("div", { className: "dshmv-empty dshmv-fill" }, texts.failed ? t("viewer_decodeFailed") : t("viewer_empty"));
|
|
1493
1566
|
}
|
|
1494
|
-
function RecordsView(props) {
|
|
1495
|
-
const { t, records } = props;
|
|
1496
|
-
const [query, setQuery] = (0, react.useState)("");
|
|
1497
|
-
const needle = query.trim().toLowerCase();
|
|
1498
|
-
const filtered = needle === "" ? records : records.filter((record) => record.sessionId.toLowerCase().includes(needle) || record.rolloutSlug.toLowerCase().includes(needle) || record.workspacePath.toLowerCase().includes(needle));
|
|
1499
|
-
const maxUsage = Math.max(1, ...records.map((record) => record.usageCount));
|
|
1500
|
-
return (0, react.createElement)("div", { className: "dshmv-fill" }, (0, react.createElement)("input", {
|
|
1501
|
-
className: "dshmv-search",
|
|
1502
|
-
placeholder: t("viewer_search"),
|
|
1503
|
-
value: query,
|
|
1504
|
-
onChange: (event) => setQuery(event.target.value)
|
|
1505
|
-
}), (0, react.createElement)("div", { className: "dshmv-scroll-fill" }, filtered.length === 0 ? (0, react.createElement)("div", { className: "dshmv-empty" }, t("viewer_empty")) : (0, react.createElement)("table", { className: "dshmv-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, t("viewer_col_session")), (0, react.createElement)("th", null, t("viewer_col_usage")), (0, react.createElement)("th", null, t("viewer_col_updated")))), (0, react.createElement)("tbody", null, ...filtered.map((record) => (0, react.createElement)("tr", { key: record.sessionId }, (0, react.createElement)("td", null, (0, react.createElement)("div", { style: { fontWeight: 600 } }, record.rolloutSlug || record.sessionId.slice(0, 8)), (0, react.createElement)("div", { className: "dshmv-mono" }, record.workspacePath)), (0, react.createElement)("td", null, (0, react.createElement)("div", { className: "dshmv-usage" }, (0, react.createElement)("span", {
|
|
1506
|
-
className: "dshmv-usage-bar",
|
|
1507
|
-
style: { width: `${Math.round(record.usageCount / maxUsage * 48)}px` }
|
|
1508
|
-
}), (0, react.createElement)("span", null, String(record.usageCount))), record.lastUsage != null ? (0, react.createElement)("div", { className: "dshmv-mono" }, `${t("viewer_col_lastUsed")}: ${formatTime(record.lastUsage)}`) : null), (0, react.createElement)("td", { className: "dshmv-mono" }, formatTime(record.sourceUpdatedAt))))))));
|
|
1509
|
-
}
|
|
1510
1567
|
/** Title chip for the viewer tab. */
|
|
1511
1568
|
function MemoryViewerTitle(props) {
|
|
1512
1569
|
return (0, react.createElement)("span", null, props.t("viewer_title"));
|
|
@@ -1617,12 +1674,15 @@ const ZH = {
|
|
|
1617
1674
|
phase1: "记忆提取中",
|
|
1618
1675
|
phase2: "记忆整理中",
|
|
1619
1676
|
processing: "记忆处理中",
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1677
|
+
transfer_exportLabel: "导出记忆",
|
|
1678
|
+
transfer_exportDesc: "保存为单个 bundle 文件,位置在浏览器里选",
|
|
1679
|
+
transfer_importLabel: "导入记忆",
|
|
1680
|
+
transfer_importDesc: "选择一个 bundle 文件合并进当前记忆库",
|
|
1623
1681
|
transfer_export: "导出",
|
|
1624
1682
|
transfer_import: "导入",
|
|
1625
1683
|
transfer_requested: "已发送,结果见上方状态栏",
|
|
1684
|
+
transfer_tooBig: "文件超过 32 MB,请改用 memory_export 工具直接导出到磁盘",
|
|
1685
|
+
transfer_readFailed: "文件读取失败",
|
|
1626
1686
|
viewer_title: "记忆浏览",
|
|
1627
1687
|
viewer_refresh: "刷新",
|
|
1628
1688
|
viewer_translate: "翻译记忆",
|
|
@@ -1635,6 +1695,9 @@ const ZH = {
|
|
|
1635
1695
|
viewer_stat_consolidated: "已整理",
|
|
1636
1696
|
viewer_stat_citations: "被引用次数",
|
|
1637
1697
|
viewer_stat_summarySize: "摘要大小",
|
|
1698
|
+
viewer_stat_indexSize: "注册表大小",
|
|
1699
|
+
viewer_topCited: "最常引用",
|
|
1700
|
+
viewer_noCitations: "还没有引用记录",
|
|
1638
1701
|
viewer_original: "显示原文",
|
|
1639
1702
|
viewer_translated: "显示译文",
|
|
1640
1703
|
viewer_showTranslated: "显示译文",
|
|
@@ -1718,12 +1781,15 @@ const EN = {
|
|
|
1718
1781
|
phase1: "Extracting memories",
|
|
1719
1782
|
phase2: "Consolidating memories",
|
|
1720
1783
|
processing: "Memory processing",
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1784
|
+
transfer_exportLabel: "Export memory",
|
|
1785
|
+
transfer_exportDesc: "Save as a single bundle file — pick the location in the browser",
|
|
1786
|
+
transfer_importLabel: "Import memory",
|
|
1787
|
+
transfer_importDesc: "Pick a bundle file to merge into the current memory store",
|
|
1724
1788
|
transfer_export: "Export",
|
|
1725
1789
|
transfer_import: "Import",
|
|
1726
1790
|
transfer_requested: "Sent — result appears in the status bar above",
|
|
1791
|
+
transfer_tooBig: "File exceeds 32 MB — use the memory_export tool to write it to disk instead",
|
|
1792
|
+
transfer_readFailed: "Failed to read the file",
|
|
1727
1793
|
viewer_title: "Memory",
|
|
1728
1794
|
viewer_refresh: "Refresh",
|
|
1729
1795
|
viewer_translate: "Translate memory",
|
|
@@ -1736,6 +1802,9 @@ const EN = {
|
|
|
1736
1802
|
viewer_stat_consolidated: "Consolidated",
|
|
1737
1803
|
viewer_stat_citations: "Citations",
|
|
1738
1804
|
viewer_stat_summarySize: "Summary size",
|
|
1805
|
+
viewer_stat_indexSize: "Registry size",
|
|
1806
|
+
viewer_topCited: "Most cited",
|
|
1807
|
+
viewer_noCitations: "No citations yet",
|
|
1739
1808
|
viewer_original: "Show original",
|
|
1740
1809
|
viewer_translated: "Show translation",
|
|
1741
1810
|
viewer_showTranslated: "Translation",
|
|
@@ -1828,7 +1897,8 @@ function apply(ctx) {
|
|
|
1828
1897
|
commands: commandsView,
|
|
1829
1898
|
hooks: {
|
|
1830
1899
|
memoryPage: card.pageStore(),
|
|
1831
|
-
memoryStatus: statusSource
|
|
1900
|
+
memoryStatus: statusSource,
|
|
1901
|
+
memoryView: viewSource
|
|
1832
1902
|
}
|
|
1833
1903
|
})
|
|
1834
1904
|
}, MemorySettingsPage));
|