dsh-api-dashboard 1.4.3 → 1.4.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/index.js +44 -12
package/README.md CHANGED
@@ -125,7 +125,7 @@ dsh plugin --profile web add link:/root/dsha-api-dashboard
125
125
 
126
126
  ## 更新日志
127
127
 
128
- 最近一版 **v1.4.3** —— 子代理胶囊只显示**它自己新产生**的消耗(不再把父会话继承来的历史、兄弟或后代子代理的消耗算进去)。一版一行的完整历史见 [`CHANGELOG.md`](CHANGELOG.md)。
128
+ 最近一版 **v1.4.4** —— 子代理胶囊只显示**它自己新产生**的消耗(不再把父会话继承来的历史、兄弟或后代子代理的消耗算进去);并恢复 v1.4.3 升级后误显示为 `~—` 的历史子代理行。一版一行的完整历史见 [`CHANGELOG.md`](CHANGELOG.md)。
129
129
 
130
130
  ## License
131
131
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-api-dashboard",
3
- "version": "1.4.3",
3
+ "version": "1.4.4",
4
4
  "description": "DeepSeek Harness 多平台 API 余额 / 用量看板:输入框下方实时显示各平台余额与本会话估算消耗",
5
5
  "keywords": [
6
6
  "dsh",
package/src/index.js CHANGED
@@ -1703,32 +1703,64 @@ let subagentCostSummarize = null
1703
1703
 
1704
1704
  const safeSessionId = (id) => typeof id === 'string' && /^[A-Za-z0-9._-]{1,128}$/.test(id) ? id : null
1705
1705
 
1706
- /** 读某会话的投影缓存记录(带 TTL 内存缓存)。任何异常 → null。 */
1707
- const readSessionCacheRecord = (sessionId) => {
1706
+ /**
1707
+ * 读某会话的投影缓存记录(带 TTL 内存缓存)。任何异常 null。
1708
+ * v1.4.4: 同时把 `identity` 带出来 —— 里面记着 `isSeeded` / `inheritedEventCount`(fork 边界),
1709
+ * 旧版本的缓存行(状态里没有 own)要靠它判断「自身用量」能不能精确还原。
1710
+ */
1711
+ const loadCacheEntry = (sessionId) => {
1708
1712
  const id = safeSessionId(sessionId)
1709
1713
  if (id === null) return null
1710
1714
  const now = Date.now()
1711
1715
  const hit = sessionCacheFiles.get(id)
1712
- if (hit !== undefined && now - hit.at < SUBAGENT_FILE_TTL_MS) return hit.rows
1713
- let rows = null
1716
+ if (hit !== undefined && now - hit.at < SUBAGENT_FILE_TTL_MS) return hit
1717
+ let entry = null
1714
1718
  try {
1715
1719
  const home = process.env.DSH_HOME || join(homedir(), '.dsh')
1716
1720
  const file = join(home, 'storages', 'session_projcache', 'sessions', `${id}.json`)
1717
1721
  const parsed = JSON.parse(readFileSync(file, 'utf8'))
1718
1722
  const r = parsed?.record?.rows
1719
- if (r !== null && typeof r === 'object') rows = r
1720
- } catch { rows = null }
1723
+ if (r !== null && typeof r === 'object') {
1724
+ const identity = parsed?.record?.identity
1725
+ entry = { at: now, rows: r, identity: (identity !== null && typeof identity === 'object') ? identity : null }
1726
+ }
1727
+ } catch { entry = null }
1721
1728
  // 只缓存成功结果, 避免一次读失败被 TTL 钉住 3 秒
1722
- if (rows !== null) sessionCacheFiles.set(id, { at: now, rows })
1729
+ if (entry !== null) sessionCacheFiles.set(id, entry)
1723
1730
  if (sessionCacheFiles.size > 256) sessionCacheFiles.clear()
1724
- return rows
1731
+ return entry
1725
1732
  }
1726
1733
 
1727
- /** 冷路径: 从缓存文件里取该会话的 queryBalanceCost **状态**(不是 wire 视图)。 */
1734
+ /** 读某会话的投影缓存 rows。任何异常 null。 */
1735
+ const readSessionCacheRecord = (sessionId) => loadCacheEntry(sessionId)?.rows ?? null
1736
+
1737
+ /**
1738
+ * 冷路径: 从缓存文件里取该会话的 queryBalanceCost **状态**(不是 wire 视图)。
1739
+ *
1740
+ * ⚠️ v1.4.4 修正 v1.4.3 的一个过严判断:v1.4.3 只认 `ver === 3`,于是**升级后所有旧缓存行
1741
+ * 一律显示 `~—`**(老框架不会再给已结束的子会话重写缓存,那些行永远好不了)。
1742
+ * 实际上旧缓存也能精确还原**非分叉**子会话的自身用量:
1743
+ * · `inheritedEventCount === 0`(没有继承任何事件)→ 自身 == 全量,`byModel` 就是精确值;
1744
+ * · 分叉过的子会话 → 旧缓存分不出继承段,**仍然返回 null**(上层显示「等待」),
1745
+ * 绝不退化成把父会话历史算进去的错数字。
1746
+ */
1728
1747
  const cachedCostState = (sessionId) => {
1729
- const row = readSessionCacheRecord(sessionId)?.queryBalanceCost
1730
- const val = row?.ver === 3 ? row.val : null
1731
- return (val !== null && typeof val === 'object' && Array.isArray(val.modelOrder) && val.byModel !== null && typeof val.byModel === 'object') ? val : null
1748
+ const entry = loadCacheEntry(sessionId)
1749
+ const row = entry?.rows?.queryBalanceCost
1750
+ const val = row?.val
1751
+ if (val === null || typeof val !== 'object' || !Array.isArray(val.modelOrder) || val.byModel === null || typeof val.byModel !== 'object') return null
1752
+ if (row.ver === 3 && val.own !== undefined) return val
1753
+ const inherited = entry?.identity?.inheritedEventCount
1754
+ if (inherited === 0) {
1755
+ return {
1756
+ ...val, ownBoundaryKnown: true, inheritedEventCount: 0,
1757
+ own: {
1758
+ currentModel: val.currentModel ?? null, currentProvider: val.currentProvider ?? null,
1759
+ last: val.last ?? null, byModel: val.byModel, modelOrder: val.modelOrder,
1760
+ },
1761
+ }
1762
+ }
1763
+ return null
1732
1764
  }
1733
1765
 
1734
1766
  /** 冷路径: 从缓存文件里取该会话的 subagentCatalog 条目。 */