dsh-compact-relay 0.3.4 → 0.3.5

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/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@
4
4
 
5
5
  (暂无新改动)
6
6
 
7
+ ## 0.3.5(2026-10-24,压缩按钮误禁修复)
8
+
9
+ - **问题(外部用户报告,0.3.3 / Windows;0.3.4 源码同样存在)**:会话用量 53.5%、插件建议压缩,但指示灯菜单「压缩旧会话」灰置,提示「暂无可压缩内容(会话太短,或近期会话需保留原文)」——把「没有活的 agent」误当成「没有可压缩内容」。
10
+ - **根因**:`readState` 的 target 允许退化成「有内容、但还没有活 agent」的 passivized live session(压力/比例能测出来),但 `compactRange` 只在有活 agent 时计算 → 客户端收到 `null` 后禁用按钮并显示通用「暂无可压内容」文案。
11
+ - **修复(additive,HTTP 契约不破坏)**:`lib/actions/state.js` 对 target(含 passivized live session)也计算 `compactRange`(纯显示信息;真正执行/preview 仍要求活 agent);新增字段 `compactRangeReason`,仅当范围存在且无活 agent 时为 `'no_agent'`。
12
+ - **客户端**:菜单「压缩旧会话」在 `reason === 'no_agent'` 时仍禁用(预览需要活 agent),但文案改为「**会话未激活:发一条消息唤醒 agent 后可压 N 条 · 约 X tokens**」(含实际数字;禁用态悬停 `title` 可读);`rangeInfo === null` 与正常可压的既有文案不变。
13
+ - **测试**:新增 `test/state-passive.mjs`(无活 agent 的 live session 仍算出范围 + `reason='no_agent'`;有活 agent `reason=null`;空会话/无会话不误报;既有 state 字段不丢),并入 `npm test`。
14
+ - 测试基线:smoke 53/53、handoff 35/35、plugin-load 14/14、contract 17/17、compact-log PASS、compress-cue PASS、state-passive PASS、markdown-lite PASS;client bundle `--check` 通过(148857 字符)。
15
+
7
16
  ## 0.3.4(2026-10-24,判断机制修复 + 小 bug)
8
17
 
9
18
  ### 判断机制(BUG-010:适合压缩的节点几乎不触发)
package/ROADMAP.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 压缩接力 · 目标与路线图
2
2
 
3
- > 版本基准:0.3.4(2026-10-24)|状态:0.3 已发布(npm + GitHub),0.3.4 发布中
3
+ > 版本基准:0.3.5(2026-10-24)|状态:0.3 已发布(npm + GitHub),0.3.5 补丁发布中
4
4
  > 维护方式:每次发布前更新"当前状态"与勾选进度;方向变化必须同时改本文件和 memory 项目页。
5
5
 
6
6
  ## 一、最终目标(North Star)
@@ -143,6 +143,7 @@
143
143
  - ✅ 0.3.1 发布包已就绪:版本号 / CHANGELOG / README 安装段 / .gitignore / npm `files` 收窄 / 文件权限归一;测试基线 smoke 50、handoff 35、plugin-load 13、contract 17、compact-log PASS。
144
144
  - ✅ 0.3.1 已发布:npm `dsh-compact-relay@0.3.1` + GitHub tag/Release;0.3.2 补设置页链接与联系方式;0.3.3 完成 Windows 适配(Win11 + Node 24.22 全测试通过)。
145
145
  - ✅ 0.3.4 判断机制修复(BUG-010:`mark_compress_point` + systemPrompt 可压缩区间提示 + 状态缓存;427 会话数据佐证旧工具 0 调用)+ BUG-005/BUG-006 小 bug;npm latest 待本次发布。
146
+ - ✅ 0.3.5 补丁:修复「无活 agent 时压缩按钮误禁 + 文案误导」(state 增加 `compactRangeReason='no_agent'`;客户端提示「会话未激活:发一条消息唤醒 agent 后可压 N 条」)。
146
147
  - ✅ 真实压缩 e2e:`test/e2e/real-compact.mjs`(真实模型 + 真实压缩事务 + `maxSummaries=1` 合并旧摘要分支)6 项断言通过。
