dsh-ws-recency 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/client.js +62 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -65,7 +65,7 @@ DSH 原生的置顶只把会话顶到**它所属工作区分组的第一行**,
65
65
 
66
66
  ## 六、Token 消耗统计
67
67
 
68
- 会话「…」菜单 →「Token 消耗统计」:
68
+ 会话下方统计条上的「用量分析」,或会话「…」菜单 →「Token 消耗统计」:
69
69
 
70
70
  - **真实账单**(每步记录的 usage):步数、输入(未缓存)、缓存命中、输出、合计;
71
71
  - **结构占比**(按内容估算):主 agent 自己(思考 / 回复 / 用户消息 / 系统提示)vs 每个工具,一条占比条 + 图例;
@@ -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.1/dsh-ws-recency-0.10.1.tgz
113
+ dsh plugin --profile <profile> add https://github.com/chyxhtc/dsh-ws-recency/releases/download/v0.10.2/dsh-ws-recency-0.10.2.tgz
114
114
  ```
115
115
 
116
116
  装完把 `dsh-ws-recency` 加进 `~/.hypers-work/profiles/<profile>/package.json` 的 `dsh.profile.bundles`,重启应用。
package/client.js CHANGED
@@ -85,6 +85,7 @@
85
85
  var pinHidden = new Set();
86
86
  var pinHost = null;
87
87
  var expandClicks = new Map();
88
+ var composerPill = null;
88
89
  var expandedSections = new Set();
89
90
  var headerMarked = new WeakSet();
90
91
  var disposed = false;
@@ -104,6 +105,8 @@
104
105
  ".wsr-pin-unpin{flex:none;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:11px;padding:2px 4px;border-radius:4px;visibility:hidden}",
105
106
  ".wsr-pin-row:hover .wsr-pin-unpin{visibility:visible}",
106
107
  ".wsr-pin-unpin:hover{color:var(--dsw-alias-label-primary)}",
108
+ ".wsr-pill{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);font:inherit;font-variant-numeric:tabular-nums;line-height:inherit;white-space:nowrap;border-radius:var(--dsw-radius-sm,6px);display:inline-flex;align-items:center;gap:6px;padding:1px 8px;cursor:pointer}",
109
+ ".wsr-pill:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-secondary,#cfd3d8)}",
107
110
  ".wsr-modal-backdrop{position:fixed;inset:0;z-index:2000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45)}",
108
111
  ".wsr-modal{width:min(720px,92vw);max-height:84vh;display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1,#1f2226);color:var(--dsw-alias-label-primary,#e8e8e8);border:.5px solid var(--dsw-alias-border-l2,rgba(255,255,255,.14));border-radius:10px;box-shadow:0 12px 40px rgba(0,0,0,.45);overflow:hidden}",
109
112
  ".wsr-modal-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;border-bottom:.5px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1))}",
@@ -181,6 +184,7 @@
181
184
  "stats.agentDetail": "主 agent 构成:思考 {reasoning} · 回复 {text} · 用户消息 {user} · 系统提示 {system}",
182
185
  "stats.diagnose.unmounted": "\n\n(宿主半已加载,但统计路由没挂上——重启应用再试)",
183
186
  "stats.diagnose.noHost": "\n\n(宿主半未加载:需要重启应用加载新版本)",
187
+ "composer.analysis": "用量分析",
184
188
  "trash.confirm": "\u5220\u9664\u8fd9\u4e2a\u4f1a\u8bdd\uff1f\n\n\u4f1a\u5148\u505c\u6b62\u5b83\u6b63\u5728\u8fdb\u884c\u7684\u5de5\u4f5c\uff0c\u518d\u628a\u65e5\u5fd7\u76ee\u5f55\u79fb\u5165\u56de\u6536\u7ad9\uff08\u4e0d\u662f\u7269\u7406\u5220\u9664\uff0c\u53ef\u4ee5\u624b\u52a8\u6062\u590d\uff09\u3002",
185
189
  "trash.failed": "\u5220\u9664\u5931\u8d25\uff1a",
186
190
  };
@@ -221,6 +225,7 @@
221
225
  "stats.agentDetail": "Agent composition: reasoning {reasoning} \u00b7 reply {text} \u00b7 user messages {user} \u00b7 system prompt {system}",
222
226
  "stats.diagnose.unmounted": "\n\n(the host half is loaded but the statistics route did not mount - restart the app and retry)",
223
227
  "stats.diagnose.noHost": "\n\n(the host half is not loaded: restart the app to pick up the new version)",
228
+ "composer.analysis": "Usage analysis",
224
229
  "trash.confirm": "Delete this session?\n\nIt stops whatever the session is running, then moves the log directory into the trash folder (a move, not an erase: you can restore it by hand).",
225
230
  "trash.failed": "Delete failed: ",
226
231
  };
@@ -785,20 +790,72 @@
785
790
  }
786
791
  }
787
792
 
793
+ /** The session the conversation view is showing, from its own DOM hook. */
794
+ function currentConversationId() {
795
+ if (typeof document === "undefined") return null;
796
+ var element = document.querySelector("[data-conversation-session]");
797
+ if (element === null || typeof element.getAttribute !== "function") return null;
798
+ var id = element.getAttribute("data-conversation-session");
799
+ return typeof id === "string" && id !== "" ? id : null;
800
+ }
801
+
802
+ /**
803
+ * Add one pill to the composer's statistics row ("turns / steps / tokens")
804
+ * that opens the same analysis panel as the session menu.
805
+ *
806
+ * The row is host-rendered and re-renders often, so the pill is re-attached
807
+ * on every pass and dropped as soon as the row or the session goes away.
808
+ */
809
+ function decorateComposerStats() {
810
+ if (typeof document === "undefined") return;
811
+ var existing = document.querySelector("[data-wsr-composer-analysis]");
812
+ var seat = document.querySelector("[data-composer-seat]");
813
+ var anchors = seat === null || typeof seat.querySelectorAll !== "function" ? [] : seat.querySelectorAll("[data-composer-stat]");
814
+ if (anchors.length === 0 || currentConversationId() === null) {
815
+ if (existing !== null) existing.remove();
816
+ composerPill = null;
817
+ return;
818
+ }
819
+ var row = anchors[0].parentElement;
820
+ if (row === null) return;
821
+ if (existing === null) {
822
+ var button = document.createElement("button");
823
+ button.type = "button";
824
+ button.className = "wsr-pill";
825
+ button.setAttribute("data-wsr-composer-analysis", "true");
826
+ button.textContent = t("composer.analysis");
827
+ button.addEventListener("click", function () {
828
+ var id = currentConversationId();
829
+ if (id !== null) openStatsPanel(id);
830
+ });
831
+ composerPill = button;
832
+ } else {
833
+ composerPill = existing;
834
+ }
835
+ if (composerPill.parentElement !== row) row.appendChild(composerPill);
836
+ }
837
+
788
838
  function apply() {
789
839
  if (disposed) return;
790
840
  var sessions = data.sessions;
791
841
  var workspaces = data.workspaces;
792
- if (!ready(sessions) || !ready(workspaces)) return;
793
-
794
842
  var settings = settingsOf();
843
+ if (!ready(sessions) || !ready(workspaces)) {
844
+ decorateComposerStats();
845
+ return;
846
+ }
847
+
795
848
  var entries = collect();
796
- if (entries.length === 0) return;
849
+ if (entries.length === 0) {
850
+ decorateComposerStats();
851
+ return;
852
+ }
797
853
 
798
854
  orderGroups(entries, latestByWorkspace(sessions, workspaces));
799
855
  foldRows(entries, settings, sessions, Date.now());
800
856
  renderPinned(entries, sessions, workspaces, settings);
801
857
  if (settings.colors) decorateRows(entries, sessions, data.statuses, settings);
858
+ decorateComposerStats();
802
859
  }
803
860
 
804
861
  function schedule() {
@@ -1236,6 +1293,8 @@
1236
1293
  });
1237
1294
  pinHidden.clear();
1238
1295
  if (pinHost !== null && pinHost.parentElement !== null) pinHost.remove();
1296
+ if (composerPill !== null && typeof composerPill.remove === "function") composerPill.remove();
1297
+ composerPill = null;
1239
1298
  pinHost = null;
1240
1299
  expandClicks.clear();
1241
1300
  roots.forEach(function (root) { root.removeAttribute(ROOT_ATTR); });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ws-recency",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
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",