dsh-brief-sidebar 0.9.3 → 0.9.4
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 +480 -55
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +303 -11
- package/lib/index.mjs.map +1 -1
- package/lib/types/client/locales.d.ts +10 -0
- package/lib/types/client/summary/ReferenceSection.d.ts +2 -2
- package/lib/types/client/summary/SearchRefSection.d.ts +21 -0
- package/lib/types/client/summary/search-refs.d.ts +38 -0
- package/lib/types/projection/keys.d.ts +42 -0
- package/lib/types/projection/register.d.ts +6 -0
- package/lib/types/projection/search-ref-fold.d.ts +116 -0
- package/package.json +1 -1
- package/src/client/locales.ts +90 -0
- package/src/client/summary/ReferenceSection.tsx +31 -13
- package/src/client/summary/SearchRefSection.tsx +241 -0
- package/src/client/summary/search-refs.ts +116 -0
- package/src/index.ts +4 -1
- package/src/projection/keys.ts +43 -0
- package/src/projection/register.ts +82 -2
- package/src/projection/search-ref-fold.ts +258 -0
package/lib/client.js
CHANGED
|
@@ -231,11 +231,11 @@ window.__ModuleLoader__.load({
|
|
|
231
231
|
in_progress: "var(--dsw-alias-state-business-primary)",
|
|
232
232
|
pending: "var(--dsw-alias-label-tertiary)"
|
|
233
233
|
};
|
|
234
|
-
const SECTION_STYLE$
|
|
234
|
+
const SECTION_STYLE$6 = {
|
|
235
235
|
flexShrink: 0,
|
|
236
236
|
borderBottom: "1px solid var(--dsw-alias-border-secondary)"
|
|
237
237
|
};
|
|
238
|
-
const HEADER_STYLE$
|
|
238
|
+
const HEADER_STYLE$7 = {
|
|
239
239
|
padding: "10px 12px 0",
|
|
240
240
|
color: "var(--dsw-alias-label-secondary)",
|
|
241
241
|
fontSize: 12,
|
|
@@ -246,14 +246,14 @@ window.__ModuleLoader__.load({
|
|
|
246
246
|
color: "var(--dsw-alias-label-secondary)",
|
|
247
247
|
fontSize: 12
|
|
248
248
|
};
|
|
249
|
-
const LIST_STYLE$
|
|
249
|
+
const LIST_STYLE$5 = {
|
|
250
250
|
listStyle: "none",
|
|
251
251
|
margin: 0,
|
|
252
252
|
padding: "6px 0",
|
|
253
253
|
display: "flex",
|
|
254
254
|
flexDirection: "column"
|
|
255
255
|
};
|
|
256
|
-
const ROW_STYLE$
|
|
256
|
+
const ROW_STYLE$6 = {
|
|
257
257
|
display: "flex",
|
|
258
258
|
alignItems: "flex-start",
|
|
259
259
|
gap: 8,
|
|
@@ -305,7 +305,7 @@ window.__ModuleLoader__.load({
|
|
|
305
305
|
/** One task row. */
|
|
306
306
|
function TodoRow(props) {
|
|
307
307
|
const { item, t } = props;
|
|
308
|
-
return (0, react.createElement)("li", { style: ROW_STYLE$
|
|
308
|
+
return (0, react.createElement)("li", { style: ROW_STYLE$6 }, (0, react.createElement)("span", { style: pillStyle(item.status) }, t(statusKey(item.status))), (0, react.createElement)("span", { style: contentStyle(item.status) }, item.content));
|
|
309
309
|
}
|
|
310
310
|
/**
|
|
311
311
|
* The progress section. The subscription is unconditional (a plain listener,
|
|
@@ -316,24 +316,24 @@ window.__ModuleLoader__.load({
|
|
|
316
316
|
const { t, ctx, scope } = props;
|
|
317
317
|
const todos = useTodos(ctx, scope?.sessionId);
|
|
318
318
|
if (todos === void 0) return (0, react.createElement)("div", {
|
|
319
|
-
style: SECTION_STYLE$
|
|
319
|
+
style: SECTION_STYLE$6,
|
|
320
320
|
"data-dsh-brief-sidebar": "progress-section"
|
|
321
|
-
}, (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
321
|
+
}, (0, react.createElement)("div", { style: HEADER_STYLE$7 }, t("section.progress")), (0, react.createElement)(Notice, {
|
|
322
322
|
title: t("board.unavailable"),
|
|
323
323
|
detail: t("board.unavailableHint")
|
|
324
324
|
}));
|
|
325
325
|
if (todos.length === 0) return (0, react.createElement)("div", {
|
|
326
|
-
style: SECTION_STYLE$
|
|
326
|
+
style: SECTION_STYLE$6,
|
|
327
327
|
"data-dsh-brief-sidebar": "progress-section"
|
|
328
|
-
}, (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
328
|
+
}, (0, react.createElement)("div", { style: HEADER_STYLE$7 }, t("section.progress")), (0, react.createElement)(Notice, {
|
|
329
329
|
title: t("board.empty"),
|
|
330
330
|
detail: t("board.emptyHint")
|
|
331
331
|
}));
|
|
332
332
|
const counts = countTodos(todos);
|
|
333
333
|
return (0, react.createElement)("div", {
|
|
334
|
-
style: SECTION_STYLE$
|
|
334
|
+
style: SECTION_STYLE$6,
|
|
335
335
|
"data-dsh-brief-sidebar": "progress-section"
|
|
336
|
-
}, (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
336
|
+
}, (0, react.createElement)("div", { style: HEADER_STYLE$7 }, t("section.progress")), (0, react.createElement)("div", { style: PROGRESS_STYLE }, progressLine(counts, t)), (0, react.createElement)("ul", { style: LIST_STYLE$5 }, todos.map((item, index) => (0, react.createElement)(TodoRow, {
|
|
337
337
|
key: `${index}:${item.content}`,
|
|
338
338
|
item,
|
|
339
339
|
t
|
|
@@ -362,6 +362,12 @@ window.__ModuleLoader__.load({
|
|
|
362
362
|
* to collide silently.
|
|
363
363
|
*/
|
|
364
364
|
const SKILL_USAGE_KEY = "dshSummarySkillUsage";
|
|
365
|
+
/**
|
|
366
|
+
* The search-reference key (queries and returned sources of this session's
|
|
367
|
+
* `advanced_search` calls). Same rule as above: the name is ours, so no other
|
|
368
|
+
* host-side unit can answer for it by accident.
|
|
369
|
+
*/
|
|
370
|
+
const SEARCH_REFS_KEY = "dshSummarySearchRefs";
|
|
365
371
|
//#endregion
|
|
366
372
|
//#region src/client/file-open.ts
|
|
367
373
|
/** The address scheme every file resource opens with. */
|
|
@@ -699,6 +705,16 @@ window.__ModuleLoader__.load({
|
|
|
699
705
|
"skillUsage.invokedGroup": "已引用 · {count}",
|
|
700
706
|
"skillUsage.availableGroup": "本会话可用 · {count}",
|
|
701
707
|
"skillUsage.availableCapped": "(可用清单共 {count} 条,列表已截断)",
|
|
708
|
+
"section.searchRefs": "搜索引用",
|
|
709
|
+
"references.tabSearch": "搜索",
|
|
710
|
+
"searchRefs.empty": "本会话还没搜索过",
|
|
711
|
+
"searchRefs.emptyHint": "模型调用 advanced_search 之后,查询与取回的外部来源会实时出现在这里。",
|
|
712
|
+
"searchRefs.queryGroup": "查询 · {count}",
|
|
713
|
+
"searchRefs.sourceGroup": "来源 · {count}",
|
|
714
|
+
"searchRefs.hits": "返回 {count} 条",
|
|
715
|
+
"searchRefs.latestTag": "本轮",
|
|
716
|
+
"searchRefs.noSourcesHint": "(该版本未回传来源清单,升级 dsh-free-search 后可见)",
|
|
717
|
+
"searchRefs.capped": "(会话共 {total} 条,列表已截断)",
|
|
702
718
|
"settings.title": "概要侧栏",
|
|
703
719
|
"settings.desc": "右侧栏概要 tab 的分区开关(只读展示)。",
|
|
704
720
|
"settings.memorySlots": "记忆槽位分区",
|
|
@@ -762,6 +778,16 @@ window.__ModuleLoader__.load({
|
|
|
762
778
|
"skillUsage.invokedGroup": "Referenced · {count}",
|
|
763
779
|
"skillUsage.availableGroup": "Available this session · {count}",
|
|
764
780
|
"skillUsage.availableCapped": "({count} skills in the catalog; the list is capped)",
|
|
781
|
+
"section.searchRefs": "Web searches",
|
|
782
|
+
"references.tabSearch": "Searches",
|
|
783
|
+
"searchRefs.empty": "No searches in this session",
|
|
784
|
+
"searchRefs.emptyHint": "Queries and the external sources they returned appear here once the model calls advanced_search.",
|
|
785
|
+
"searchRefs.queryGroup": "Queries · {count}",
|
|
786
|
+
"searchRefs.sourceGroup": "Sources · {count}",
|
|
787
|
+
"searchRefs.hits": "{count} returned",
|
|
788
|
+
"searchRefs.latestTag": "This turn",
|
|
789
|
+
"searchRefs.noSourcesHint": "(this dsh-free-search build returns no source list; upgrade to see sources)",
|
|
790
|
+
"searchRefs.capped": "({total} in the session; the list is capped)",
|
|
765
791
|
"settings.title": "Brief sidebar",
|
|
766
792
|
"settings.desc": "Section switches for the summary tab in the right sidebar (read-only views).",
|
|
767
793
|
"settings.memorySlots": "Memory slots section",
|
|
@@ -825,6 +851,16 @@ window.__ModuleLoader__.load({
|
|
|
825
851
|
"skillUsage.invokedGroup": "参照済み · {count}",
|
|
826
852
|
"skillUsage.availableGroup": "このセッションで利用可能 · {count}",
|
|
827
853
|
"skillUsage.availableCapped": "(カタログは全 {count} 件、一覧は上限で省略)",
|
|
854
|
+
"section.searchRefs": "Web 検索",
|
|
855
|
+
"references.tabSearch": "検索",
|
|
856
|
+
"searchRefs.empty": "このセッションではまだ検索していません",
|
|
857
|
+
"searchRefs.emptyHint": "モデルが advanced_search を呼び出すと、クエリと取得した外部ソースがここに表示されます。",
|
|
858
|
+
"searchRefs.queryGroup": "クエリ · {count}",
|
|
859
|
+
"searchRefs.sourceGroup": "ソース · {count}",
|
|
860
|
+
"searchRefs.hits": "{count} 件返却",
|
|
861
|
+
"searchRefs.latestTag": "今回のターン",
|
|
862
|
+
"searchRefs.noSourcesHint": "(この dsh-free-search ビルドはソース一覧を返しません。アップグレードすると表示されます)",
|
|
863
|
+
"searchRefs.capped": "(セッション全体で {total} 件、一覧は上限で省略)",
|
|
828
864
|
"settings.title": "概要サイドバー",
|
|
829
865
|
"settings.desc": "右サイドバー概要タブのセクション表示切り替え(読み取り専用)。",
|
|
830
866
|
"settings.memorySlots": "メモリスロットセクション",
|
|
@@ -888,6 +924,16 @@ window.__ModuleLoader__.load({
|
|
|
888
924
|
"skillUsage.invokedGroup": "참조됨 · {count}",
|
|
889
925
|
"skillUsage.availableGroup": "이 세션에서 사용 가능 · {count}",
|
|
890
926
|
"skillUsage.availableCapped": "(카탈로그 전체 {count}개, 목록은 잘림)",
|
|
927
|
+
"section.searchRefs": "웹 검색",
|
|
928
|
+
"references.tabSearch": "검색",
|
|
929
|
+
"searchRefs.empty": "이 세션에서는 아직 검색하지 않았습니다",
|
|
930
|
+
"searchRefs.emptyHint": "모델이 advanced_search를 호출하면 쿼리와 가져온 외부 소스가 여기에 표시됩니다.",
|
|
931
|
+
"searchRefs.queryGroup": "쿼리 · {count}",
|
|
932
|
+
"searchRefs.sourceGroup": "소스 · {count}",
|
|
933
|
+
"searchRefs.hits": "{count}件 반환",
|
|
934
|
+
"searchRefs.latestTag": "이번 턴",
|
|
935
|
+
"searchRefs.noSourcesHint": "(이 dsh-free-search 빌드는 소스 목록을 반환하지 않습니다. 업그레이드 필요)",
|
|
936
|
+
"searchRefs.capped": "(세션 전체 {total}건, 목록은 잘림)",
|
|
891
937
|
"settings.title": "요약 사이드바",
|
|
892
938
|
"settings.desc": "오른쪽 사이드바 요약 탭의 섹션 표시 전환(읽기 전용).",
|
|
893
939
|
"settings.memorySlots": "메모리 슬롯 섹션",
|
|
@@ -951,6 +997,16 @@ window.__ModuleLoader__.load({
|
|
|
951
997
|
"skillUsage.invokedGroup": "Référencées · {count}",
|
|
952
998
|
"skillUsage.availableGroup": "Disponibles dans cette session · {count}",
|
|
953
999
|
"skillUsage.availableCapped": "({count} compétences au catalogue ; la liste est tronquée)",
|
|
1000
|
+
"section.searchRefs": "Recherches web",
|
|
1001
|
+
"references.tabSearch": "Recherches",
|
|
1002
|
+
"searchRefs.empty": "Aucune recherche dans cette session",
|
|
1003
|
+
"searchRefs.emptyHint": "Les requêtes et les sources externes renvoyées apparaissent ici dès que le modèle appelle advanced_search.",
|
|
1004
|
+
"searchRefs.queryGroup": "Requêtes · {count}",
|
|
1005
|
+
"searchRefs.sourceGroup": "Sources · {count}",
|
|
1006
|
+
"searchRefs.hits": "{count} renvoyées",
|
|
1007
|
+
"searchRefs.latestTag": "Ce tour-ci",
|
|
1008
|
+
"searchRefs.noSourcesHint": "(cette version de dsh-free-search ne renvoie pas la liste des sources ; mettez à jour)",
|
|
1009
|
+
"searchRefs.capped": "({total} dans la session ; la liste est tronquée)",
|
|
954
1010
|
"settings.title": "Barre latérale Résumé",
|
|
955
1011
|
"settings.desc": "Interrupteurs des sections de l’onglet Résumé de la barre latérale (lecture seule).",
|
|
956
1012
|
"settings.memorySlots": "Section des emplacements mémoire",
|
|
@@ -1014,6 +1070,16 @@ window.__ModuleLoader__.load({
|
|
|
1014
1070
|
"skillUsage.invokedGroup": "Referenziert · {count}",
|
|
1015
1071
|
"skillUsage.availableGroup": "In dieser Sitzung verfügbar · {count}",
|
|
1016
1072
|
"skillUsage.availableCapped": "({count} Skills im Katalog; die Liste ist gekürzt)",
|
|
1073
|
+
"section.searchRefs": "Websuchen",
|
|
1074
|
+
"references.tabSearch": "Suchen",
|
|
1075
|
+
"searchRefs.empty": "Keine Suchen in dieser Sitzung",
|
|
1076
|
+
"searchRefs.emptyHint": "Abfragen und die zurückgegebenen externen Quellen erscheinen hier, sobald das Modell advanced_search aufruft.",
|
|
1077
|
+
"searchRefs.queryGroup": "Abfragen · {count}",
|
|
1078
|
+
"searchRefs.sourceGroup": "Quellen · {count}",
|
|
1079
|
+
"searchRefs.hits": "{count} zurückgegeben",
|
|
1080
|
+
"searchRefs.latestTag": "Dieser Durchlauf",
|
|
1081
|
+
"searchRefs.noSourcesHint": "(dieser dsh-free-search-Build liefert keine Quellenliste; aktualisieren, um Quellen zu sehen)",
|
|
1082
|
+
"searchRefs.capped": "({total} in der Sitzung; die Liste ist gekürzt)",
|
|
1017
1083
|
"settings.title": "Übersicht-Seitenleiste",
|
|
1018
1084
|
"settings.desc": "Schalter für die Abschnitte des Übersicht-Tabs in der rechten Seitenleiste (schreibgeschützt).",
|
|
1019
1085
|
"settings.memorySlots": "Speicherplätze-Abschnitt",
|
|
@@ -1077,6 +1143,16 @@ window.__ModuleLoader__.load({
|
|
|
1077
1143
|
"skillUsage.invokedGroup": "Referenziate · {count}",
|
|
1078
1144
|
"skillUsage.availableGroup": "Disponibili in questa sessione · {count}",
|
|
1079
1145
|
"skillUsage.availableCapped": "({count} skill nel catalogo; l’elenco è troncato)",
|
|
1146
|
+
"section.searchRefs": "Ricerche web",
|
|
1147
|
+
"references.tabSearch": "Ricerche",
|
|
1148
|
+
"searchRefs.empty": "Nessuna ricerca in questa sessione",
|
|
1149
|
+
"searchRefs.emptyHint": "Le query e le fonti esterne restituite compaiono qui quando il modello chiama advanced_search.",
|
|
1150
|
+
"searchRefs.queryGroup": "Query · {count}",
|
|
1151
|
+
"searchRefs.sourceGroup": "Fonti · {count}",
|
|
1152
|
+
"searchRefs.hits": "{count} restituite",
|
|
1153
|
+
"searchRefs.latestTag": "Questo turno",
|
|
1154
|
+
"searchRefs.noSourcesHint": "(questa build di dsh-free-search non restituisce l’elenco delle fonti; aggiorna per vederlo)",
|
|
1155
|
+
"searchRefs.capped": "({total} nella sessione; l’elenco è troncato)",
|
|
1080
1156
|
"settings.title": "Barra laterale Riepilogo",
|
|
1081
1157
|
"settings.desc": "Interruttori delle sezioni della scheda Riepilogo nella barra laterale destra (sola lettura).",
|
|
1082
1158
|
"settings.memorySlots": "Sezione slot di memoria",
|
|
@@ -1140,6 +1216,16 @@ window.__ModuleLoader__.load({
|
|
|
1140
1216
|
"skillUsage.invokedGroup": "Использованы · {count}",
|
|
1141
1217
|
"skillUsage.availableGroup": "Доступны в этой сессии · {count}",
|
|
1142
1218
|
"skillUsage.availableCapped": "({count} навыков в каталоге; список усечён)",
|
|
1219
|
+
"section.searchRefs": "Поиск в сети",
|
|
1220
|
+
"references.tabSearch": "Поиск",
|
|
1221
|
+
"searchRefs.empty": "В этой сессии ещё не было поиска",
|
|
1222
|
+
"searchRefs.emptyHint": "Запросы и возвращённые внешние источники появятся здесь, как только модель вызовет advanced_search.",
|
|
1223
|
+
"searchRefs.queryGroup": "Запросы · {count}",
|
|
1224
|
+
"searchRefs.sourceGroup": "Источники · {count}",
|
|
1225
|
+
"searchRefs.hits": "возвращено {count}",
|
|
1226
|
+
"searchRefs.latestTag": "Этот ход",
|
|
1227
|
+
"searchRefs.noSourcesHint": "(эта сборка dsh-free-search не возвращает список источников; обновите, чтобы видеть их)",
|
|
1228
|
+
"searchRefs.capped": "(в сессии всего {total}; список усечён)",
|
|
1143
1229
|
"settings.title": "Боковая панель «Сводка»",
|
|
1144
1230
|
"settings.desc": "Переключатели разделов вкладки «Сводка» на правой панели (только чтение).",
|
|
1145
1231
|
"settings.memorySlots": "Раздел слотов памяти",
|
|
@@ -1203,6 +1289,16 @@ window.__ModuleLoader__.load({
|
|
|
1203
1289
|
"skillUsage.invokedGroup": "Referenciadas · {count}",
|
|
1204
1290
|
"skillUsage.availableGroup": "Disponibles en esta sesión · {count}",
|
|
1205
1291
|
"skillUsage.availableCapped": "({count} skills en el catálogo; la lista está truncada)",
|
|
1292
|
+
"section.searchRefs": "Búsquedas web",
|
|
1293
|
+
"references.tabSearch": "Búsquedas",
|
|
1294
|
+
"searchRefs.empty": "Sin búsquedas en esta sesión",
|
|
1295
|
+
"searchRefs.emptyHint": "Las consultas y las fuentes externas devueltas aparecen aquí cuando el modelo llama a advanced_search.",
|
|
1296
|
+
"searchRefs.queryGroup": "Consultas · {count}",
|
|
1297
|
+
"searchRefs.sourceGroup": "Fuentes · {count}",
|
|
1298
|
+
"searchRefs.hits": "{count} devueltas",
|
|
1299
|
+
"searchRefs.latestTag": "Este turno",
|
|
1300
|
+
"searchRefs.noSourcesHint": "(esta versión de dsh-free-search no devuelve la lista de fuentes; actualiza para verla)",
|
|
1301
|
+
"searchRefs.capped": "({total} en la sesión; la lista está truncada)",
|
|
1206
1302
|
"settings.title": "Barra lateral Resumen",
|
|
1207
1303
|
"settings.desc": "Interruptores de las secciones de la pestaña Resumen en la barra lateral derecha (solo lectura).",
|
|
1208
1304
|
"settings.memorySlots": "Sección de ranuras de memoria",
|
|
@@ -1249,24 +1345,24 @@ window.__ModuleLoader__.load({
|
|
|
1249
1345
|
*
|
|
1250
1346
|
* Colours come from `--dsw-alias-*` tokens only (skin contract).
|
|
1251
1347
|
*/
|
|
1252
|
-
const SECTION_STYLE$
|
|
1348
|
+
const SECTION_STYLE$5 = {
|
|
1253
1349
|
flexShrink: 0,
|
|
1254
1350
|
borderBottom: "1px solid var(--dsw-alias-border-secondary)"
|
|
1255
1351
|
};
|
|
1256
|
-
const HEADER_STYLE$
|
|
1352
|
+
const HEADER_STYLE$6 = {
|
|
1257
1353
|
padding: "10px 12px 0",
|
|
1258
1354
|
color: "var(--dsw-alias-label-secondary)",
|
|
1259
1355
|
fontSize: 12,
|
|
1260
1356
|
fontWeight: 600
|
|
1261
1357
|
};
|
|
1262
|
-
const LIST_STYLE$
|
|
1358
|
+
const LIST_STYLE$4 = {
|
|
1263
1359
|
listStyle: "none",
|
|
1264
1360
|
margin: 0,
|
|
1265
1361
|
padding: "6px 0",
|
|
1266
1362
|
display: "flex",
|
|
1267
1363
|
flexDirection: "column"
|
|
1268
1364
|
};
|
|
1269
|
-
const ROW_STYLE$
|
|
1365
|
+
const ROW_STYLE$5 = {
|
|
1270
1366
|
display: "flex",
|
|
1271
1367
|
alignItems: "flex-start",
|
|
1272
1368
|
gap: 8,
|
|
@@ -1290,7 +1386,7 @@ window.__ModuleLoader__.load({
|
|
|
1290
1386
|
cursor: "pointer"
|
|
1291
1387
|
};
|
|
1292
1388
|
/** The codeplan pill: same form as the status pills, tertiary emphasis. */
|
|
1293
|
-
const TAG_STYLE$
|
|
1389
|
+
const TAG_STYLE$2 = {
|
|
1294
1390
|
flexShrink: 0,
|
|
1295
1391
|
color: "var(--dsw-alias-label-tertiary)",
|
|
1296
1392
|
border: "1px solid var(--dsw-alias-label-tertiary)",
|
|
@@ -1311,12 +1407,12 @@ window.__ModuleLoader__.load({
|
|
|
1311
1407
|
const plan = splitCodeplanPath(path);
|
|
1312
1408
|
const title = plan === null ? path : `${t("deliverable.codeplanTag")}: ${plan.task} · ${path}`;
|
|
1313
1409
|
const label = basename(path);
|
|
1314
|
-
const content = plan === null ? null : (0, react.createElement)("span", { style: TAG_STYLE$
|
|
1315
|
-
if (open === void 0) return (0, react.createElement)("li", { style: ROW_STYLE$
|
|
1410
|
+
const content = plan === null ? null : (0, react.createElement)("span", { style: TAG_STYLE$2 }, t("deliverable.codeplanTag"));
|
|
1411
|
+
if (open === void 0) return (0, react.createElement)("li", { style: ROW_STYLE$5 }, content, (0, react.createElement)("span", {
|
|
1316
1412
|
style: PATH_STYLE,
|
|
1317
1413
|
title
|
|
1318
1414
|
}, label));
|
|
1319
|
-
return (0, react.createElement)("li", { style: ROW_STYLE$
|
|
1415
|
+
return (0, react.createElement)("li", { style: ROW_STYLE$5 }, content, (0, react.createElement)("button", {
|
|
1320
1416
|
style: BUTTON_STYLE,
|
|
1321
1417
|
title,
|
|
1322
1418
|
onClick: () => {
|
|
@@ -1342,9 +1438,9 @@ window.__ModuleLoader__.load({
|
|
|
1342
1438
|
const latestPaths = view.latest?.paths ?? [];
|
|
1343
1439
|
const history = historyPaths(view.sessionPaths, latestPaths);
|
|
1344
1440
|
if (latestPaths.length === 0 && view.sessionTotal === 0) return (0, react.createElement)("div", {
|
|
1345
|
-
style: SECTION_STYLE$
|
|
1441
|
+
style: SECTION_STYLE$5,
|
|
1346
1442
|
"data-dsh-brief-sidebar": "deliverables-section"
|
|
1347
|
-
}, (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
1443
|
+
}, (0, react.createElement)("div", { style: HEADER_STYLE$6 }, t("section.deliverables")), (0, react.createElement)("div", { style: {
|
|
1348
1444
|
margin: "0 auto",
|
|
1349
1445
|
padding: 24,
|
|
1350
1446
|
maxWidth: 460,
|
|
@@ -1357,12 +1453,12 @@ window.__ModuleLoader__.load({
|
|
|
1357
1453
|
color: "var(--dsw-alias-label-secondary)"
|
|
1358
1454
|
} }, t("deliverables.empty")), (0, react.createElement)("div", null, t("deliverables.emptyHint"))));
|
|
1359
1455
|
return (0, react.createElement)("div", {
|
|
1360
|
-
style: SECTION_STYLE$
|
|
1456
|
+
style: SECTION_STYLE$5,
|
|
1361
1457
|
"data-dsh-brief-sidebar": "deliverables-section"
|
|
1362
|
-
}, (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
1458
|
+
}, (0, react.createElement)("div", { style: HEADER_STYLE$6 }, t("section.deliverables")), latestPaths.length > 0 && (0, react.createElement)(GroupHeader, {
|
|
1363
1459
|
text: expandCount(t("deliverables.currentTurn"), latestPaths.length),
|
|
1364
1460
|
marker: "deliverables-current-group"
|
|
1365
|
-
}), (0, react.createElement)("ul", { style: LIST_STYLE$
|
|
1461
|
+
}), (0, react.createElement)("ul", { style: LIST_STYLE$4 }, latestPaths.map((path) => (0, react.createElement)(PathRow, {
|
|
1366
1462
|
key: path,
|
|
1367
1463
|
path,
|
|
1368
1464
|
t,
|
|
@@ -1377,7 +1473,7 @@ window.__ModuleLoader__.load({
|
|
|
1377
1473
|
}), history.length > 0 && view.sessionTotal > view.sessionPaths.length && (0, react.createElement)(GroupCaption, {
|
|
1378
1474
|
text: expandTotal(t("deliverables.historyCapped"), view.sessionTotal),
|
|
1379
1475
|
marker: "deliverables-history-capped"
|
|
1380
|
-
}), historyOpen && (0, react.createElement)("ul", { style: LIST_STYLE$
|
|
1476
|
+
}), historyOpen && (0, react.createElement)("ul", { style: LIST_STYLE$4 }, history.map((path) => (0, react.createElement)(PathRow, {
|
|
1381
1477
|
key: path,
|
|
1382
1478
|
path,
|
|
1383
1479
|
t,
|
|
@@ -1387,7 +1483,7 @@ window.__ModuleLoader__.load({
|
|
|
1387
1483
|
//#endregion
|
|
1388
1484
|
//#region src/client/summary/skill-usage.ts
|
|
1389
1485
|
/** Whether a value is a non-negative safe integer (the view's counter shape). */
|
|
1390
|
-
function isCounter$
|
|
1486
|
+
function isCounter$3(value) {
|
|
1391
1487
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
1392
1488
|
}
|
|
1393
1489
|
/** Narrow one skill tally; `undefined` = malformed, dropped. */
|
|
@@ -1395,7 +1491,7 @@ window.__ModuleLoader__.load({
|
|
|
1395
1491
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1396
1492
|
const raw = value;
|
|
1397
1493
|
if (typeof raw["name"] !== "string" || raw["name"].length === 0) return void 0;
|
|
1398
|
-
if (!isCounter$
|
|
1494
|
+
if (!isCounter$3(raw["count"]) || !isCounter$3(raw["lastTurn"])) return void 0;
|
|
1399
1495
|
return {
|
|
1400
1496
|
name: raw["name"],
|
|
1401
1497
|
count: raw["count"],
|
|
@@ -1406,10 +1502,10 @@ window.__ModuleLoader__.load({
|
|
|
1406
1502
|
* The latest-turn bucket, or `null` when it is absent OR drifted. A drifted
|
|
1407
1503
|
* bucket only costs the "本轮" tag, so it degrades instead of voiding the view.
|
|
1408
1504
|
*/
|
|
1409
|
-
function readLatest(value) {
|
|
1505
|
+
function readLatest$1(value) {
|
|
1410
1506
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1411
1507
|
const raw = value;
|
|
1412
|
-
if (!isCounter$
|
|
1508
|
+
if (!isCounter$3(raw["turn"]) || !Array.isArray(raw["names"])) return null;
|
|
1413
1509
|
return {
|
|
1414
1510
|
turn: raw["turn"],
|
|
1415
1511
|
names: raw["names"].filter((n) => typeof n === "string" && n.length > 0)
|
|
@@ -1437,16 +1533,16 @@ window.__ModuleLoader__.load({
|
|
|
1437
1533
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1438
1534
|
const raw = value;
|
|
1439
1535
|
if (!Array.isArray(raw["session"])) return void 0;
|
|
1440
|
-
if (!isCounter$
|
|
1536
|
+
if (!isCounter$3(raw["sessionTotal"]) || !isCounter$3(raw["callTotal"])) return void 0;
|
|
1441
1537
|
const session = [];
|
|
1442
1538
|
for (const entry of raw["session"]) {
|
|
1443
1539
|
const narrowed = readEntry(entry);
|
|
1444
1540
|
if (narrowed !== void 0) session.push(narrowed);
|
|
1445
1541
|
}
|
|
1446
1542
|
const available = readAvailable(raw["available"]);
|
|
1447
|
-
const availableCount = available.length === 0 ? 0 : isCounter$
|
|
1543
|
+
const availableCount = available.length === 0 ? 0 : isCounter$3(raw["availableCount"]) ? raw["availableCount"] : available.length;
|
|
1448
1544
|
return {
|
|
1449
|
-
latest: readLatest(raw["latest"]),
|
|
1545
|
+
latest: readLatest$1(raw["latest"]),
|
|
1450
1546
|
session,
|
|
1451
1547
|
sessionTotal: raw["sessionTotal"],
|
|
1452
1548
|
callTotal: raw["callTotal"],
|
|
@@ -1483,6 +1579,129 @@ window.__ModuleLoader__.load({
|
|
|
1483
1579
|
return template.replace("{count}", String(count)).replace("{total}", String(total));
|
|
1484
1580
|
}
|
|
1485
1581
|
//#endregion
|
|
1582
|
+
//#region src/projection/search-ref-fold.ts
|
|
1583
|
+
/**
|
|
1584
|
+
* The dedupe key. Host case and a trailing slash are not meaningful for
|
|
1585
|
+
* identity; path case IS, so it is left alone. Exported because the client
|
|
1586
|
+
* matches a row against the latest-turn bucket with the same algorithm.
|
|
1587
|
+
*/
|
|
1588
|
+
function urlKey(url) {
|
|
1589
|
+
const trimmed = url.trim();
|
|
1590
|
+
return (trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed).replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]+/i, (match) => match.toLowerCase());
|
|
1591
|
+
}
|
|
1592
|
+
//#endregion
|
|
1593
|
+
//#region src/client/summary/search-refs.ts
|
|
1594
|
+
/**
|
|
1595
|
+
* The `dshSummarySearchRefs` projection — reading it.
|
|
1596
|
+
*
|
|
1597
|
+
* The unit is registered by THIS plugin's host half (key `dshSummarySearchRefs`):
|
|
1598
|
+
* the queries this session ran through `advanced_search`, and the sources those
|
|
1599
|
+
* searches brought back. It answers "what did the session pull in from outside"
|
|
1600
|
+
* — where the skill tab says which instruction packs were loaded and the memory
|
|
1601
|
+
* tab says which of the user's own knowledge was injected.
|
|
1602
|
+
*
|
|
1603
|
+
* Reading discipline, same as every other brief section:
|
|
1604
|
+
* - `undefined` = the capability is ABSENT (no projection registry, or a frame
|
|
1605
|
+
* drifted past repair) → the tab hides;
|
|
1606
|
+
* - empty lists = the honest empty state (the session has not searched yet);
|
|
1607
|
+
* - a malformed row is dropped, never thrown.
|
|
1608
|
+
*
|
|
1609
|
+
* The module is deliberately PURE — no React, no context, no IO.
|
|
1610
|
+
*/
|
|
1611
|
+
/** Whether a value is a non-negative safe integer (the view's counters). */
|
|
1612
|
+
function isCounter$2(value) {
|
|
1613
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
1614
|
+
}
|
|
1615
|
+
/** Narrow one source row; `undefined` = malformed, dropped. */
|
|
1616
|
+
function readItem$1(value) {
|
|
1617
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1618
|
+
const raw = value;
|
|
1619
|
+
if (typeof raw["url"] !== "string" || raw["url"].length === 0) return void 0;
|
|
1620
|
+
if (typeof raw["host"] !== "string") return void 0;
|
|
1621
|
+
if (typeof raw["query"] !== "string") return void 0;
|
|
1622
|
+
if (!isCounter$2(raw["count"]) || !isCounter$2(raw["lastTurn"])) return void 0;
|
|
1623
|
+
const item = {
|
|
1624
|
+
url: raw["url"],
|
|
1625
|
+
host: raw["host"],
|
|
1626
|
+
query: raw["query"],
|
|
1627
|
+
count: raw["count"],
|
|
1628
|
+
lastTurn: raw["lastTurn"]
|
|
1629
|
+
};
|
|
1630
|
+
if (typeof raw["title"] === "string" && raw["title"].length > 0) item.title = raw["title"];
|
|
1631
|
+
if (typeof raw["snippet"] === "string" && raw["snippet"].length > 0) item.snippet = raw["snippet"];
|
|
1632
|
+
return item;
|
|
1633
|
+
}
|
|
1634
|
+
/** Narrow one query row; `undefined` = malformed, dropped. */
|
|
1635
|
+
function readQuery(value) {
|
|
1636
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1637
|
+
const raw = value;
|
|
1638
|
+
if (typeof raw["query"] !== "string" || raw["query"].length === 0) return void 0;
|
|
1639
|
+
if (!isCounter$2(raw["turn"]) || !isCounter$2(raw["hits"])) return void 0;
|
|
1640
|
+
return {
|
|
1641
|
+
query: raw["query"],
|
|
1642
|
+
turn: raw["turn"],
|
|
1643
|
+
hits: raw["hits"]
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
/** The latest-turn key set, or `null` when absent OR drifted (only a tag rides it). */
|
|
1647
|
+
function readLatest(value) {
|
|
1648
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1649
|
+
const raw = value;
|
|
1650
|
+
if (!isCounter$2(raw["turn"]) || !Array.isArray(raw["urls"])) return null;
|
|
1651
|
+
return {
|
|
1652
|
+
turn: raw["turn"],
|
|
1653
|
+
urls: raw["urls"].filter((u) => typeof u === "string" && u.length > 0)
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Narrow a raw projection value into a search-reference view.
|
|
1658
|
+
*
|
|
1659
|
+
* @param value - the raw `unknown` snapshot of the `dshSummarySearchRefs` face.
|
|
1660
|
+
* @returns the validated view, or `undefined` when the capability is absent.
|
|
1661
|
+
*/
|
|
1662
|
+
function readSearchRefs(value) {
|
|
1663
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1664
|
+
const raw = value;
|
|
1665
|
+
if (!Array.isArray(raw["queries"]) || !Array.isArray(raw["sources"])) return void 0;
|
|
1666
|
+
if (!isCounter$2(raw["queryTotal"]) || !isCounter$2(raw["sourceTotal"])) return void 0;
|
|
1667
|
+
const queries = [];
|
|
1668
|
+
for (const entry of raw["queries"]) {
|
|
1669
|
+
const narrowed = readQuery(entry);
|
|
1670
|
+
if (narrowed !== void 0) queries.push(narrowed);
|
|
1671
|
+
}
|
|
1672
|
+
const sources = [];
|
|
1673
|
+
for (const entry of raw["sources"]) {
|
|
1674
|
+
const narrowed = readItem$1(entry);
|
|
1675
|
+
if (narrowed !== void 0) sources.push(narrowed);
|
|
1676
|
+
}
|
|
1677
|
+
return {
|
|
1678
|
+
latest: readLatest(raw["latest"]),
|
|
1679
|
+
queries,
|
|
1680
|
+
sources,
|
|
1681
|
+
queryTotal: raw["queryTotal"],
|
|
1682
|
+
sourceTotal: raw["sourceTotal"]
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
/** Whether one source row was surfaced by the latest turn's searches. */
|
|
1686
|
+
function isLatestSource(view, url) {
|
|
1687
|
+
return view.latest?.urls.includes(urlKey(url)) === true;
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* The href to render for a source URL, or `undefined` when it must not be a link.
|
|
1691
|
+
*
|
|
1692
|
+
* Search results are untrusted external data: a `javascript:` or `data:` URL in
|
|
1693
|
+
* a provider response would otherwise become a clickable footgun in the user's
|
|
1694
|
+
* own sidebar. Only web schemes get an anchor; everything else renders as text.
|
|
1695
|
+
*/
|
|
1696
|
+
function safeHref(url) {
|
|
1697
|
+
try {
|
|
1698
|
+
const parsed = new URL(url);
|
|
1699
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.href : void 0;
|
|
1700
|
+
} catch {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
//#endregion
|
|
1486
1705
|
//#region src/client/summary/memory-recall.ts
|
|
1487
1706
|
/**
|
|
1488
1707
|
* The `memoryRecall` projection — reading it.
|
|
@@ -1756,24 +1975,24 @@ window.__ModuleLoader__.load({
|
|
|
1756
1975
|
* overlaps the plugin's own bubble; nothing here needs one;
|
|
1757
1976
|
* - **colours from `--dsw-alias-*` tokens only** (skin contract).
|
|
1758
1977
|
*/
|
|
1759
|
-
const SECTION_STYLE$
|
|
1978
|
+
const SECTION_STYLE$4 = {
|
|
1760
1979
|
flexShrink: 0,
|
|
1761
1980
|
borderBottom: "1px solid var(--dsw-alias-border-secondary)"
|
|
1762
1981
|
};
|
|
1763
|
-
const HEADER_STYLE$
|
|
1982
|
+
const HEADER_STYLE$5 = {
|
|
1764
1983
|
padding: "10px 12px 0",
|
|
1765
1984
|
color: "var(--dsw-alias-label-secondary)",
|
|
1766
1985
|
fontSize: 12,
|
|
1767
1986
|
fontWeight: 600
|
|
1768
1987
|
};
|
|
1769
|
-
const LIST_STYLE$
|
|
1988
|
+
const LIST_STYLE$3 = {
|
|
1770
1989
|
listStyle: "none",
|
|
1771
1990
|
margin: 0,
|
|
1772
1991
|
padding: "6px 0",
|
|
1773
1992
|
display: "flex",
|
|
1774
1993
|
flexDirection: "column"
|
|
1775
1994
|
};
|
|
1776
|
-
const ROW_STYLE$
|
|
1995
|
+
const ROW_STYLE$4 = {
|
|
1777
1996
|
display: "flex",
|
|
1778
1997
|
alignItems: "baseline",
|
|
1779
1998
|
gap: 8,
|
|
@@ -1792,7 +2011,7 @@ window.__ModuleLoader__.load({
|
|
|
1792
2011
|
fontSize: 11
|
|
1793
2012
|
};
|
|
1794
2013
|
/** The "本轮" pill: same form as the deliverables codeplan tag. */
|
|
1795
|
-
const TAG_STYLE = {
|
|
2014
|
+
const TAG_STYLE$1 = {
|
|
1796
2015
|
flexShrink: 0,
|
|
1797
2016
|
color: "var(--dsw-alias-label-tertiary)",
|
|
1798
2017
|
border: "1px solid var(--dsw-alias-label-tertiary)",
|
|
@@ -1802,12 +2021,12 @@ window.__ModuleLoader__.load({
|
|
|
1802
2021
|
lineHeight: "16px",
|
|
1803
2022
|
whiteSpace: "nowrap"
|
|
1804
2023
|
};
|
|
1805
|
-
const FOOTER_STYLE$
|
|
2024
|
+
const FOOTER_STYLE$3 = {
|
|
1806
2025
|
padding: "0 12px 10px",
|
|
1807
2026
|
color: "var(--dsw-alias-label-tertiary)",
|
|
1808
2027
|
fontSize: 11
|
|
1809
2028
|
};
|
|
1810
|
-
const EMPTY_STYLE$
|
|
2029
|
+
const EMPTY_STYLE$3 = {
|
|
1811
2030
|
margin: "0 auto",
|
|
1812
2031
|
padding: 24,
|
|
1813
2032
|
maxWidth: 460,
|
|
@@ -1831,19 +2050,19 @@ window.__ModuleLoader__.load({
|
|
|
1831
2050
|
const rest = availableExcept(view.available, referenced);
|
|
1832
2051
|
const latestNames = view.latest?.names ?? [];
|
|
1833
2052
|
return (0, react.createElement)("div", {
|
|
1834
|
-
style: SECTION_STYLE$
|
|
2053
|
+
style: SECTION_STYLE$4,
|
|
1835
2054
|
"data-dsh-brief-sidebar": "skill-usage-section"
|
|
1836
|
-
}, !hideHeader && (0, react.createElement)("div", { style: HEADER_STYLE$
|
|
2055
|
+
}, !hideHeader && (0, react.createElement)("div", { style: HEADER_STYLE$5 }, t("section.skillUsage")), view.session.length === 0 && (0, react.createElement)("div", { style: EMPTY_STYLE$3 }, (0, react.createElement)("div", { style: {
|
|
1837
2056
|
marginBottom: 6,
|
|
1838
2057
|
color: "var(--dsw-alias-label-secondary)"
|
|
1839
2058
|
} }, t("skillUsage.empty")), (0, react.createElement)("div", null, t("skillUsage.emptyHint"))), view.session.length > 0 && (0, react.createElement)(GroupHeader, {
|
|
1840
2059
|
text: expandCount(t("skillUsage.invokedGroup"), view.session.length),
|
|
1841
2060
|
marker: "skill-usage-invoked-group"
|
|
1842
|
-
}), (0, react.createElement)("ul", { style: LIST_STYLE$
|
|
2061
|
+
}), (0, react.createElement)("ul", { style: LIST_STYLE$3 }, view.session.map((entry) => (0, react.createElement)("li", {
|
|
1843
2062
|
key: entry.name,
|
|
1844
|
-
style: ROW_STYLE$
|
|
2063
|
+
style: ROW_STYLE$4,
|
|
1845
2064
|
"data-dsh-brief-sidebar": "skill-usage-row"
|
|
1846
|
-
}, (0, react.createElement)("span", { style: NAME_STYLE$1 }, entry.name), (0, react.createElement)("span", { style: COUNT_STYLE }, expandPair(t("skillUsage.uses"), entry.count, entry.count)), latestNames.includes(entry.name) && (0, react.createElement)("span", { style: TAG_STYLE }, t("skillUsage.latestTag"))))), rest.length > 0 && (0, react.createElement)(FoldToggle, {
|
|
2065
|
+
}, (0, react.createElement)("span", { style: NAME_STYLE$1 }, entry.name), (0, react.createElement)("span", { style: COUNT_STYLE }, expandPair(t("skillUsage.uses"), entry.count, entry.count)), latestNames.includes(entry.name) && (0, react.createElement)("span", { style: TAG_STYLE$1 }, t("skillUsage.latestTag"))))), rest.length > 0 && (0, react.createElement)(FoldToggle, {
|
|
1847
2066
|
label: expandCount(t("skillUsage.availableGroup"), rest.length),
|
|
1848
2067
|
open: availableOpen,
|
|
1849
2068
|
marker: "skill-usage-available-toggle",
|
|
@@ -1853,11 +2072,193 @@ window.__ModuleLoader__.load({
|
|
|
1853
2072
|
}), rest.length > 0 && view.availableCount > view.available.length && (0, react.createElement)(GroupCaption, {
|
|
1854
2073
|
text: expandCount(t("skillUsage.availableCapped"), view.availableCount),
|
|
1855
2074
|
marker: "skill-usage-available-capped"
|
|
1856
|
-
}), availableOpen && (0, react.createElement)("ul", { style: LIST_STYLE$
|
|
2075
|
+
}), availableOpen && (0, react.createElement)("ul", { style: LIST_STYLE$3 }, rest.map((name) => (0, react.createElement)("li", {
|
|
1857
2076
|
key: name,
|
|
1858
|
-
style: ROW_STYLE$
|
|
2077
|
+
style: ROW_STYLE$4,
|
|
1859
2078
|
"data-dsh-brief-sidebar": "skill-usage-available-row"
|
|
1860
|
-
}, (0, react.createElement)("span", { style: NAME_STYLE$1 }, name)))), view.session.length > 0 && (0, react.createElement)("div", { style: FOOTER_STYLE$
|
|
2079
|
+
}, (0, react.createElement)("span", { style: NAME_STYLE$1 }, name)))), view.session.length > 0 && (0, react.createElement)("div", { style: FOOTER_STYLE$3 }, expandPair(t("skillUsage.count"), view.callTotal, view.sessionTotal)));
|
|
2080
|
+
}
|
|
2081
|
+
//#endregion
|
|
2082
|
+
//#region src/client/summary/SearchRefSection.tsx
|
|
2083
|
+
/**
|
|
2084
|
+
* The search-reference section: the `dshSummarySearchRefs` projection drawn as
|
|
2085
|
+
* one tab of the references section.
|
|
2086
|
+
*
|
|
2087
|
+
* It answers "what did this session pull in from outside": the queries it ran
|
|
2088
|
+
* through `advanced_search`, and the sources those searches returned. Two
|
|
2089
|
+
* groups, because they are two different facts — a query says what was asked,
|
|
2090
|
+
* a source says what came back, and an older `dsh-free-search` without
|
|
2091
|
+
* `presentationMeta` produces queries with no sources at all. That degraded
|
|
2092
|
+
* case is stated rather than hidden, because an empty source list would
|
|
2093
|
+
* otherwise read as "the search found nothing".
|
|
2094
|
+
*
|
|
2095
|
+
* Optional on both sides: no registry, or a host half that never registered the
|
|
2096
|
+
* unit, means the client reads capability absence and the section hides.
|
|
2097
|
+
*
|
|
2098
|
+
* Two contracts inherited from the recall section:
|
|
2099
|
+
* - **no native `title` attribute** — the whole text rides the row or is left
|
|
2100
|
+
* out; an unskinable tooltip would overlap the plugin's own surfaces;
|
|
2101
|
+
* - **colours from `--dsw-alias-*` tokens only** (skin contract).
|
|
2102
|
+
*
|
|
2103
|
+
* Source links are untrusted external data, so only `http`/`https` become
|
|
2104
|
+
* anchors (see `safeHref`) and they open with `rel="noreferrer noopener"`.
|
|
2105
|
+
*/
|
|
2106
|
+
const SECTION_STYLE$3 = {
|
|
2107
|
+
flexShrink: 0,
|
|
2108
|
+
borderBottom: "1px solid var(--dsw-alias-border-secondary)"
|
|
2109
|
+
};
|
|
2110
|
+
const HEADER_STYLE$4 = {
|
|
2111
|
+
padding: "10px 12px 0",
|
|
2112
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
2113
|
+
fontSize: 12,
|
|
2114
|
+
fontWeight: 600
|
|
2115
|
+
};
|
|
2116
|
+
const LIST_STYLE$2 = {
|
|
2117
|
+
listStyle: "none",
|
|
2118
|
+
margin: 0,
|
|
2119
|
+
padding: "6px 0",
|
|
2120
|
+
display: "flex",
|
|
2121
|
+
flexDirection: "column"
|
|
2122
|
+
};
|
|
2123
|
+
const ROW_STYLE$3 = {
|
|
2124
|
+
display: "flex",
|
|
2125
|
+
alignItems: "flex-start",
|
|
2126
|
+
gap: 8,
|
|
2127
|
+
padding: "6px 12px"
|
|
2128
|
+
};
|
|
2129
|
+
const QUERY_STYLE = {
|
|
2130
|
+
minWidth: 0,
|
|
2131
|
+
flex: "1 1 auto",
|
|
2132
|
+
overflowWrap: "anywhere",
|
|
2133
|
+
color: "var(--dsw-alias-label-secondary)"
|
|
2134
|
+
};
|
|
2135
|
+
/** The source title, one line: the host and URL carry the identification. */
|
|
2136
|
+
const TITLE_STYLE$2 = {
|
|
2137
|
+
minWidth: 0,
|
|
2138
|
+
flex: "1 1 auto",
|
|
2139
|
+
display: "-webkit-box",
|
|
2140
|
+
WebkitLineClamp: 2,
|
|
2141
|
+
WebkitBoxOrient: "vertical",
|
|
2142
|
+
overflow: "hidden",
|
|
2143
|
+
color: "var(--dsw-alias-label-secondary)"
|
|
2144
|
+
};
|
|
2145
|
+
const SNIPPET_STYLE = {
|
|
2146
|
+
margin: 0,
|
|
2147
|
+
minWidth: 0,
|
|
2148
|
+
overflowWrap: "anywhere",
|
|
2149
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2150
|
+
fontSize: 11,
|
|
2151
|
+
lineHeight: "16px"
|
|
2152
|
+
};
|
|
2153
|
+
const META_STYLE$2 = {
|
|
2154
|
+
flexShrink: 0,
|
|
2155
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2156
|
+
fontSize: 11,
|
|
2157
|
+
lineHeight: "18px",
|
|
2158
|
+
whiteSpace: "nowrap"
|
|
2159
|
+
};
|
|
2160
|
+
/** The "本轮" pill: same form as the skill tag, tertiary emphasis. */
|
|
2161
|
+
const TAG_STYLE = {
|
|
2162
|
+
flexShrink: 0,
|
|
2163
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2164
|
+
border: "1px solid var(--dsw-alias-label-tertiary)",
|
|
2165
|
+
borderRadius: 999,
|
|
2166
|
+
padding: "0 6px",
|
|
2167
|
+
fontSize: 11,
|
|
2168
|
+
lineHeight: "16px",
|
|
2169
|
+
whiteSpace: "nowrap"
|
|
2170
|
+
};
|
|
2171
|
+
const FOOTER_STYLE$2 = {
|
|
2172
|
+
padding: "0 12px 10px",
|
|
2173
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2174
|
+
fontSize: 11
|
|
2175
|
+
};
|
|
2176
|
+
const EMPTY_STYLE$2 = {
|
|
2177
|
+
margin: "0 auto",
|
|
2178
|
+
padding: 24,
|
|
2179
|
+
maxWidth: 460,
|
|
2180
|
+
textAlign: "center",
|
|
2181
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2182
|
+
lineHeight: 1.7,
|
|
2183
|
+
fontSize: 12
|
|
2184
|
+
};
|
|
2185
|
+
/**
|
|
2186
|
+
* The search-reference section. The subscription is unconditional (a plain
|
|
2187
|
+
* listener, not IO); the view decides whether anything is drawn.
|
|
2188
|
+
*
|
|
2189
|
+
* @param props - translation, client context, session scope, header switch.
|
|
2190
|
+
*/
|
|
2191
|
+
function SearchRefSection(props) {
|
|
2192
|
+
const { t, ctx, scope, hideHeader = false } = props;
|
|
2193
|
+
const view = readSearchRefs(useProjectionValue(ctx, scope?.sessionId, SEARCH_REFS_KEY));
|
|
2194
|
+
if (view === void 0) return null;
|
|
2195
|
+
if (view.queries.length === 0 && view.sources.length === 0) return (0, react.createElement)("div", {
|
|
2196
|
+
style: SECTION_STYLE$3,
|
|
2197
|
+
"data-dsh-brief-sidebar": "search-refs-section"
|
|
2198
|
+
}, !hideHeader && (0, react.createElement)("div", { style: HEADER_STYLE$4 }, t("section.searchRefs")), (0, react.createElement)("div", { style: EMPTY_STYLE$2 }, (0, react.createElement)("div", { style: {
|
|
2199
|
+
marginBottom: 6,
|
|
2200
|
+
color: "var(--dsw-alias-label-secondary)"
|
|
2201
|
+
} }, t("searchRefs.empty")), (0, react.createElement)("div", null, t("searchRefs.emptyHint"))));
|
|
2202
|
+
const body = [];
|
|
2203
|
+
if (view.queries.length > 0) {
|
|
2204
|
+
body.push((0, react.createElement)(GroupHeader, {
|
|
2205
|
+
key: "qh",
|
|
2206
|
+
text: expandCount(t("searchRefs.queryGroup"), view.queries.length),
|
|
2207
|
+
marker: "search-refs-query-group"
|
|
2208
|
+
}));
|
|
2209
|
+
body.push((0, react.createElement)("ul", {
|
|
2210
|
+
key: "ql",
|
|
2211
|
+
style: LIST_STYLE$2
|
|
2212
|
+
}, view.queries.map((row) => (0, react.createElement)("li", {
|
|
2213
|
+
key: `${row.turn}:${row.query}`,
|
|
2214
|
+
style: ROW_STYLE$3,
|
|
2215
|
+
"data-dsh-brief-sidebar": "search-refs-query"
|
|
2216
|
+
}, (0, react.createElement)("span", { style: QUERY_STYLE }, row.query), (0, react.createElement)("span", { style: META_STYLE$2 }, expandCount(t("searchRefs.hits"), row.hits))))));
|
|
2217
|
+
}
|
|
2218
|
+
if (view.sources.length > 0) {
|
|
2219
|
+
body.push((0, react.createElement)(GroupHeader, {
|
|
2220
|
+
key: "sh",
|
|
2221
|
+
text: expandCount(t("searchRefs.sourceGroup"), view.sources.length),
|
|
2222
|
+
marker: "search-refs-source-group"
|
|
2223
|
+
}));
|
|
2224
|
+
body.push((0, react.createElement)("ul", {
|
|
2225
|
+
key: "sl",
|
|
2226
|
+
style: LIST_STYLE$2
|
|
2227
|
+
}, view.sources.map((item) => {
|
|
2228
|
+
const href = safeHref(item.url);
|
|
2229
|
+
const label = item.title ?? item.url;
|
|
2230
|
+
const link = href === void 0 ? (0, react.createElement)("span", { style: TITLE_STYLE$2 }, label) : (0, react.createElement)("a", {
|
|
2231
|
+
style: TITLE_STYLE$2,
|
|
2232
|
+
href,
|
|
2233
|
+
target: "_blank",
|
|
2234
|
+
rel: "noreferrer noopener"
|
|
2235
|
+
}, label);
|
|
2236
|
+
return (0, react.createElement)("li", {
|
|
2237
|
+
key: item.url,
|
|
2238
|
+
style: ROW_STYLE$3,
|
|
2239
|
+
"data-dsh-brief-sidebar": "search-refs-source"
|
|
2240
|
+
}, (0, react.createElement)("div", { style: {
|
|
2241
|
+
minWidth: 0,
|
|
2242
|
+
flex: "1 1 auto",
|
|
2243
|
+
display: "flex",
|
|
2244
|
+
flexDirection: "column",
|
|
2245
|
+
gap: 2
|
|
2246
|
+
} }, link, (0, react.createElement)("span", { style: META_STYLE$2 }, item.host), item.snippet !== void 0 && (0, react.createElement)("p", { style: SNIPPET_STYLE }, item.snippet)), isLatestSource(view, item.url) && (0, react.createElement)("span", { style: TAG_STYLE }, t("searchRefs.latestTag")));
|
|
2247
|
+
})));
|
|
2248
|
+
} else body.push((0, react.createElement)("div", {
|
|
2249
|
+
key: "ns",
|
|
2250
|
+
style: FOOTER_STYLE$2,
|
|
2251
|
+
"data-dsh-brief-sidebar": "search-refs-no-sources"
|
|
2252
|
+
}, t("searchRefs.noSourcesHint")));
|
|
2253
|
+
if (view.queryTotal > view.queries.length || view.sourceTotal > view.sources.length) body.push((0, react.createElement)("div", {
|
|
2254
|
+
key: "cap",
|
|
2255
|
+
style: FOOTER_STYLE$2,
|
|
2256
|
+
"data-dsh-brief-sidebar": "search-refs-capped"
|
|
2257
|
+
}, expandTotal(t("searchRefs.capped"), Math.max(view.queryTotal, view.sourceTotal))));
|
|
2258
|
+
return (0, react.createElement)("div", {
|
|
2259
|
+
style: SECTION_STYLE$3,
|
|
2260
|
+
"data-dsh-brief-sidebar": "search-refs-section"
|
|
2261
|
+
}, !hideHeader && (0, react.createElement)("div", { style: HEADER_STYLE$4 }, t("section.searchRefs")), ...body);
|
|
1861
2262
|
}
|
|
1862
2263
|
//#endregion
|
|
1863
2264
|
//#region src/client/summary/recall-feedback.ts
|
|
@@ -2849,7 +3250,11 @@ window.__ModuleLoader__.load({
|
|
|
2849
3250
|
color: "var(--dsw-alias-label-primary)",
|
|
2850
3251
|
fontWeight: 600
|
|
2851
3252
|
};
|
|
2852
|
-
const ORDER = [
|
|
3253
|
+
const ORDER = [
|
|
3254
|
+
"skills",
|
|
3255
|
+
"memory",
|
|
3256
|
+
"search"
|
|
3257
|
+
];
|
|
2853
3258
|
/**
|
|
2854
3259
|
* The references section. All hooks run before any early return, so the tab
|
|
2855
3260
|
* strip can disappear (no capability at all) without ever changing hook order.
|
|
@@ -2860,19 +3265,28 @@ window.__ModuleLoader__.load({
|
|
|
2860
3265
|
const { t, ctx, scope, fetchImpl } = props;
|
|
2861
3266
|
const [tab, setTab] = (0, react.useState)("skills");
|
|
2862
3267
|
const skillsLive = readSkillUsage(useProjectionValue(ctx, scope?.sessionId, SKILL_USAGE_KEY)) !== void 0;
|
|
3268
|
+
const searchLive = readSearchRefs(useProjectionValue(ctx, scope?.sessionId, SEARCH_REFS_KEY)) !== void 0;
|
|
2863
3269
|
const recallFrame = readRecall(useProjectionValue(ctx, scope?.sessionId, MEMORY_RECALL_KEY));
|
|
2864
3270
|
const slotsFrame = readSlots(useProjectionValue(ctx, scope?.sessionId, MEMORY_SLOTS_KEY));
|
|
2865
3271
|
const recallOn = useConfigFlag(ctx, resolveShowMemoryRecall) !== false;
|
|
2866
3272
|
const slotsOn = useConfigFlag(ctx, resolveShowMemorySlots) === true;
|
|
2867
3273
|
const memoryLive = recallFrame !== void 0 && recallOn || slotsFrame !== void 0 && slotsOn;
|
|
3274
|
+
const live = {
|
|
3275
|
+
skills: skillsLive,
|
|
3276
|
+
memory: memoryLive,
|
|
3277
|
+
search: searchLive
|
|
3278
|
+
};
|
|
3279
|
+
const active = live[tab] ? tab : ORDER.find((id) => live[id]) ?? "skills";
|
|
2868
3280
|
const onTabsKeyDown = (0, react.useCallback)((event) => {
|
|
2869
3281
|
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
2870
3282
|
event.preventDefault();
|
|
2871
|
-
const
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
3283
|
+
const shown = ORDER.filter((id) => live[id]);
|
|
3284
|
+
if (shown.length < 2) return;
|
|
3285
|
+
const at = shown.indexOf(active);
|
|
3286
|
+
const step = event.key === "ArrowRight" ? 1 : shown.length - 1;
|
|
3287
|
+
setTab(shown[(at + step) % shown.length]);
|
|
3288
|
+
}, [live, active]);
|
|
3289
|
+
if (!skillsLive && !memoryLive && !searchLive) return null;
|
|
2876
3290
|
const tabButton = (id, label) => (0, react.createElement)("button", {
|
|
2877
3291
|
key: id,
|
|
2878
3292
|
type: "button",
|
|
@@ -2886,7 +3300,6 @@ window.__ModuleLoader__.load({
|
|
|
2886
3300
|
setTab(id);
|
|
2887
3301
|
}
|
|
2888
3302
|
}, label);
|
|
2889
|
-
const active = tab === "skills" && !skillsLive ? "memory" : tab;
|
|
2890
3303
|
return (0, react.createElement)("div", {
|
|
2891
3304
|
style: SECTION_STYLE,
|
|
2892
3305
|
"data-dsh-brief-sidebar": "references-section"
|
|
@@ -2896,7 +3309,7 @@ window.__ModuleLoader__.load({
|
|
|
2896
3309
|
style: TABS_STYLE,
|
|
2897
3310
|
onKeyDown: onTabsKeyDown,
|
|
2898
3311
|
"data-dsh-brief-sidebar": "reference-tabs"
|
|
2899
|
-
}, skillsLive && tabButton("skills", t("references.tabSkills")), memoryLive && tabButton("memory", t("references.tabMemory"))), skillsLive && (0, react.createElement)("div", {
|
|
3312
|
+
}, skillsLive && tabButton("skills", t("references.tabSkills")), memoryLive && tabButton("memory", t("references.tabMemory")), searchLive && tabButton("search", t("references.tabSearch"))), skillsLive && (0, react.createElement)("div", {
|
|
2900
3313
|
role: "tabpanel",
|
|
2901
3314
|
id: "dsh-brief-reference-pane-skills",
|
|
2902
3315
|
"aria-labelledby": "dsh-brief-reference-tab-skills",
|
|
@@ -2924,6 +3337,18 @@ window.__ModuleLoader__.load({
|
|
|
2924
3337
|
t,
|
|
2925
3338
|
ctx,
|
|
2926
3339
|
scope
|
|
3340
|
+
})), searchLive && (0, react.createElement)("div", {
|
|
3341
|
+
role: "tabpanel",
|
|
3342
|
+
id: "dsh-brief-reference-pane-search",
|
|
3343
|
+
"aria-labelledby": "dsh-brief-reference-tab-search",
|
|
3344
|
+
hidden: active !== "search",
|
|
3345
|
+
style: active === "search" ? void 0 : { display: "none" },
|
|
3346
|
+
"data-dsh-brief-sidebar": "reference-pane-search"
|
|
3347
|
+
}, (0, react.createElement)(SearchRefSection, {
|
|
3348
|
+
t,
|
|
3349
|
+
ctx,
|
|
3350
|
+
scope,
|
|
3351
|
+
hideHeader: true
|
|
2927
3352
|
})));
|
|
2928
3353
|
}
|
|
2929
3354
|
//#endregion
|