dsh-brief-sidebar 0.5.0-beta.1 → 0.5.0-beta.3
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/dsh.plugin.json +1 -1
- package/lib/client.js +91 -15
- package/lib/client.js.map +1 -1
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/summary/DeliverablesSection.d.ts +3 -0
- package/lib/types/client/summary/deliverables.d.ts +8 -0
- package/lib/types/client/summary/memory-slots.d.ts +10 -0
- package/package.json +1 -1
- package/src/client/locales.ts +9 -9
- package/src/client/summary/DeliverablesSection.tsx +53 -9
- package/src/client/summary/MemorySlotsSection.tsx +17 -2
- package/src/client/summary/deliverables.ts +12 -0
- package/src/client/summary/memory-slots.ts +22 -0
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-brief-sidebar",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.3",
|
|
4
4
|
"main": "./lib/index.mjs",
|
|
5
5
|
"description": "会话简报侧栏页(brief):把会话的 todo 列表(`todos` 投影的进展看板)、产物列表(`dshSummaryDeliverables` 投影的实时产出文件)与记忆槽位(`memorySlots` 投影,来自 dsh-prime-memory,开关可关)一起渲染成右侧栏的一个「概要」tab,并遮蔽 DSH 官方那条 composer 上方的 todo 面板。只读展示,不做写回。",
|
|
6
6
|
"engines": {
|
package/lib/client.js
CHANGED
|
@@ -496,6 +496,17 @@ window.__ModuleLoader__.load({
|
|
|
496
496
|
const slash = normalizedPath.lastIndexOf("/");
|
|
497
497
|
return slash < 0 ? normalizedPath : normalizedPath.slice(slash + 1);
|
|
498
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* 历史文件 = 全会话去重路径 − 本回合活跃路径。
|
|
501
|
+
*
|
|
502
|
+
* 分隔符归一化后比较(`a\b` 与 `a/b` 视为同一路径),保持 sessionPaths 自带的
|
|
503
|
+
* "最近在前"顺序;活跃路径一个都不出现——分层契约:活跃的已在上方列表里,
|
|
504
|
+
* 折叠区只收"更早改过的文件"。
|
|
505
|
+
*/
|
|
506
|
+
function historyPaths(sessionPaths, latestPaths) {
|
|
507
|
+
const active = new Set(latestPaths.map(normalized));
|
|
508
|
+
return sessionPaths.filter((path) => !active.has(normalized(path)));
|
|
509
|
+
}
|
|
499
510
|
//#endregion
|
|
500
511
|
//#region src/client/locales.ts
|
|
501
512
|
/**
|
|
@@ -540,7 +551,7 @@ window.__ModuleLoader__.load({
|
|
|
540
551
|
"status.completed": "已完成",
|
|
541
552
|
"deliverables.empty": "本回合暂无改动文件",
|
|
542
553
|
"deliverables.emptyHint": "会话里成功写入或修改文件后,它们会实时出现在这里。",
|
|
543
|
-
"deliverables.
|
|
554
|
+
"deliverables.history": "更早改动的文件 · {count}",
|
|
544
555
|
"deliverable.codeplanTag": "规划",
|
|
545
556
|
"section.memorySlots": "记忆",
|
|
546
557
|
"slots.empty": "当前没有激活的记忆槽位",
|
|
@@ -571,7 +582,7 @@ window.__ModuleLoader__.load({
|
|
|
571
582
|
"status.completed": "Done",
|
|
572
583
|
"deliverables.empty": "No files changed in this turn",
|
|
573
584
|
"deliverables.emptyHint": "Files written or edited successfully in the session appear here live.",
|
|
574
|
-
"deliverables.
|
|
585
|
+
"deliverables.history": "Earlier changes · {count}",
|
|
575
586
|
"deliverable.codeplanTag": "Plan",
|
|
576
587
|
"section.memorySlots": "Memory",
|
|
577
588
|
"slots.empty": "No active memory slots",
|
|
@@ -602,7 +613,7 @@ window.__ModuleLoader__.load({
|
|
|
602
613
|
"status.completed": "完了",
|
|
603
614
|
"deliverables.empty": "このターンで変更されたファイルはありません",
|
|
604
615
|
"deliverables.emptyHint": "セッションでファイルの書き込み・変更が成功すると、ここにリアルタイムで表示されます。",
|
|
605
|
-
"deliverables.
|
|
616
|
+
"deliverables.history": "以前の変更 · {count}",
|
|
606
617
|
"deliverable.codeplanTag": "計画",
|
|
607
618
|
"section.memorySlots": "メモリ",
|
|
608
619
|
"slots.empty": "アクティブなメモリスロットはありません",
|
|
@@ -633,7 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
633
644
|
"status.completed": "완료",
|
|
634
645
|
"deliverables.empty": "이번 턴에 변경된 파일이 없습니다",
|
|
635
646
|
"deliverables.emptyHint": "세션에서 파일을 성공적으로 작성하거나 수정하면 여기에 실시간으로 표시됩니다.",
|
|
636
|
-
"deliverables.
|
|
647
|
+
"deliverables.history": "이전 변경 사항 · {count}",
|
|
637
648
|
"deliverable.codeplanTag": "계획",
|
|
638
649
|
"section.memorySlots": "메모리",
|
|
639
650
|
"slots.empty": "활성화된 메모리 슬롯이 없습니다",
|
|
@@ -664,7 +675,7 @@ window.__ModuleLoader__.load({
|
|
|
664
675
|
"status.completed": "Terminé",
|
|
665
676
|
"deliverables.empty": "Aucun fichier modifié à ce tour",
|
|
666
677
|
"deliverables.emptyHint": "Les fichiers écrits ou modifiés dans la session apparaissent ici en direct.",
|
|
667
|
-
"deliverables.
|
|
678
|
+
"deliverables.history": "Modifications antérieures · {count}",
|
|
668
679
|
"deliverable.codeplanTag": "Plan",
|
|
669
680
|
"section.memorySlots": "Mémoire",
|
|
670
681
|
"slots.empty": "Aucun emplacement mémoire actif",
|
|
@@ -695,7 +706,7 @@ window.__ModuleLoader__.load({
|
|
|
695
706
|
"status.completed": "Fertig",
|
|
696
707
|
"deliverables.empty": "Keine Dateien in diesem Durchgang geändert",
|
|
697
708
|
"deliverables.emptyHint": "In der Sitzung erfolgreich geschriebene oder geänderte Dateien erscheinen hier live.",
|
|
698
|
-
"deliverables.
|
|
709
|
+
"deliverables.history": "Frühere Änderungen · {count}",
|
|
699
710
|
"deliverable.codeplanTag": "Plan",
|
|
700
711
|
"section.memorySlots": "Gedächtnis",
|
|
701
712
|
"slots.empty": "Keine aktiven Speicherplätze",
|
|
@@ -726,7 +737,7 @@ window.__ModuleLoader__.load({
|
|
|
726
737
|
"status.completed": "Completato",
|
|
727
738
|
"deliverables.empty": "Nessun file modificato in questo turno",
|
|
728
739
|
"deliverables.emptyHint": "I file scritti o modificati nella sessione appaiono qui in tempo reale.",
|
|
729
|
-
"deliverables.
|
|
740
|
+
"deliverables.history": "Modifiche precedenti · {count}",
|
|
730
741
|
"deliverable.codeplanTag": "Piano",
|
|
731
742
|
"section.memorySlots": "Memoria",
|
|
732
743
|
"slots.empty": "Nessuno slot di memoria attivo",
|
|
@@ -757,7 +768,7 @@ window.__ModuleLoader__.load({
|
|
|
757
768
|
"status.completed": "Готово",
|
|
758
769
|
"deliverables.empty": "За этот ход файлы не менялись",
|
|
759
770
|
"deliverables.emptyHint": "Успешно записанные или изменённые файлы появляются здесь в реальном времени.",
|
|
760
|
-
"deliverables.
|
|
771
|
+
"deliverables.history": "Более ранние изменения · {count}",
|
|
761
772
|
"deliverable.codeplanTag": "План",
|
|
762
773
|
"section.memorySlots": "Память",
|
|
763
774
|
"slots.empty": "Активных слотов памяти нет",
|
|
@@ -788,7 +799,7 @@ window.__ModuleLoader__.load({
|
|
|
788
799
|
"status.completed": "Hecho",
|
|
789
800
|
"deliverables.empty": "Ningún archivo modificado en este turno",
|
|
790
801
|
"deliverables.emptyHint": "Los archivos escritos o editados en la sesión aparecen aquí en directo.",
|
|
791
|
-
"deliverables.
|
|
802
|
+
"deliverables.history": "Cambios anteriores · {count}",
|
|
792
803
|
"deliverable.codeplanTag": "Plan",
|
|
793
804
|
"section.memorySlots": "Memoria",
|
|
794
805
|
"slots.empty": "No hay ranuras de memoria activas",
|
|
@@ -858,11 +869,26 @@ window.__ModuleLoader__.load({
|
|
|
858
869
|
gap: 8,
|
|
859
870
|
padding: "6px 12px"
|
|
860
871
|
};
|
|
861
|
-
|
|
862
|
-
|
|
872
|
+
/** 折叠区开关行:与文件行同宽,tertiary 强调,整行可点。 */
|
|
873
|
+
const HISTORY_TOGGLE_STYLE = {
|
|
874
|
+
background: "none",
|
|
875
|
+
border: "none",
|
|
876
|
+
font: "inherit",
|
|
877
|
+
fontSize: 12,
|
|
863
878
|
color: "var(--dsw-alias-label-tertiary)",
|
|
864
|
-
|
|
879
|
+
cursor: "pointer",
|
|
880
|
+
display: "flex",
|
|
881
|
+
alignItems: "center",
|
|
882
|
+
gap: 4,
|
|
883
|
+
padding: "6px 12px",
|
|
884
|
+
textAlign: "left",
|
|
885
|
+
width: "calc(100% - 24px)"
|
|
865
886
|
};
|
|
887
|
+
const CHEVRON_STYLE$1 = (open) => ({
|
|
888
|
+
flexShrink: 0,
|
|
889
|
+
transition: "transform 0.16s",
|
|
890
|
+
transform: open ? "rotate(180deg)" : "none"
|
|
891
|
+
});
|
|
866
892
|
const PATH_STYLE = {
|
|
867
893
|
minWidth: 0,
|
|
868
894
|
overflowWrap: "anywhere",
|
|
@@ -918,14 +944,19 @@ window.__ModuleLoader__.load({
|
|
|
918
944
|
/**
|
|
919
945
|
* The deliverables section. The subscription is unconditional (a plain
|
|
920
946
|
* listener, not IO).
|
|
947
|
+
*
|
|
948
|
+
* 分层:活跃文件(本回合 latest)直接列表;全会话更早改动折叠在开关行后面
|
|
949
|
+
* (与活跃文件按归一化路径去重),展开后是与活跃区相同的可点击文件行。
|
|
921
950
|
* @param props - translation, client context, session scope.
|
|
922
951
|
*/
|
|
923
952
|
function DeliverablesSection(props) {
|
|
924
953
|
const { t, ctx, scope } = props;
|
|
954
|
+
const [historyOpen, setHistoryOpen] = (0, react.useState)(false);
|
|
925
955
|
const view = readDeliverables(useProjectionValue(ctx, scope?.sessionId, DELIVERABLES_KEY));
|
|
926
956
|
if (view === void 0) return null;
|
|
927
957
|
const open = sidebarFileOpener(ctx, scope?.sessionId);
|
|
928
958
|
const latestPaths = view.latest?.paths ?? [];
|
|
959
|
+
const history = historyPaths(view.sessionPaths, latestPaths);
|
|
929
960
|
if (latestPaths.length === 0 && view.sessionTotal === 0) return (0, react.createElement)("div", {
|
|
930
961
|
style: SECTION_STYLE$1,
|
|
931
962
|
"data-dsh-brief-sidebar": "deliverables-section"
|
|
@@ -949,7 +980,32 @@ window.__ModuleLoader__.load({
|
|
|
949
980
|
path,
|
|
950
981
|
t,
|
|
951
982
|
open
|
|
952
|
-
}))), (0, react.createElement)("
|
|
983
|
+
}))), history.length > 0 && (0, react.createElement)("button", {
|
|
984
|
+
type: "button",
|
|
985
|
+
"aria-expanded": historyOpen,
|
|
986
|
+
style: HISTORY_TOGGLE_STYLE,
|
|
987
|
+
onClick: () => {
|
|
988
|
+
setHistoryOpen((current) => !current);
|
|
989
|
+
}
|
|
990
|
+
}, expandCount(t("deliverables.history"), history.length), (0, react.createElement)("svg", {
|
|
991
|
+
width: 10,
|
|
992
|
+
height: 10,
|
|
993
|
+
viewBox: "0 0 16 16",
|
|
994
|
+
"aria-hidden": true,
|
|
995
|
+
style: CHEVRON_STYLE$1(historyOpen)
|
|
996
|
+
}, (0, react.createElement)("path", {
|
|
997
|
+
d: "M4 6l4 4 4-4",
|
|
998
|
+
fill: "none",
|
|
999
|
+
stroke: "currentColor",
|
|
1000
|
+
strokeWidth: 1.5,
|
|
1001
|
+
strokeLinecap: "round",
|
|
1002
|
+
strokeLinejoin: "round"
|
|
1003
|
+
}))), historyOpen && (0, react.createElement)("ul", { style: LIST_STYLE$1 }, history.map((path) => (0, react.createElement)(PathRow, {
|
|
1004
|
+
key: path,
|
|
1005
|
+
path,
|
|
1006
|
+
t,
|
|
1007
|
+
open
|
|
1008
|
+
}))));
|
|
953
1009
|
}
|
|
954
1010
|
//#endregion
|
|
955
1011
|
//#region src/client/summary/memory-slots.ts
|
|
@@ -1030,6 +1086,20 @@ window.__ModuleLoader__.load({
|
|
|
1030
1086
|
const refs = raw["refs"].filter((ref) => typeof ref === "string" && ref.length > 0);
|
|
1031
1087
|
if (refs.length > 0) slot.refs = refs;
|
|
1032
1088
|
}
|
|
1089
|
+
if (Array.isArray(raw["refViews"])) {
|
|
1090
|
+
const views = [];
|
|
1091
|
+
for (const entry of raw["refViews"]) {
|
|
1092
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
1093
|
+
const view = entry;
|
|
1094
|
+
if (typeof view["ref"] !== "string" || view["ref"].length === 0) continue;
|
|
1095
|
+
if (typeof view["title"] !== "string" || view["title"].length === 0) continue;
|
|
1096
|
+
views.push({
|
|
1097
|
+
ref: view["ref"],
|
|
1098
|
+
title: view["title"]
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
if (views.length > 0) slot.refViews = views;
|
|
1102
|
+
}
|
|
1033
1103
|
return slot;
|
|
1034
1104
|
}
|
|
1035
1105
|
/**
|
|
@@ -1166,12 +1236,15 @@ window.__ModuleLoader__.load({
|
|
|
1166
1236
|
};
|
|
1167
1237
|
/**
|
|
1168
1238
|
* One slot row: kind pill, title (full body rides the tooltip), status pill,
|
|
1169
|
-
* priority; body
|
|
1239
|
+
* priority; body line underneath when the wire view carries it; refs as
|
|
1240
|
+
* resolved 名称简述 (record_id → title) with the raw refs on the tooltip, or
|
|
1241
|
+
* raw refs when the host has not resolved them.
|
|
1170
1242
|
*/
|
|
1171
1243
|
function SlotRow(props) {
|
|
1172
1244
|
const { slot, t } = props;
|
|
1173
1245
|
const statusLabel = STATUS_KEY[slot.status] === void 0 ? slot.status : t(STATUS_KEY[slot.status]);
|
|
1174
1246
|
const title = slot.body === void 0 ? slot.title : `${slot.title} — ${slot.body}`;
|
|
1247
|
+
const refsLine = slot.refViews !== void 0 ? slot.refViews.map((view) => view.title).join(" · ") : slot.refs !== void 0 ? slot.refs.join(" · ") : void 0;
|
|
1175
1248
|
return (0, react.createElement)("li", { style: ROW_STYLE$1 }, (0, react.createElement)("span", { style: KIND_STYLE }, slot.kind), (0, react.createElement)("div", { style: {
|
|
1176
1249
|
minWidth: 0,
|
|
1177
1250
|
flex: "1 1 auto",
|
|
@@ -1181,7 +1254,10 @@ window.__ModuleLoader__.load({
|
|
|
1181
1254
|
} }, (0, react.createElement)("span", {
|
|
1182
1255
|
style: TITLE_STYLE,
|
|
1183
1256
|
title
|
|
1184
|
-
}, slot.title), slot.body !== void 0 && (0, react.createElement)("p", { style: BODY_STYLE$1 }, truncateBody(slot.body)),
|
|
1257
|
+
}, slot.title), slot.body !== void 0 && (0, react.createElement)("p", { style: BODY_STYLE$1 }, truncateBody(slot.body)), refsLine !== void 0 && (0, react.createElement)("p", {
|
|
1258
|
+
style: REFS_STYLE,
|
|
1259
|
+
title: slot.refs !== void 0 ? slot.refs.join("\n") : void 0
|
|
1260
|
+
}, refsLine)), (0, react.createElement)("span", { style: META_STYLE }, `P${slot.priority}`), (0, react.createElement)("span", { style: slot.status === "open" ? STATUS_OPEN_STYLE : STATUS_SETTLED_STYLE }, statusLabel));
|
|
1185
1261
|
}
|
|
1186
1262
|
/**
|
|
1187
1263
|
* A no-op unsubscribe source, kept as one identity so the absent-scope
|