147
148
  - ✅ P3-01~14(13 修/1 确认无需修)+ BUG-004 + P2-T1 已收口。
148
149
  - ⏳ 市场收录 PR:仓库满 1 天(2026-10-21 19:09 后)提,yml 与说明已备。
@@ -66,10 +66,15 @@ export async function readState(deps, { sessionId, agent } = {}) {
66
66
  const advice = adviceFor({ pressure: measured.tokens, summaries, thresholds: thresholdLines });
67
67
 
68
68
  // 当前能不能精压(菜单里显示「可压 N 条 / 没有可压范围」,点击前就有明确反馈)。
69
- // 只对活着的 agent 算;passivized 的会话没有 agent,点了也压不了,直接 null。
69
+ //
70
+ // 0.3.5(外部用户报的「压缩按钮灰置」):有 live session、但还没有活 agent
71
+ // (target 是 passivized 的 live session)时也要算范围 —— selectCompactableRange
72
+ // 只需要 session/nodes/engine/cfg,是纯显示信息;真实执行仍要求活 agent(preview
73
+ // 需要 agent 去跑选段/事务)。否则会把「会话未激活」误显示成「没有可压缩内容」。
74
+ const hasLiveAgent = picked !== undefined && picked !== null;
70
75
  let compactRange = null;
71
- if (picked !== undefined && picked !== null) {
72
- const live = picked.session ?? null;
76
+ if (target !== null) {
77
+ const live = target.session ?? null;
73
78
  if (live !== null) {
74
79
  compactRange = selectCompactableRange({
75
80
  session: live,
@@ -84,6 +89,9 @@ export async function readState(deps, { sessionId, agent } = {}) {
84
89
  : { nodes: compactRange.shadowedSeqs.length, tokens: compactRange.tokenCount, startSeq: compactRange.startSeq, endSeq: compactRange.endSeq };
85
90
  }
86
91
  }
92
+ // 范围算出来了但没有活 agent:客户端据此区分「会话未激活(发一条消息唤醒 agent)」
93
+ // 和「真的没有可压缩内容」。additive 字段,不破坏既有 HTTP 契约。
94
+ const compactRangeReason = compactRange !== null && !hasLiveAgent ? 'no_agent' : null;
87
95
 
88
96
  // M6:钉住集合(菜单显示「清除钉住(N 条)」,也能在无 agent 时读 live session)。
89
97
  const pinnedSeqs = target === null ? [] : livePinnedSeqs(target.session);
@@ -119,6 +127,8 @@ export async function readState(deps, { sessionId, agent } = {}) {
119
127
  level: advice === 'none' ? 'idle' : advice,
120
128
  pins: { count: pinnedSeqs.length, seqs: pinnedSeqs.slice(-20), marks: pinMarks },
121
129
  compactRange,
130
+ // 0.3.5:compactRange 非 null 但无活 agent 时为 'no_agent',其它情况 null。
131
+ compactRangeReason,
122
132
  busy: deps.lock.isBusy(target?.id),
123
133
  thresholds: thresholdLines,
124
134
  // A8:两套派生色板由 host 算好下发,浏览器半只按明暗挑一套(见 core/colors.js)。
package/lib/client.js CHANGED
@@ -1014,6 +1014,9 @@ window.__ModuleLoader__.load({
1014
1014
  startSeq: data.compactRange.startSeq ?? null,
1015
1015
  endSeq: data.compactRange.endSeq ?? null,
1016
1016
  },
1017
+ // 0.3.5:范围存在但会话没有活 agent —— 菜单据此显示「会话未激活…」而不是
1018
+ // 「暂无可压缩内容」(applyState 只保留白名单字段,新字段必须显式透传)。
1019
+ compactRangeReason: data.compactRangeReason === 'no_agent' ? 'no_agent' : null,
1017
1020
  });
1018
1021
  }, []);
1019
1022
 
@@ -1855,7 +1858,8 @@ window.__ModuleLoader__.load({
1855
1858
  role: 'menuitem',
1856
1859
  'data-cr-item': action,
1857
1860
  disabled,
1858
- title: oneLine ? (meta.note ?? sub) : undefined,
1861
+ // 禁用态的两行条目也把说明挂到 title:鼠标悬停能读到完整原因(含数字)。
1862
+ title: meta.title ?? (oneLine || disabled ? (meta.note ?? sub) : undefined),
1859
1863
  onClick: () => {
1860
1864
  if (disabled) return;
1861
1865
  // M6:压缩项先走预览(meta.onClick),其余动作直接执行。
@@ -1912,6 +1916,12 @@ window.__ModuleLoader__.load({
1912
1916
 
1913
1917
  // undefined=宿主没上报(老版本/未知);null=明确没有可压范围;object=可压多少。
1914
1918
  const rangeInfo = state.compactRange;
1919
+ // 0.3.5:有可压范围、但会话还没有活 agent(passivized live session)——preview 需要
1920
+ // 活 agent,所以按钮仍禁用,但文案要说清「发一条消息唤醒 agent」,不能再报「暂无可压缩内容」。
1921
+ const passiveRangeNote =
1922
+ rangeInfo !== null && rangeInfo !== undefined && state.compactRangeReason === 'no_agent'
1923
+ ? `会话未激活:发一条消息唤醒 agent 后可压 ${rangeInfo.nodes} 条 · 约 ${fmt(rangeInfo.tokens)} tokens`
1924
+ : null;
1915
1925
  const panel = open
1916
1926
  ? h(
1917
1927
  'div',
@@ -1953,9 +1963,11 @@ window.__ModuleLoader__.load({
1953
1963
  ? `暂无可压内容:有 ${pins.count} 条消息被锁定保护(先点「解锁消息」)`
1954
1964
  : '暂无可压缩内容(会话太短,或近期会话需保留原文)',
1955
1965
  }
1956
- : rangeInfo !== undefined
1957
- ? { note: `可压 ${rangeInfo.nodes} 条 · 约 ${fmt(rangeInfo.tokens)} tokens · 点击先看压缩预估` }
1958
- : { note: '点击先看压缩预估(范围/容量)' }),
1966
+ : passiveRangeNote !== null
1967
+ ? { disabled: true, title: passiveRangeNote, note: passiveRangeNote }
1968
+ : rangeInfo !== undefined
1969
+ ? { note: `可压 ${rangeInfo.nodes} 条 · 约 ${fmt(rangeInfo.tokens)} tokens · 点击先看压缩预估` }
1970
+ : { note: '点击先看压缩预估(范围/容量)' }),
1959
1971
  onClick: () => {
1960
1972
  void startPreview();
1961
1973
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-compact-relay",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "DeepSeek Harness 上下文指示器插件:提供容量监控、压缩预览与确认、九段式交接单生成及消息锁定功能。 · Context indicator for DSH: preview-then-confirm compaction, 9-section session handoff, and pinned messages.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -53,7 +53,7 @@
53
53
  "node": ">=22"
54
54
  },
55
55
  "scripts": {
56
- "test": "node scripts/build-client.mjs --check && node --check lib/client.js && node test/smoke.mjs && node test/handoff.mjs && node test/plugin-load.mjs && node test/contract.mjs && node test/compact-log.mjs && node test/compress-cue.mjs && node test/markdown-lite.mjs",
56
+ "test": "node scripts/build-client.mjs --check && node --check lib/client.js && node test/smoke.mjs && node test/handoff.mjs && node test/plugin-load.mjs && node test/contract.mjs && node test/compact-log.mjs && node test/compress-cue.mjs && node test/state-passive.mjs && node test/markdown-lite.mjs",
57
57
  "test:e2e": "node test/e2e/smoke.mjs",
58
58
  "test:e2e:settings": "node test/e2e/settings-ui.mjs",
59
59
  "test:e2e:compact": "node test/e2e/real-compact.mjs"