dsh-ws-recency 0.10.2 → 0.10.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/README.md +1 -1
- package/client.js +123 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ dsh plugin --profile <profile> add github:chyxhtc/dsh-ws-recency
|
|
|
110
110
|
或固定版本的预构建包:
|
|
111
111
|
|
|
112
112
|
```powershell
|
|
113
|
-
dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.10.
|
|
113
|
+
dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.10.4/dsh-ws-recency-0.10.4.tgz
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
装完把 `dsh-ws-recency` 加进 `~/.hypers-work/profiles/<profile>/package.json` 的 `dsh.profile.bundles`,重启应用。
|
package/client.js
CHANGED
|
@@ -230,13 +230,27 @@
|
|
|
230
230
|
"trash.failed": "Delete failed: ",
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
/* Resolved lazily: the dictionaries are declared further down this closure. */
|
|
234
|
+
var resolvedDictionary = null;
|
|
235
|
+
|
|
236
|
+
function fallbackDictionary() {
|
|
237
|
+
if (resolvedDictionary !== null) return resolvedDictionary;
|
|
238
|
+
var language = "";
|
|
239
|
+
/* The page's own lang wins: it is what the UI is actually rendered in. */
|
|
240
|
+
try { if (typeof document !== "undefined" && document.documentElement !== null && document.documentElement !== undefined) language = document.documentElement.lang || ""; } catch (error) { language = ""; }
|
|
241
|
+
try { if (language === "" && typeof navigator !== "undefined" && navigator.language) language = navigator.language; } catch (error) { /* keep empty */ }
|
|
242
|
+
resolvedDictionary = String(language).toLowerCase().indexOf("zh") === 0 ? ZH : EN;
|
|
243
|
+
return resolvedDictionary;
|
|
244
|
+
}
|
|
234
245
|
|
|
235
246
|
function t(key, params) {
|
|
236
247
|
if (typeof data.t === "function") {
|
|
237
|
-
|
|
248
|
+
var translated = null;
|
|
249
|
+
try { translated = data.t(key, params); } catch (error) { translated = null; }
|
|
250
|
+
if (typeof translated === "string" && translated !== key) return translated;
|
|
238
251
|
}
|
|
239
|
-
var
|
|
252
|
+
var dictionary = fallbackDictionary();
|
|
253
|
+
var text = (dictionary && dictionary[key]) || key;
|
|
240
254
|
if (params !== undefined && params.n !== undefined) text = text.replace("{n}", String(params.n));
|
|
241
255
|
return text;
|
|
242
256
|
}
|
|
@@ -799,12 +813,72 @@
|
|
|
799
813
|
return typeof id === "string" && id !== "" ? id : null;
|
|
800
814
|
}
|
|
801
815
|
|
|
816
|
+
/** The nearest horizontal flex row above the stats: the whole footer dock. */
|
|
817
|
+
function composerDockOf(row) {
|
|
818
|
+
var node = row;
|
|
819
|
+
for (var depth = 0; depth < 4; depth += 1) {
|
|
820
|
+
var parent = node.parentElement;
|
|
821
|
+
if (parent === null) break;
|
|
822
|
+
var style = null;
|
|
823
|
+
try {
|
|
824
|
+
style = typeof window !== "undefined" && typeof window.getComputedStyle === "function"
|
|
825
|
+
? window.getComputedStyle(parent)
|
|
826
|
+
: null;
|
|
827
|
+
} catch (error) {
|
|
828
|
+
style = null;
|
|
829
|
+
}
|
|
830
|
+
if (style !== null && style.display === "flex" && (style.flexDirection === "row" || style.flexDirection === "")) return parent;
|
|
831
|
+
node = parent;
|
|
832
|
+
}
|
|
833
|
+
return row.parentElement === null ? row : row.parentElement;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/** The host's own pill in that row, used as the visual template. */
|
|
837
|
+
function pillTemplateOf(row) {
|
|
838
|
+
if (typeof row.querySelector !== "function") return null;
|
|
839
|
+
var button = row.querySelector('button[class*="_pill"]');
|
|
840
|
+
return button !== null ? button : row.querySelector('[class*="_pill"]');
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
function cloneIconOf(template) {
|
|
844
|
+
if (template === null || typeof template.querySelector !== "function") return null;
|
|
845
|
+
var icon = template.querySelector("svg");
|
|
846
|
+
if (icon === null || typeof icon.cloneNode !== "function") return null;
|
|
847
|
+
try { return icon.cloneNode(true); } catch (error) { return null; }
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/** Copy the host pill's own computed metrics onto the clone. */
|
|
851
|
+
function copyPillMetrics(template, wrapper, button) {
|
|
852
|
+
if (template === null || template === undefined || typeof window === "undefined" || typeof window.getComputedStyle !== "function") return;
|
|
853
|
+
var read = function (name) {
|
|
854
|
+
try {
|
|
855
|
+
return window.getComputedStyle(template).getPropertyValue(name) || "";
|
|
856
|
+
} catch (error) {
|
|
857
|
+
return "";
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
var inherited = ["font-size", "font-family", "font-weight", "line-height", "letter-spacing"];
|
|
861
|
+
for (var i = 0; i < inherited.length; i += 1) {
|
|
862
|
+
var value = read(inherited[i]);
|
|
863
|
+
if (value !== "") {
|
|
864
|
+
wrapper.style[inherited[i]] = value;
|
|
865
|
+
button.style[inherited[i]] = value;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
var own = ["padding", "gap", "border-radius", "color"];
|
|
869
|
+
for (var j = 0; j < own.length; j += 1) {
|
|
870
|
+
var metric = read(own[j]);
|
|
871
|
+
if (metric !== "") button.style[own[j]] = metric;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
802
875
|
/**
|
|
803
|
-
* Add one pill
|
|
804
|
-
*
|
|
876
|
+
* Add one pill at the END of the composer footer that opens the analysis
|
|
877
|
+
* panel for the conversation on screen.
|
|
805
878
|
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
879
|
+
* It reuses the host pill's own class names and icon so it reads as part of
|
|
880
|
+
* the same row, sits after the context ring rather than between the stats,
|
|
881
|
+
* is re-attached whenever the host re-renders, and disappears with the row.
|
|
808
882
|
*/
|
|
809
883
|
function decorateComposerStats() {
|
|
810
884
|
if (typeof document === "undefined") return;
|
|
@@ -818,21 +892,46 @@
|
|
|
818
892
|
}
|
|
819
893
|
var row = anchors[0].parentElement;
|
|
820
894
|
if (row === null) return;
|
|
895
|
+
var dock = composerDockOf(row);
|
|
896
|
+
|
|
821
897
|
if (existing === null) {
|
|
898
|
+
var template = pillTemplateOf(row);
|
|
899
|
+
/* Wrapped exactly like a host pill (its anchor span) and carrying the
|
|
900
|
+
host's own computed metrics: appended to the footer dock rather than
|
|
901
|
+
into the stats row, this pill would otherwise inherit the dock's font
|
|
902
|
+
size and read larger than its neighbours. */
|
|
903
|
+
var wrapper = document.createElement("span");
|
|
904
|
+
wrapper.setAttribute("data-wsr-composer-analysis", "true");
|
|
905
|
+
var anchorTemplate = template === null ? null : template.parentElement;
|
|
906
|
+
var anchorClass = anchorTemplate !== null && typeof anchorTemplate.className === "string" ? anchorTemplate.className : "";
|
|
907
|
+
if (anchorClass !== "") wrapper.className = anchorClass;
|
|
822
908
|
var button = document.createElement("button");
|
|
823
909
|
button.type = "button";
|
|
824
|
-
|
|
825
|
-
button.
|
|
826
|
-
|
|
910
|
+
var base = template !== null && typeof template.className === "string" ? template.className : "";
|
|
911
|
+
button.className = base === "" ? "wsr-pill" : base + " wsr-pill";
|
|
912
|
+
var icon = cloneIconOf(template);
|
|
913
|
+
if (icon !== null) button.appendChild(icon);
|
|
914
|
+
var label = document.createElement("span");
|
|
915
|
+
var labelTemplate = template === null || typeof template.querySelector !== "function" ? null : template.querySelector('[class*="_label"]');
|
|
916
|
+
label.className = labelTemplate !== null && typeof labelTemplate.className === "string" && labelTemplate.className !== ""
|
|
917
|
+
? labelTemplate.className
|
|
918
|
+
: "wsr-pill-label";
|
|
919
|
+
label.textContent = t("composer.analysis");
|
|
920
|
+
button.appendChild(label);
|
|
827
921
|
button.addEventListener("click", function () {
|
|
828
922
|
var id = currentConversationId();
|
|
829
923
|
if (id !== null) openStatsPanel(id);
|
|
830
924
|
});
|
|
831
|
-
|
|
925
|
+
copyPillMetrics(template, wrapper, button);
|
|
926
|
+
wrapper.appendChild(button);
|
|
927
|
+
composerPill = wrapper;
|
|
832
928
|
} else {
|
|
833
929
|
composerPill = existing;
|
|
834
930
|
}
|
|
835
|
-
|
|
931
|
+
var children = dock.children || [];
|
|
932
|
+
if (composerPill.parentElement !== dock || children[children.length - 1] !== composerPill) {
|
|
933
|
+
dock.appendChild(composerPill);
|
|
934
|
+
}
|
|
836
935
|
}
|
|
837
936
|
|
|
838
937
|
function apply() {
|
|
@@ -903,7 +1002,7 @@
|
|
|
903
1002
|
return h(Item, {
|
|
904
1003
|
icon: typeof Icon === "function" ? h(Icon, {}) : undefined,
|
|
905
1004
|
onSelect: function () { props.actions.toggleFollowUp(props.sessionId); },
|
|
906
|
-
},
|
|
1005
|
+
}, t(flagged ? "menu.unflag" : "menu.flag"));
|
|
907
1006
|
}
|
|
908
1007
|
|
|
909
1008
|
/**
|
|
@@ -967,7 +1066,7 @@
|
|
|
967
1066
|
if (typeof window.alert === "function") window.alert(t("trash.failed") + (error && error.message ? error.message : error));
|
|
968
1067
|
});
|
|
969
1068
|
},
|
|
970
|
-
},
|
|
1069
|
+
}, t("menu.trash"));
|
|
971
1070
|
}
|
|
972
1071
|
|
|
973
1072
|
/* ------------------------- token statistics ------------------------- */
|
|
@@ -1175,7 +1274,7 @@
|
|
|
1175
1274
|
return h(Item, {
|
|
1176
1275
|
icon: typeof Icon === "function" ? h(Icon, {}) : undefined,
|
|
1177
1276
|
onSelect: function () { openStatsPanel(props.sessionId); },
|
|
1178
|
-
},
|
|
1277
|
+
}, t("menu.stats"));
|
|
1179
1278
|
}
|
|
1180
1279
|
|
|
1181
1280
|
/** Settings -> General row: how old a session must be before it is folded. */
|
|
@@ -1184,11 +1283,11 @@
|
|
|
1184
1283
|
var days = Number(settings.foldDays);
|
|
1185
1284
|
if (!Number.isFinite(days)) days = DEFAULT_DAYS;
|
|
1186
1285
|
var keep = settings.keepActive !== false;
|
|
1187
|
-
var text =
|
|
1286
|
+
var text = t("settings.title");
|
|
1188
1287
|
return h("div", { className: "wsr-setRow" },
|
|
1189
1288
|
h("div", { className: "wsr-setText" },
|
|
1190
1289
|
h("div", { className: "wsr-setTitle" }, text),
|
|
1191
|
-
h("div", { className: "wsr-setDesc" },
|
|
1290
|
+
h("div", { className: "wsr-setDesc" }, t("settings.description")),
|
|
1192
1291
|
),
|
|
1193
1292
|
h("div", { className: "wsr-controls" },
|
|
1194
1293
|
h("button", {
|
|
@@ -1218,7 +1317,7 @@
|
|
|
1218
1317
|
checked: keep,
|
|
1219
1318
|
onChange: function (event) { props.actions.setKeepActive(event.target.checked); },
|
|
1220
1319
|
}),
|
|
1221
|
-
|
|
1320
|
+
t("settings.exempt")),
|
|
1222
1321
|
),
|
|
1223
1322
|
);
|
|
1224
1323
|
}
|
|
@@ -1227,11 +1326,11 @@
|
|
|
1227
1326
|
function ColorsRow(props) {
|
|
1228
1327
|
var settings = props.useStore(function (state) { return state; });
|
|
1229
1328
|
var enabled = settings.colors !== false;
|
|
1230
|
-
var text =
|
|
1329
|
+
var text = t("color.title");
|
|
1231
1330
|
return h("div", { className: "wsr-setRow" },
|
|
1232
1331
|
h("div", { className: "wsr-setText" },
|
|
1233
1332
|
h("div", { className: "wsr-setTitle" }, text),
|
|
1234
|
-
h("div", { className: "wsr-setDesc" },
|
|
1333
|
+
h("div", { className: "wsr-setDesc" }, t("color.description")),
|
|
1235
1334
|
),
|
|
1236
1335
|
h("div", { className: "wsr-controls" },
|
|
1237
1336
|
h("label", { className: "wsr-exempt" },
|
|
@@ -1240,7 +1339,7 @@
|
|
|
1240
1339
|
checked: enabled,
|
|
1241
1340
|
onChange: function (event) { props.actions.setColors(event.target.checked); },
|
|
1242
1341
|
}),
|
|
1243
|
-
|
|
1342
|
+
t("color.enabled")),
|
|
1244
1343
|
),
|
|
1245
1344
|
);
|
|
1246
1345
|
}
|
|
@@ -1249,11 +1348,11 @@
|
|
|
1249
1348
|
function PinSectionRow(props) {
|
|
1250
1349
|
var settings = props.useStore(function (state) { return state; });
|
|
1251
1350
|
var enabled = settings.pinnedSection !== false;
|
|
1252
|
-
var text =
|
|
1351
|
+
var text = t("pin.title");
|
|
1253
1352
|
return h("div", { className: "wsr-setRow" },
|
|
1254
1353
|
h("div", { className: "wsr-setText" },
|
|
1255
1354
|
h("div", { className: "wsr-setTitle" }, text),
|
|
1256
|
-
h("div", { className: "wsr-setDesc" },
|
|
1355
|
+
h("div", { className: "wsr-setDesc" }, t("pin.description")),
|
|
1257
1356
|
),
|
|
1258
1357
|
h("div", { className: "wsr-controls" },
|
|
1259
1358
|
h("label", { className: "wsr-exempt" },
|
|
@@ -1262,7 +1361,7 @@
|
|
|
1262
1361
|
checked: enabled,
|
|
1263
1362
|
onChange: function (event) { props.actions.setPinnedSection(event.target.checked); },
|
|
1264
1363
|
}),
|
|
1265
|
-
|
|
1364
|
+
t("pin.enabled")),
|
|
1266
1365
|
),
|
|
1267
1366
|
);
|
|
1268
1367
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ws-recency",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"description": "Sidebar session management for DeepSeek Harness: workspace groups sorted by latest activity, stale history folded, a global pinned section, follow-up marks, session delete into a recoverable trash, and per-session token statistics split by tool.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "chyxhtc",
|