@marktrue/dsh-mobile-remote 3.2.1-rc.1 → 3.2.2-alpha.1
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 +405 -17
- package/docs/00-/345/274/200/345/217/221/346/200/273/347/272/262.md +4 -1
- package/docs/01-PRD.md +1 -1
- package/docs/02-architecture.md +2 -2
- package/docs/03-api.md +146 -32
- package/docs/04-security.md +9 -5
- package/docs/05-test-cases.md +58 -18
- package/docs/06-install-run.md +64 -0
- package/docs/07-user-manual.md +2 -1
- package/docs/09-compatibility.md +60 -32
- package/docs/10-release.md +3 -1
- package/docs/spec-app-auto-update.md +143 -0
- package/lib/index.js +271 -142
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v3.2.
|
|
3
|
+
## v3.2.2-alpha.1(build 26,issue #39 + upstream v3.2.2)— NPM-only 自动更新 + 上游 v3.2.2 并入
|
|
4
4
|
|
|
5
|
-
> 插件 `3.2.
|
|
5
|
+
> 插件 `3.2.2-alpha.1` / App `3.2.2+26` / 载体 `3.2.2-alpha.1-app`。本 fork 的独立预发布线;仅发布到本地 registry 做本机验收,不触发公共 npm 发布或 tag。
|
|
6
|
+
|
|
7
|
+
### 随上游并入的改动(main v3.2.2 基线,`09dd2934`)
|
|
8
|
+
|
|
9
|
+
本分支基于 upstream/main 的 v3.2.2 发布提交,以下上游已交付内容一并保留:
|
|
10
|
+
|
|
11
|
+
#### 审批兜底(真机验收修复)
|
|
12
|
+
|
|
13
|
+
- 下游返回 `unavailable` 不再抢先应答:仅在桌面给出**真实答复**时才收手机卡;下游 unavailable 时保留手机条目,等 `/respond` 或手机侧 fail-close 超时给出最终结果。
|
|
14
|
+
- 回归覆盖:下游立即 unavailable 时手机仍可作答,且结果以手机为准。
|
|
15
|
+
|
|
16
|
+
#### 对话轮次导航(PR #42)
|
|
17
|
+
|
|
18
|
+
- 一期:对话页右侧刻度轨按轮次跳转;长会话定位修复(尺寸缓存、有符号估算、尝试次数上界、尾部安全网)。
|
|
19
|
+
- 二期:接入宿主 `turnOutline` 投影,未加载轮次以短淡刻度显示,点它按 200 条/页有界跨页加载后定位;用户主动滚动即取消,四种终止结果均有明确说明。
|
|
20
|
+
- 新增只读端点 `GET /m/api/turn-outline?sessionId=`:四态(`available` / `empty` / `capability-missing` / `read-failed`)+ 稳定错误码、5 秒有界等待、冷折叠串行(并发 1)+ 有界队列(8)、按体积 256 KB 截断并显式标 `truncated`。
|
|
21
|
+
- 能力位 `capabilities.turnOutline` 按宿主是否真的挂载投影判定;旧插件/旧 App 双方都能降级到既有行为;长会话跨页跳转的限制如实标注。
|
|
22
|
+
|
|
23
|
+
#### App 在线本地通知(#46)
|
|
24
|
+
|
|
25
|
+
- SSE 在线且 App **不在前台**时,`approval/requested` 与 `question/requested` 直接弹系统本地通知(Android 13+ 首次启动请求通知权限);点通知直达该会话的待办卡。
|
|
26
|
+
- 同一 `rpcId` 5 分钟内只提醒一次(SSE 重连/回放会重放未结算帧);回到前台自动清掉系统通知;`pushUrls` 退为「App 被杀/离线」时的兜底。
|
|
27
|
+
- Android 构建开启 core library desugaring(`desugar_jdk_libs 2.1.5`),满足通知库要求。
|
|
28
|
+
|
|
29
|
+
#### 二维码地址优选(#49)
|
|
30
|
+
|
|
31
|
+
- 新增纯函数 `orderQrAddresses`:默认仍是「局域网私有地址优先」;**仅当机器上没有任何 `10./192.168.x/172.16-31` 地址时**,才把 Tailscale CGNAT(`100.64/10`)提到最前。
|
|
32
|
+
- 7 项回归覆盖排序与端到端载荷选择;`docs/03-api.md` 同步。
|
|
6
33
|
|
|
7
34
|
### 更新源与安全
|
|
8
35
|
|
|
@@ -21,27 +48,17 @@
|
|
|
21
48
|
- 历史失败/未确认事务不再阻塞 App 更新;APK 按 sha 复用,安装未完成给出可执行指引。
|
|
22
49
|
- 桌面「连接移动端」同步显示阶段文本与最新输出。
|
|
23
50
|
|
|
24
|
-
###
|
|
25
|
-
|
|
26
|
-
- Windows:npm/pnpm 经 shell 调用,缺失客户端给出稳定原因;桌面原生自更新仍受 `restart-unsupported` 限制(Linux/WSL 宿主可完成自更新)。
|
|
27
|
-
|
|
28
|
-
## v3.2.1-alpha.3(2026-10-26)— Android release 签名密钥迁移
|
|
29
|
-
|
|
30
|
-
> 插件 `3.2.1-alpha.3` / App `3.2.1+25` / 载体 `3.2.1-alpha.3-app`。插件更新 `alpha` dist-tag;`latest` 保持在 alpha1。
|
|
51
|
+
### 其他随分支并入
|
|
31
52
|
|
|
32
|
-
-
|
|
33
|
-
- 签名证书与 alpha1/alpha2 不同:安装 alpha3 前必须卸载旧 App 后重装;卸载可能清除本机 App 数据。
|
|
53
|
+
- Git 标签页设置顺序与 SSE 取消回归覆盖补齐。
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
> 插件 `3.2.1-alpha.2` / App `3.2.1+24` / 载体 `3.2.1-alpha.2-app`。插件更新 `alpha` dist-tag;`latest` 保持在 alpha1。
|
|
55
|
+
### 平台
|
|
38
56
|
|
|
39
|
-
-
|
|
40
|
-
- App 未变,carrier 复用 alpha1 的已发布 APK(`3.2.1+24`),仅更新插件配对信息。
|
|
57
|
+
- Windows:npm/pnpm 经 shell 调用,缺失客户端给出稳定原因;桌面原生自更新仍受 `restart-unsupported` 限制(Linux/WSL 宿主可完成自更新)。
|
|
41
58
|
|
|
42
59
|
## v3.2.1-alpha.1(2026-10-24)— Desktop 连接、版本偏斜与 npm 载体预发布
|
|
43
60
|
|
|
44
|
-
> 插件 `3.2.1-alpha.1` / App `3.2.1+24` / 载体 `3.2.1-alpha.1-app`。主插件发布到 npm `alpha` dist-tag
|
|
61
|
+
> 插件 `3.2.1-alpha.1` / App `3.2.1+24` / 载体 `3.2.1-alpha.1-app`。主插件发布到 npm `alpha` dist-tag;首发后显式将 `latest` 指向 alpha.1,后续预发布不自动移动 `latest`。
|
|
45
62
|
|
|
46
63
|
- 桌面 DSH 未配置时按可信桌面形态自动启用 LAN 桥,默认更新目录可用;桥端点只公告真实可达地址。
|
|
47
64
|
- 补齐 DSH 0.2.0/0.2.1 宿主能力探测与 Peer 兼容,失配时明确诊断。
|
|
@@ -49,6 +66,271 @@
|
|
|
49
66
|
- App 提供轮次导航与轮次大纲,并完善与插件版本偏斜时的更新/接续处理。
|
|
50
67
|
- 发布链包含 App carrier、配对清单及 npm-drill 预演工具。
|
|
51
68
|
|
|
69
|
+
## v3.2.0(build 58,本机候选构建,未公开发布)— 桌面形态适配与发版演练
|
|
70
|
+
|
|
71
|
+
> 本机验收候选:插件语义版本 `3.2.0` / App `3.2.0+58`。仅用于本机与真机验证,**未向公共 npm/GitHub 发布**,不代表正式 release。
|
|
72
|
+
|
|
73
|
+
### 插件:#36 桌面形态 S1 + #37 发版演练
|
|
74
|
+
|
|
75
|
+
- 桌面形态未显式配置 `lanBridge` 时自动开启局域网桥:优先手机可达的私有 IPv4、过滤常见虚拟网卡、端口自动选取并跨重启持久化;显式配置仍优先。
|
|
76
|
+
- 未配置 `updateDir` 时默认使用 `~/.dsh/mobile-remote/update`,启动自动创建并校验可写。
|
|
77
|
+
- 新增本地 npm registry 发版演练(插件/载体安装与更新、失败路径),正式发版前可在不触碰公共 npm 的情况下验证完整链路。
|
|
78
|
+
|
|
79
|
+
### App
|
|
80
|
+
|
|
81
|
+
- 本机候选只提高 Android `versionCode` 到 `58`,App 功能代码未变。
|
|
82
|
+
|
|
83
|
+
### 验证
|
|
84
|
+
|
|
85
|
+
- develop 合并后 Node 全量 540 tests(536 pass / 0 fail / 4 opt-in skipped);App analyze/test 门禁通过。
|
|
86
|
+
- 本机发布演练 20/20 断言通过;真机已用此前的 +57 完成核心链路,本 +58 候选待本机升级验证。
|
|
87
|
+
|
|
88
|
+
## v3.2.0(build 49,issues #32/#33)— 自更新链路加固与 Git 标签排序修复
|
|
89
|
+
|
|
90
|
+
> 版本:插件 `3.2.0` / App `3.2.0+49`。本版两端都改:安装新 APK 之外,还需更新插件并重启宿主,应用 #32 自更新与打包链路的后续修正。
|
|
91
|
+
|
|
92
|
+
### 插件:#32 自更新与打包后续修正
|
|
93
|
+
|
|
94
|
+
- 修正 bootstrap 中重复的插件条目覆盖,保留插件内容标识;加固自更新事务与并发锁处理。
|
|
95
|
+
- 依赖键与实际 scoped package 名对齐,修正 npm scope,并补齐 `dsh.bundle` 声明。
|
|
96
|
+
- 发布脚本按 `npm pack` 实际产物名归档;重启后自检不再吞掉失败。
|
|
97
|
+
|
|
98
|
+
### App:Git 标签页设置顺序显示(#33)
|
|
99
|
+
|
|
100
|
+
- 设置弹窗的已选标签行即时按上移/下移后的顺序显示;未选标签仍可选,并按默认顺序排在后面。
|
|
101
|
+
- 保存后重新加载本地偏好并重开弹窗,实际行顺序与已保存顺序一致。
|
|
102
|
+
|
|
103
|
+
### 验证
|
|
104
|
+
|
|
105
|
+
- Flutter 全量测试 592 项通过;develop 集成门禁 5/5 通过。
|
|
106
|
+
- ⚠ 真机验收待完成。
|
|
107
|
+
|
|
108
|
+
## v3.2.0(build 48,issue #32)— 两端版本偏斜的兑现机制
|
|
109
|
+
|
|
110
|
+
> 版本:插件 `3.2.0` / App `3.2.0+48`。本版**两端都改了**:装新 APK 之外,还需同步插件副本并重启宿主,否则新端点在旧插件上不存在(App 会明确提示而不是静默失败)。
|
|
111
|
+
> 内容 = #32(ADR 0019):把 README 早已承诺的「任意组合可用、协议只加不删」从政策变成机制。
|
|
112
|
+
|
|
113
|
+
### 三条判据各司其职(#32)
|
|
114
|
+
|
|
115
|
+
- **能力能不能用**看能力声明;**要不要下载新版本**看发布清单里的**内容标识**(`contentSha256`);**要不要提示对齐**看版本号(只决定文案)。
|
|
116
|
+
- 新增判据解决一个实测盲区:上游 `v3.2.0` 与 develop 的插件**版本号都是 3.2.0、内容却不同**——用版本号判「是否已最新」永远看不见这类差异。
|
|
117
|
+
|
|
118
|
+
### 插件自更新:手机可直接触发,含无人值守回滚(#32)
|
|
119
|
+
|
|
120
|
+
- 手机端触发后走完整链路:下载 → 校验(字节哈希 + 内容标识)→ 解包复核 → 快照当前版本 → 原子落位 → 切依赖 → `pnpm install` → 重启宿主。
|
|
121
|
+
- **失败自动回滚一次**:由**外部监督器**在宿主之外确认新实例健康(按"正在运行的内容标识"判定),不健康就用快照恢复旧字节并再重启一次——监督器不依赖新版插件能否加载,因此新版起不来也能救回。
|
|
122
|
+
- **重启断线是正常环节**:手机端持久化"更新进行中"并在重连后接续,不把断线当失败。
|
|
123
|
+
- 不能自更新的形态(如 Desktop)明确降级为**降级指引**:按实际安装方式给一条可复制的升级命令,不诱导点"一键更新"。
|
|
124
|
+
|
|
125
|
+
### App 侧对齐与编排(#32)
|
|
126
|
+
|
|
127
|
+
- 两端不一致时给**温和提示**(PC 端优先,手机端首页横幅/设置页尾注),不阻断使用。
|
|
128
|
+
- **插件先行**:App 的更新入口在插件未对齐时先引导更新插件;固定同一份发布清单的产物身份(URL/大小/哈希),不会因为改更新源或上游发新版而"跨版本拼接"。
|
|
129
|
+
- 安装器拉起不等于装上:只有本机版本/build 与固定目标一致才收尾。
|
|
130
|
+
|
|
131
|
+
### 发布链(#32)
|
|
132
|
+
|
|
133
|
+
- 发布清单 schema 1 同时描述两端产物(App 从主机源取 APK、插件从同一份清单取 tgz);发布脚本产出后**自动校验**,不一致即中止。
|
|
134
|
+
- 插件 tgz 自包含运行依赖(`bundleDependencies`),离线/覆盖安装不会缺依赖。
|
|
135
|
+
|
|
136
|
+
### 验证
|
|
137
|
+
|
|
138
|
+
- develop 集成门禁 **5/5 全绿**(`flutter-analyze` 0 issue、`flutter-test` **+590 全绿**、`timeline-contract`、`account-usage`、`kotlin-usage-panel`)。
|
|
139
|
+
- 六轮代码复核(C1–C9 / W1–W5 / D1–D5 / E1–E3 / F1)逐项修复并留下隔离回归;Node 侧 338 项、App 侧含真实 Store+假 HTTP 的编排回归。
|
|
140
|
+
- ⚠ **真实端到端尚未验证**:真实下载、`pnpm install`、宿主重启、故障注入回滚与真机安装留待本次真机测试确认。
|
|
141
|
+
|
|
142
|
+
## v3.2.0(build 47,issue #31)— 长会话里轮次导航定位失败修复
|
|
143
|
+
|
|
144
|
+
> 版本:插件 `3.2.0` / App `3.2.0+47`。本版**只改 App**(未改 `lib/index.js`):安装新 APK 即可,无需同步插件副本或重启宿主。
|
|
145
|
+
> 内容 = #31(长会话里点刻度轨早期轮次报「未能定位到第 N 轮:多次尝试后仍未进入视图」)。真机会话"轮数少、条目多"(如 10 轮 / 约 3000 条工具与消息)是常态,第 2 轮离底部约 2900 个条目。
|
|
146
|
+
|
|
147
|
+
### 修复:长会话里跳不到早期轮次(#31)
|
|
148
|
+
|
|
149
|
+
- **跳转定位改为"查表 + 校正"**:新增**条目尺寸缓存**(按稳定 key 记录已构建条目的实测高度),并据此估算"内容索引 → 偏移"(宿主 Dashboard 虚拟化列表 `getOffsetForIndex` 的等价物)。长跳从"盲二分十几次"降到**一步到几步**:3000 条目的真实分页会话里,冷跳 5 个落点、热跳 **2 个落点**即进入目标轮。
|
|
150
|
+
- **估算用 center 相对的有符号坐标**:此前按"从最早条目累加的非负前缀"估算,与 `CustomScrollView.center` 的实际坐标系(更早历史在**负坐标**)整体平移,估算永远通不过实测区间判据;现在用 `prefix(目标) − prefix(center)`,并归一化到布局给出的真实 extent(缓存只影响相对权重)。
|
|
151
|
+
- **搜索界按实测持久、布局估计每轮重读**:`minScrollExtent()` 只是懒布局的动态估计,真实分页把更早历史 prepend 进来后它会向负方向大幅扩展;把它当成"永久实测下界"会让区间冻结在错误位置(目标约 −215000,冻结下界却停在 −10 附近)。现在只持久化**实测**界(索引更小者的底部 / 更大者的顶部),布局估计每轮重读。
|
|
152
|
+
- **有界性与失败说明**:定位上界改为**尝试次数**(24),墙钟只作 20 秒绝对安全网——固定墙钟会在大量 prepend 后把慢帧误判成停滞、在**正在收敛途中**误报失败;每次落点后允许几帧布局稳定再判定可见性;安全网到时后不再滚动或精调。`notInWindow` / `exhausted` 的区分与"不可达时明确说明原因"保持不变。
|
|
153
|
+
- 点未加载刻度仍按 200 条/页跨页加载直到覆盖该轮起始序号;翻页期间该齿脉冲,用户主动滚动即取消(未变)。
|
|
154
|
+
|
|
155
|
+
### 验证
|
|
156
|
+
|
|
157
|
+
- develop 集成门禁 **5/5 全绿**(`flutter-analyze` 0 issue、`flutter-test` **+533 全绿**、`timeline-contract` 125 PASS、`account-usage`、`kotlin-usage-panel`)。
|
|
158
|
+
- 评审侧独立复跑:严格"初始 50 条 / before 每页 ≤200"的 1000 轮 / 3000 条会话,冷跳 5 个落点、热跳 2 个落点,均与目标轮相交;尾部安全网反例(跨过 20 秒上限不得再精调)通过。
|
|
159
|
+
- 新增回归:真实分页后端下的冷/热长跳、真机形状(10 轮 × ~250 条目)中段目标、尺寸前缀纯函数 6 例、尾部安全网 1 例。
|
|
160
|
+
|
|
161
|
+
## v3.2.0(build 46,issue #19 / #21 / #30)— 宿主 0.2.0 兼容:4 处静默失效 + 子代理列表 / Codex 余额
|
|
162
|
+
|
|
163
|
+
> 版本:插件 `3.2.0` / App `3.2.0+46`。本版**改动了插件**(`lib/index.js`)——除安装新 APK,**必须同步插件副本并重启宿主**才会生效。
|
|
164
|
+
> 内容 = #19(适配 DSH 0.2.0 的四处宿主接口变更,并把能力漂移显式化)、#21(子代理列表与 Codex 余额在 0.2.0 下失效)、#30(上游化交付的 4 项审查修复)。App 侧代码未变,build 号用于与插件版本对齐并提供更新入口。
|
|
165
|
+
|
|
166
|
+
### 修复:宿主 0.2.0 下四处**静默失效**(#19)
|
|
167
|
+
|
|
168
|
+
宿主升级后这四处**都不报错**,只是"看起来正常、实际没反应":
|
|
169
|
+
|
|
170
|
+
- **后台任务**:`jobs.list/kill` 的 caller 形状变了(Agent 对象 → SessionId 字符串)。传错不报错——列表恒为空、终止报"任务属于另一个会话"。现按代际给形状。
|
|
171
|
+
- **任务事件**:两个回调 `onJobsChanged`/`onJobDone` 被统一的 `events.subscribe` 取代,现两代各走一条路径。
|
|
172
|
+
- **设置读取**:`settings.get(ns)` 被移除,改由 `describe()` 返回描述符数组;两处调用点收敛为跨代读取。
|
|
173
|
+
- **双端审批通道**:`openWireStream` 的取消信号从第 3 位挪到第 5 位,传错位会让 `approvalMode: both` 的 `$events` 通道**永远不就绪**。
|
|
174
|
+
- 另:`$events` 断流改为**退避重连**(3s 起、上限 60s、仅卸载停止;就绪过即单向置位);删除整车 `apiProxy` 死代码;`/m/api/diagnostics` 新增宿主能力**三态**报告(`ok`/`drift`/`missing`)与实际代际路径。
|
|
175
|
+
|
|
176
|
+
### 修复:子代理列表与 Codex 余额(#21)
|
|
177
|
+
|
|
178
|
+
- **「会话工具 → 子代理」打不开**:宿主 0.2.0 删除了 `subagents/list` Remote 端点。现改为三级目录来源:宿主持久目录(含**已释放**的子代理)→ 持久化枚举(父会话休眠/归档时入口不消失)→ 会话注册表兜底(标 `catalogDegraded`,**不让不完整列表冒充完整目录**)。
|
|
179
|
+
- **手机看不到 Codex 余额**(而桌面网页端正常):0.2.0 移除 `settings.get()` 后,代理配置被**误判为"未启用"**而静默改走直连、最终超时。现区分三态——用户没开代理 / 代理可用 / **读不到宿主设置**(显式失败);失败详情只回稳定错误码与固定文案,**不回传异常原文**(凭据可能内嵌在异常消息里)。
|
|
180
|
+
|
|
181
|
+
### 审查修复(#30)
|
|
182
|
+
|
|
183
|
+
- 目录条目的 `label` 可省略:**已释放**的子代理现在会补读持久标题,不再退化成短 ID。
|
|
184
|
+
- 目录 `mode: "unknown"` 的不受支持条目保留 `diagnostic/unsupported` 语义,不再伪装成普通闲置子代理。
|
|
185
|
+
- `/m/api/diagnostics` 的 `checks.hostCapabilities["settings.read"]` 与真实读取**共享判定**,并新增 `checks.hostCapabilityReasons` 原因码——读取已经失败时诊断不再报 `ok`。
|
|
186
|
+
- HTTP 429 限流与登录失效不再被误报为"网络不可达";只接受 allow-list 的错误码与**校验过的**状态码。
|
|
187
|
+
|
|
188
|
+
### 兼容与安装
|
|
189
|
+
|
|
190
|
+
- **peer 依赖声明 `>=0.1.0-rc.6 <0.3.0`**:宿主用 `semver.satisfies(runtimeVersion, range, { includePrerelease: true })` 判定,该范围覆盖 `0.1.x`、`0.2.0-rc.*` 与 `0.2.x` 正式版(原 `<0.2.0` 到 `0.2.0` 正式版会被判不兼容)。上界只声明可安装边界,功能路径仍按能力探测。
|
|
191
|
+
- `0.1.x` / `0.2.x` 两代宿主 API 都支持,**不按宿主版本号硬拦截**。
|
|
192
|
+
|
|
193
|
+
### 门禁(2026-10-10)
|
|
194
|
+
|
|
195
|
+
- develop 集成门禁 **5/5 全绿**(`flutter-analyze` / `flutter-test` / `timeline-contract` / `account-usage` / `kotlin-usage-panel`);全量 node 测试 **207/207 PASS**;`node --check lib/index.js` 通过。
|
|
196
|
+
- 验证范围如实标注:只对 **`0.2.x` 真实宿主**做过端到端验证;`0.1.x` 路径由两代假宿主夹具保护(真实宿主未验证)。
|
|
197
|
+
|
|
198
|
+
## v3.2.0(build 45,issue #24 / #25 / #28)— 对话轮次导航(一期+二期)+ 预热 run 级硬截止
|
|
199
|
+
|
|
200
|
+
> 版本:插件 `3.2.0` / App `3.2.0+45`。本版**改动了插件**(`lib/index.js`)——除安装新 APK,**必须同步插件副本并重启宿主**才会生效。
|
|
201
|
+
> 内容 = issue #28(预热 run 级硬截止,提交 `969bde6` + `e17d2c8`)、#24(轮次导航一期,merge `6711f63`)、#25(二期:宿主轮次大纲端点到刻度轨,merge `d93cf98`)。
|
|
202
|
+
|
|
203
|
+
### 新增:对话轮次导航(#24 一期 + #25 二期)
|
|
204
|
+
|
|
205
|
+
长会话里按轮次定位:对话页右侧悬浮一条**刻度轨**,每轮一个刻度。
|
|
206
|
+
|
|
207
|
+
- 默认极细半透明;**上翻离开底部才显形**,与「回到底部」圆钮同进同出;少于 2 轮不渲染(一轮没有导航价值)。
|
|
208
|
+
- **点按刻度直接跳转**;沿轨竖直拖动 = **扫掠轮次**(拖动过程出预览、松手落在所指那一轮)。超长轨道在上下沿会**自动滚动**,能一路扫到底,不再有"看不见也点不到"的刻度。
|
|
209
|
+
- 预览显示该轮**提示词**(1 行)与**回复摘要**(至多 3 行);提示词为空(纯图片/纯命令轮)时回退「第 N 轮」;非真人注入消息不参与预览。
|
|
210
|
+
- 定位是**有界迭代 + 实测几何校正**:懒构建的列表、条目高度不均(长回复)也能收敛;目标不可达或多次尝试仍失败会**明确说明原因**,不静默停下。
|
|
211
|
+
- **二期把宿主轮次大纲接到手机**:插件新增只读端点 `GET /m/api/turn-outline?sessionId=`,`/bootstrap` 与 SSE hello 增加 `turnOutline` 能力位(宿主真的挂了该投影才算支持)。刻度轨从此是**整个会话的完整阶梯**:已加载轮次正常显示,未加载轮次以**短淡刻度**区分。
|
|
212
|
+
- 点未加载刻度会**按 200 条/页跨页加载**直到覆盖该轮起始序号再定位(不改动既有上翻的 30 条/页);翻页期间该齿脉冲,**用户主动滚动即取消**。
|
|
213
|
+
- 大纲获取失败按**四态**分别说明:能力缺失 / 该会话暂时没有大纲 / 阶梯被截断(更早轮次需上翻)/ 读取失败或超时——**空数组不再被当成"没有轮次"**,"不支持"与"该会话没有大纲"也给出不同说法。
|
|
214
|
+
|
|
215
|
+
### 修复:冷启动预热改为 run 级硬截止(#28)
|
|
216
|
+
|
|
217
|
+
预热寿命若被旧 timer 反复收紧会失效——现在收紧时必须先清旧 timer,并把预热寿命提到 run 级硬截止。
|
|
218
|
+
|
|
219
|
+
### 服务端(插件)要点
|
|
220
|
+
|
|
221
|
+
- 新端点复用既有路由分派 / 鉴权 / Host 校验 / `sendJson` 约定;**只读**,不改既有路由语义。
|
|
222
|
+
- 冷折叠**有界等待 5 秒**(从请求到达起算、含排队时间),队列有界(8)且并发 1;超时或客户端断开都回**明确降级**,真正未结束的观察继续占住执行槽、迟到 lease 释放,**断开后不再向已销毁的响应写入**。
|
|
223
|
+
|
|
224
|
+
### 门禁(2026-10-09)
|
|
225
|
+
|
|
226
|
+
- develop 集成门禁 **5/5 全绿**:`flutter-analyze` 0 issue、`flutter-test` **518 项全绿**、`timeline-contract` **125 PASS**、`account-usage` 15/15、`kotlin-usage-panel` PASS。
|
|
227
|
+
- 评审侧:三轮评审的全部反例与探针均已转绿(服务端隔离探针 **39 PASS / 0 FAIL**)。
|
|
228
|
+
|
|
229
|
+
## v3.2.0(build 44,issue #27)— 冷启动首次 /sessions 不再 504:枚举与标题预算解耦
|
|
230
|
+
|
|
231
|
+
> 版本:插件 `3.2.0` / App `3.2.0+44`。本版**改动了插件**(`lib/index.js`)——除安装新 APK,**必须同步插件副本并重启宿主**才会生效。
|
|
232
|
+
> 内容 = issue #27 的修复(提交 `58e0a0f` + `9c0cb78`,merge `8770bf5` / `d5dba5b` @ develop)。
|
|
233
|
+
|
|
234
|
+
### 问题(issue #27,`+43` 部署后实测)
|
|
235
|
+
|
|
236
|
+
宿主重启后最初三次 `/m/api/sessions` 返回 **504 `sessions-timeout`**(1.37–1.47 秒、28 字节),而从第二分钟起为 `200` / 1.37 秒(386 个会话、386 个真实标题);对照部署前是 `200` / **82.45 秒**。即把「永远很慢」修成了「稳态很快」,但**冷启动首次请求从「慢但成功」退化成了「快但失败」**。
|
|
237
|
+
|
|
238
|
+
根因:`listSessionsWithinTitleBudget` 把**枚举本身**(`query.listSessions`)也放进了**标题折叠的 1.5 秒预算**。宿主刚起来时内核语料是冷的(note 793 实测全量 `persistence.stat()` 约 22 秒),枚举必然超过 1.5 秒 → `{timedOut:true}` → 路由 `504`。1.5 秒预算的意图是限制**可延后的标题折叠**,不是核心枚举。
|
|
239
|
+
|
|
240
|
+
### 修法
|
|
241
|
+
|
|
242
|
+
- **枚举与标题预算解耦**:新增 `Config.enumerationBudgetMs`(默认 `DEFAULT_ENUMERATION_BUDGET_MS`)作为枚举自己的预算;标题折叠继续 ≤1.5 秒(超预算的会话先用短码兜底、随后后台有界预热)。
|
|
243
|
+
- **默认 12 秒——先于客户端超时给出结论**:App 对 `/sessions` 用的是 `getJson` 的默认超时 **15 秒**(`dsh-mobile-app/lib/api.dart`)。若服务端预算更大,冷首轮落在 15–30 秒之间会出现「服务端最终 200、客户端已经先放弃」——用户既拿不到列表、也拿不到明确失败,服务端还在为一个没人等的请求继续烧 CPU。12 秒 = 15 秒 − 3 秒余量(网络往返 + ~110KB JSON 序列化)。
|
|
244
|
+
- **防御性默认**:宿主传给 `apply()` 的是**原始** config(schema 默认值不在这里生效),缺字段必须回落到常量,否则 `undefined - elapsed` 得到 NaN、`setTimeout(NaN)` 立即触发 → 冷启动被误判成超时。
|
|
245
|
+
|
|
246
|
+
### 门禁与验收证据(2026-10-09)
|
|
247
|
+
|
|
248
|
+
- 插件测试:`node --test test/*.mjs` **134/134 通过**。含新回归——枚举 1.7 秒(慢于标题预算、快于默认预算)→ **200 + N**,且标题为短码兜底(证明标题预算仍生效);该用例刻意**不传** config,同时钉住生产部署路径的防御性默认。
|
|
249
|
+
- 变异验证:把枚举预算退回标题预算 → 新回归立刻变红(`504 !== 200`),正是本 issue 报告的缺陷。
|
|
250
|
+
- 分支门禁:`flutter-analyze` / `timeline-contract` / `account-usage` / `kotlin-usage-panel` **PASS**;`flutter-test` 为 main 基线既有 3 项红灯(`sse_cancel_window_test.dart`),按基线例外放行——改动只碰插件与 Node 测试。
|
|
251
|
+
- **develop 集成门禁 5/5 全绿**(含 `flutter-test`,develop 侧已有该测试的修复):`20-integration-8770bf571bcd.md`、`20-integration-d5dba5b1eef1.md`。
|
|
252
|
+
- 维护者代码评审:note 1055「#27 代码评审通过:`58e0a0f`」,未发现 BLOCKING/WARNING。
|
|
253
|
+
|
|
254
|
+
### 仍未验(本版部署后实测)
|
|
255
|
+
|
|
256
|
+
note 1055 明确要求「部署后仍需实测真实冷首轮/稳态及 App 15s 超时与服务端预算的匹配」。本版把预算压到 12 秒后需实测:宿主重启后**首次**请求应为 `200 + N`(而非 504),且耗时 <15 秒。
|
|
257
|
+
|
|
258
|
+
## v3.2.0(build 43,issue #20)— 会话列表不再「越用越慢」:revision 缓存 + 每请求预算 + single-flight
|
|
259
|
+
|
|
260
|
+
> 版本:插件 `3.2.0` / App `3.2.0+43`。本版**改动了插件**(新增 `lib/session-title-cache.js`、`lib/session-title-refresh.js`,改 `lib/index.js`)——除了安装新 APK,**必须同步插件副本并重启宿主**才会生效。
|
|
261
|
+
> 内容 = issue #20 第 2 步在 develop 上的集成(merge `a266e76`,分支交付 SHA `b5f8afc`)。
|
|
262
|
+
|
|
263
|
+
### 问题(issue #20)
|
|
264
|
+
|
|
265
|
+
手机 App 打开就是会话列表。桌面端积累大量会话后,列表要么挂死、要么极慢:`/sessions` 在响应前**同步折叠全部休眠会话的标题**,而折叠要完整读取每个会话日志(多帧 zstd 解压 → JSON 解析 → 折叠校验)。本机 384 个会话实测冷缓存 **81–113 秒**才返回(维护者 note 702 / note 793 已量化根因:354 会话离线全量折叠 108.8 秒;`persistence.stat()` 全量 21.9 秒)。
|
|
266
|
+
|
|
267
|
+
### 第 1 步(更早的 develop 版本已落地)
|
|
268
|
+
|
|
269
|
+
客户端断开即取消**本请求**的枚举与标题折叠:`requestAbort` + 把取消信号传进宿主读取,重试不再叠加。
|
|
270
|
+
|
|
271
|
+
### 第 2 步(本版)
|
|
272
|
+
|
|
273
|
+
- **revision 失效的持久化标题缓存**:`~/.dsh/mobile-remote/session-titles.json`,`{ id: { title, revision, at } }`;revision 未变 → **零日志读取**,宿主重启后依然命中(失效键取自不读日志的 `persistence.stat()`)。
|
|
274
|
+
- **每请求时间预算(≤1.5s)+ 增量返回**:预算内只折叠新增/变更会话,其余用短码兜底并**立即返回 200**;预算耗尽时仅在客户端仍连接时转为后台有界预热。
|
|
275
|
+
- **single-flight + 折叠串行门**:并发请求复用同一个 in-flight 轮次;取消清理期间不叠加第二轮(避免读取宽度翻倍)。
|
|
276
|
+
- **有界读取**:整轮 miss **只发一次** `readTitleSnapshots`(其内部读取宽度由宿主 `persistedReadConcurrency`=4 约束,插件不再叠加 per-id 扇出);旧宿主/整批故障的逐个 `readTitleSnapshot` 兜底同样 ≤4。实测 354 会话的标题链全量枚举由 **91 次降到 3 次**且与 N 无关。
|
|
277
|
+
- **评审 note 908 BLOCKING 修复**(`b5f8afc`):`mapBounded` 用 `Promise.all` 时**首拒即返回**,会让折叠串行门在其余三路仍在清理时就被释放、重试再开四路 → 实测 `maxActive=7` 突破 ≤4 上限。改为等**全部 worker `allSettled`** 之后再重抛原失败,并在派发前查取消。
|
|
278
|
+
|
|
279
|
+
### 门禁与验收证据(2026-10-09)
|
|
280
|
+
|
|
281
|
+
- 分支门禁:`flutter-analyze` / `timeline-contract` / `account-usage` / `kotlin-usage-panel` **PASS**;`flutter-test` 在 main 基线有 3 项既有红灯(`sse_cancel_window_test.dart` 的取消窗口/对照/连续重建),按基线例外放行——本分支只改插件与 Node 测试,**未触及任何 Flutter 代码**。
|
|
282
|
+
- **develop 集成门禁 5/5 全绿**(含 `flutter-test`,develop 侧已有该测试的修复,因此无需例外):报告 `20-integration-a266e760b708.md`。
|
|
283
|
+
- 合并后 `node --test test/*.mjs` **165/165 通过**(隔离临时 HOME/DSH_HOME)。
|
|
284
|
+
- 变异验证:把 `allSettled` 退回 `Promise.all`,note 908 的两条回归**立刻变红**(重试抢跑,`dispatches=12 ≠ 4`)。
|
|
285
|
+
- 维护者代码评审:note 1041「#20 最终代码复核通过:`25a320b`」,issue 已按用户授权关闭。
|
|
286
|
+
|
|
287
|
+
### 仍未验(如实标注,勿以本版发布代替)
|
|
288
|
+
|
|
289
|
+
- **真实语料的冷首屏计时与生产复核**(note 793 验收第 1、7 条:`/m/api/sessions` ≤2s 返回 200+N、`xinfangyb` 的 4 个会话在 App 可见)——需在本次部署后实测。
|
|
290
|
+
- 79 个 seeded 会话的完整冷读失败属另一缺陷(note 788/793 建议单独跟踪)。
|
|
291
|
+
|
|
292
|
+
## v3.2.0(build 42,issue #19 / #21 / #20 / #22)— develop 首次发到上游 v3.2.0 基线
|
|
293
|
+
|
|
294
|
+
> 版本:插件 `3.2.0` / App `3.2.0+42`。本次把 develop 推到了上游 v3.2.0 基线(`5832efc` 合并 `github/main`),并带上 develop 独有的 #19 / #21 / #20 / #22 修复。
|
|
295
|
+
> **插件副本与已部署副本逐字节一致**(`diff -rq lib/ ~/.dsh/profiles/web/node_modules/dsh-mobile-remote/lib/` 为空),本轮发布**按流程重新执行一次部署与延迟重启以刷新运行中的插件**。
|
|
296
|
+
|
|
297
|
+
### 上游 v3.2.0 带来的内容(合并 `github/main`,此前不在手机版本里)
|
|
298
|
+
|
|
299
|
+
- **移动端 Git 只读浏览 + 会话文件浏览**(PR #31 含 PR #28;PR #27 收尾补正):对话操作栏新增 `git` / `files` 入口,浏览根 = 当前会话工作目录;提交详情、文件改动预览、分支图与工作区事实均为只读。
|
|
300
|
+
- **会话列表运行状态**(PR #30 覆盖 #29):运行中虚线旋转、等待态静态警示色、子代理可从父会话进入。
|
|
301
|
+
- **斜杠命令在提交时真正执行**(#25):此前 `/compact` 被当普通消息投给模型,压缩从未发生;现在命中内核命令语法且名字在命令目录里就走 `POST /m/api/commands`,不插乐观气泡、不进 `/send` 回执对账,并把结果 toast 出来。服务端 `commands.execute` 整条命令超时由 15s 放宽到 **180s**(大会话摘要远不止 15s),客户端 `runCommand` 用 200s 保证服务端先收敛。
|
|
302
|
+
- **宽表格横滑不再被消息列表抢走**(#33):把表格子树的拖拽阈值压到 4px,使横向手势按 hit-test 由最内层表格胜出;修复前"按住表格横滑"会触发 `_loadMoreInfinite()`,用户可被一路带到任意早的历史。
|
|
303
|
+
- **模型未确定时显式说明**(PR #27 复核补正):强度区域不再静默消失。
|
|
304
|
+
- **扫码地址双重挂载路径修复**(PR #32):修 `/m/m` —— LAN 桥与回环都中招。
|
|
305
|
+
- **`flutter analyze` 门禁回到 0 issue**:合并后新增的 41 项 info(39 项 `curly_braces_in_flow_control_structures` + 2 项 `use_null_aware_elements`)已用 `dart fix --apply` 机械化修回。
|
|
306
|
+
|
|
307
|
+
### develop 独有修复(上游没有,这次一并随 App 发布)
|
|
308
|
+
|
|
309
|
+
- **#19 / #21 宿主 0.2.x 兼容**:子代理列表与 Codex 余额在宿主 0.2.0 下失效——插件改为按能力探测而非按宿主版本号推断,并在缺失/漂移时给出明确原因(三分状态:缺失、语义漂移、可用)。peer 依赖范围去掉上界。
|
|
310
|
+
- **#20 请求级取消**:客户端断开即取消会话枚举与标题折叠,止住枚举放大与死队列复用;逐个标题兜底读取在断开时取消在途请求。
|
|
311
|
+
- **#22 会话列表刷新的在途守卫**:同一时刻只允许一个列表请求在飞,期间到达的刷新合并为「结束后再补一次」;被合并的刷新等到补发真正结束才返回;切换服务器地址后旧地址未完成的请求不再挡住新地址刷新;owner 收尾窗口不再留下 phantom in-flight。
|
|
312
|
+
- **轮次导航**(issue #24,ADR 0018 + `CONTEXT.md` 领域词条):对话页右侧刻度轨按轮次定位,可见轮次可跳转、未构建轮次以弱化刻度区分——本版只随仓库记录决策,**App 侧实现仍在 `feature/turn-navigation` 工作树、未进本次发布**。
|
|
313
|
+
|
|
314
|
+
### 门禁与验收证据(2026-10-08 develop)
|
|
315
|
+
|
|
316
|
+
- `flutter analyze` → **0 issue**;`flutter test` → **399 全绿**。
|
|
317
|
+
- `node --test test/*.mjs` → **132 pass / 0 fail**;`node tools/timeline-contract-check.mjs` → **77 PASS**;`node tools/account-usage-check.mjs` → **15/15**;`node tools/account-usage-adversarial-check.mjs` → **19/19**。
|
|
318
|
+
- Kotlin `UsagePanelModelTest` → **27 项全绿**(用 `:app:cleanTestDebugUnitTest` 强制重跑,核对 `dsh-mobile-app/build/app/test-results/.../TEST-*.xml` 的 mtime,避免把 `UP-TO-DATE` 缓存误判为"门禁空跑")。
|
|
319
|
+
- 构建环境:Flutter 3.47.1 / JDK 17 / Android SDK 36;`PUB_HOSTED_URL` 跟随 `pubspec.lock` 的 `https://pub.flutter-io.cn`,构建后 `pubspec.lock` 无改动(88 处源保持镜像)。
|
|
320
|
+
- 更新链路:`package-release.sh` → `verify-update-manifest.mjs` **RESULT: PASS**(size/sha256 与 APK 实算一致);`GET /m/api/update/manifest` 返回 `version=3.2.0+42`、`size=75057490`、`sha256=4db924e4…`,`GET /m/api/update/apk` 下载 75057490 字节、实算 sha256 与 manifest 一致。`aapt2 dump badging` 核对 APK 内置 `versionCode='42'` / `versionName='3.2.0'`(**> 手机已装 `+40`**,不会触发「不能降级安装」)。
|
|
321
|
+
- 宿主重启与自检:`restart-dsh-web-service.sh <pid> 90` 于 13:02:11 停止旧 pid、13:02:13 新 pid 接管、smoke OK;`tools/postrestart-check.sh` 逐项 PASS——端口由新 pid 接管、`bootstrap` capabilities(`eventTimeline` v1)、`update/manifest` 版本 = `3.2.0+42`、`session-config` 取真实会话(`deepseek-v4.1-flash` / `opencode-go-plus` / `reasoningEffort=high`)、`catalog?refresh=1`。**该脚本自带 20s 超时不适用于本机的 `/m/api/sessions`**(见下条),本次是逐端点手工复核补全的,不是脚本一次全绿。
|
|
322
|
+
|
|
323
|
+
### 观察记录:`/m/api/sessions` 在本机约需 81 秒
|
|
324
|
+
|
|
325
|
+
- 本机现有 **384 个会话**,`GET /m/api/sessions` 实测返回 200、约 110KB,但耗时 **81.2s**(`bootstrap`/`update/manifest` 均为毫秒级)——列表按会话逐条读取日志,成本随会话数线性增长。
|
|
326
|
+
- 影响:`tools/postrestart-check.sh` 的 `curl -m 20` 取不到 `sessionId`,会判 FAIL;**这是超时口径问题,不是宿主故障**(用 `-m 150` 同一端点正常返回)。手机上该列表也会长时间转圈(#22 的在途守卫保证它不再堆积请求,但单个请求仍慢)。
|
|
327
|
+
- 未在本次修改:属性能问题而非本次发布的回归(发布前后插件副本逐字节一致)。建议后续单独立 issue:给列表加缓存/分页,或让 `postrestart-check.sh` 的会话探测复用可配置超时。
|
|
328
|
+
|
|
329
|
+
### 已知未解决:issue #20(缺陷本体在上游核心)
|
|
330
|
+
|
|
331
|
+
插件侧的降级读取(`degraded/current-surface`、`configDegraded`)在 #21 已落地,本版无改动;**缺陷本体在 DSH 核心**——`dsh-session-query.readSession()` 仍走 `Session.create(...)` 快照路径而非 `Session.fromRestore`。上游已加入逃逸口(日志有 `session/end-seed` 且 `data.inherited === true` 时可跳过等长校验),因此是否复现取决于目标会话的日志内容。插件侧降级保留到核心改走 restore 构造路径。
|
|
332
|
+
|
|
333
|
+
|
|
52
334
|
## v3.2.0(2026-10-04,issue #25 / #26 / #33,PR #27 / #28 / #29 / #30 / #31 / #32)— 移动端 Git 与会话文件浏览 + 会话列表状态 + 命令与手势修复
|
|
53
335
|
|
|
54
336
|
> 版本:插件 `3.2.0` / App `3.2.0+23`。
|
|
@@ -142,6 +424,104 @@
|
|
|
142
424
|
- 本次复核了当前安装的 DSH 打包产物:`dsh-session-query.readSession()` 仍然调用 `Session.create(...)`(新建快照路径)而不是 `Session.fromRestore`,但上游**已加入逃逸口**——报错文案变为 `seeded session constructor seed must equal its inherited prefix or mark its inherited cut`,即当日志中存在 `session/end-seed` 且 `data.inherited === true` 的标记事件时可以跳过等长校验。因此该缺陷是否复现取决于目标会话的日志里有没有这个标记(旧版本 DSH 写入的会话可能没有)。插件侧这套降级仍需保留,直到核心改走 restore 构造路径。
|
|
143
425
|
|
|
144
426
|
|
|
427
|
+
## v3.1.5(build 40,issue #22)— 会话列表刷新不再堆积,宿主不会再被 App 打到饱和
|
|
428
|
+
|
|
429
|
+
> 版本:插件 `3.1.5` / App `3.1.5+40`。本次**只改动了 App**——安装新 APK 即可,**无需同步插件副本,也无需重启宿主**。
|
|
430
|
+
|
|
431
|
+
- **修复:手机 App 会把桌面宿主打到持续满载,导致会话列表一直转圈,连其它功能一起卡住。** App 每收到一个会话事件就重新拉一次会话列表,而一次列表请求在宿主上要把历史日志**整个读一遍**(会话攒多后以分钟计)。请求发出去之后既不等结果、也不管上一个是否还在跑,于是越堆越多——实测手机上同时压着 **16–18 个请求**、宿主 CPU 到 **171%**,**谁都完不成**,列表自然永远刷不出来。现在同一时刻只会有一个列表请求在飞;期间到达的刷新会合并成「结束后再补一次」,**既不堆积,也不会漏掉这期间的变化**。
|
|
432
|
+
- **顺带修掉两个边界**:① 被合并的刷新现在会**等到补发真正结束**才返回——否则界面会先显示旧数据,随后数据更新了却不再通知,列表停在旧内容上;② **切换服务器地址后,旧地址未完成的请求不再挡住新地址的刷新**(此前换地址后首屏会被旧地址的慢请求卡住)。
|
|
433
|
+
- 其余为新增回归测试(请求合并、等待语义、销毁后不再补发、跨地址不阻塞),并**逐条验证过「注入对应缺陷即变红」**,而不是只看它们通过。
|
|
434
|
+
|
|
435
|
+
## v3.1.5(build 39,issue #15)— 修复文件浏览的返回超时与右滑退出
|
|
436
|
+
|
|
437
|
+
> 版本:插件 `3.1.5` / App `3.1.5+39`。本次改动了插件,需同步插件副本并重启宿主。
|
|
438
|
+
|
|
439
|
+
- **修复:文件预览返回后偶尔报「无法读取目录:TimeoutException」**。文件下载响应是唯一没有显式声明「取完即断」的响应,于是沿用了服务端的连接复用默认值;手机侧连接池的空闲时间比它长,复用那条已被服务端半关的连接时,下一个请求会一直等到超时。预览时正好走的下载通道,返回时的列目录就复用了它留下的连接。现已与其余接口统一为「响应即断」,同类路径(更新包下载、二维码)一并补齐。
|
|
440
|
+
- **修复:目录浏览页右滑会直接退出整个页面**,而不是返回上级。现在与同一操作栏里的 Git 页面行为一致:预览中 → 退回目录;子目录 → 回到上级;已在会话工作目录根 → 才退出页面。
|
|
441
|
+
- 其余为新增回归测试(下载响应头、四种返回手势路径),并验证过「改回旧实现即变红」。
|
|
442
|
+
|
|
443
|
+
## v3.1.5(build 38,issue #15)— 文件浏览改挂对话操作栏、改为会话级,并修复打不开的问题
|
|
444
|
+
|
|
445
|
+
> 版本:插件 `3.1.5` / App `3.1.5+38`。
|
|
446
|
+
|
|
447
|
+
- **修正入口位置**:build 37 把「文件」放在了主页抽屉,实际需求是**对话界面右上角「对话操作」⋮ 展开的操作栏**。现改为与 Git 导航并列,抽屉里的入口已移除。
|
|
448
|
+
- **修正浏览范围**:改为**当前会话的工作目录**(与同一栏的 Git 导航同源),不再是首页筛选选中的那个工作区。取不到会话工作目录时页面说明原因并可重试,不会退回到别处的目录。
|
|
449
|
+
- **修复打开即报错**:build 37 点开「文件」会显示「无法读取目录:No host specified in URI …」。根因是控制器新建了一个 `Api` 实例,而它的服务端地址默认为空、要由启动流程载入——于是请求发到了一个没有主机名的 URL 上。现改为复用已配置的全局实例。
|
|
450
|
+
- 操作栏新增动作后,旧设备上保存的图标顺序会自动恢复默认(仅丢一次自定义排序),不会出现缺项。
|
|
451
|
+
- 客户端仍是只读浏览;服务端读取边界的加固仍由 GitLab `#16` 单独跟踪,本次未改动。
|
|
452
|
+
|
|
453
|
+
## v3.1.5(build 37,issue #17 #15)— 子代理列表排序与状态 + 侧边栏文件浏览
|
|
454
|
+
|
|
455
|
+
> 版本:插件 `3.1.5` / App `3.1.5+37`。
|
|
456
|
+
>
|
|
457
|
+
> 注:本条中的「侧边栏『文件』入口」在 build 38 已按需求修正为对话操作栏入口,且该版本点开会报 `No host specified in URI`,见上一条。
|
|
458
|
+
|
|
459
|
+
- 会话工具 →「子代理」:列表改为按**创建时间由近到远**排列(最新派生的在最上),此前不排序且活跃/休眠父会话顺序相反。
|
|
460
|
+
- 子代理行显示**运行状态**:运行时方形虚线旋转、空闲不显示(复用会话列表同一套标识);状态取自实时推送,不再印英文 `running`/`inactive`(后者在休眠父会话下恒为 inactive,会与实际情况矛盾)。
|
|
461
|
+
- 子代理行副标题改为「会话 id · 相对创建时间」,让排序依据可见;「中断」按钮只在真的运行时出现。
|
|
462
|
+
- 侧边栏新增「文件」入口:只读浏览当前已注册工作区的目录结构与文件内容(issue #15)。
|
|
463
|
+
|
|
464
|
+
## v3.1.5(build 36)— 会话列表排序与运行状态标识
|
|
465
|
+
|
|
466
|
+
> 版本:插件 `3.1.5` / App `3.1.5+36`。
|
|
467
|
+
|
|
468
|
+
- 首页最近会话与会话列表按最新可见消息时间倒序;打开会话不再改变排序,旧插件缺少 `lastMessageAt` 时回退到 `lastActivity`、`createdAt`。
|
|
469
|
+
- 隐藏子代理会话、保留用户 fork 会话,并使计数与可见项目一致。
|
|
470
|
+
- 增加运行中与等待审批/问询状态标识;会话转为空闲时停止动效,并尊重系统减弱动态效果设置。
|
|
471
|
+
|
|
472
|
+
## v3.1.5(build 35,issue #13)— 对话操作栏:三个入口收敛为可排序图标栏
|
|
473
|
+
|
|
474
|
+
> 版本:插件 `3.1.5` / App `3.1.5+35`。
|
|
475
|
+
|
|
476
|
+
- 聊天页 AppBar 的 Git、会话工具、复制三个入口收敛为一个「对话操作」⋮ 入口,打开右侧窄幅图标栏;栏不挤压聊天内容,点外部或按系统返回即关闭。
|
|
477
|
+
- 图标栏支持长按拖动排序,顺序按设备本地持久化,跨会话与重启保持;默认顺序为 Git → 会话工具 → 复制。
|
|
478
|
+
- 三个动作的目标页与既有行为完全不变:Git 仍进入全屏只读浏览页,会话工具仍弹出原有底部弹层,复制仍导出当前已加载的对话。
|
|
479
|
+
- 无会话与空对话的既有兜底行为不变(不跳转、提示「当前没有可复制的对话内容」)。
|
|
480
|
+
|
|
481
|
+
## v3.1.5(build 34,issue #10)— 修复分支图悬线与颜色碰撞
|
|
482
|
+
|
|
483
|
+
> 版本:插件 `3.1.5` / App `3.1.5+34`。
|
|
484
|
+
|
|
485
|
+
- 未被更近子提交连入的已选分支 tip 不再在节点前绘制悬空 lane;真实父子连线和分页延续保持不变。
|
|
486
|
+
- 恢复归档 `app-git-management` 分支的浅色/深色调色板、31-based 引用哈希与碰撞探测,避免已选引用共享相同线色。
|
|
487
|
+
|
|
488
|
+
## v3.1.5(build 33,issue #10 note #379)— 分支图与只读 Git 安全修复
|
|
489
|
+
|
|
490
|
+
> 版本:插件 `3.1.5` / App `3.1.5+33`。
|
|
491
|
+
|
|
492
|
+
- 分支图修复 lane 拓扑错连与起点上方多余线段;保留真实父子连接、屏幕滚动和跨页延续。
|
|
493
|
+
- 只读 Git 浏览禁用仓库配置的 fsmonitor、hooks 与 clean/process filters,清除继承的 trace 写入变量;超限输出明确失败。
|
|
494
|
+
- 修复工作区变化期间的异步检查竞态,旧请求不再覆盖新鲜度状态。
|
|
495
|
+
|
|
496
|
+
## v3.1.5(build 32,issue #10 note #379)— 高饱和度分支图
|
|
497
|
+
|
|
498
|
+
> 版本:插件 `3.1.5` / App `3.1.5+32`。
|
|
499
|
+
|
|
500
|
+
- 提高浅色与深色主题下的分支图颜色饱和度,并保持引用颜色稳定和清晰对比。
|
|
501
|
+
|
|
502
|
+
## v3.1.5(build 31,issue #10 note #379)— 五引用分支图与黑白 Git 图标
|
|
503
|
+
|
|
504
|
+
> 版本:插件 `3.1.5` / App `3.1.5+31`。
|
|
505
|
+
|
|
506
|
+
- Git 菱形图标保留 45° 底板,浅色主题黑底白线、深色主题白底黑线。
|
|
507
|
+
- 分支图允许同时选择最多五个本地/远程引用;默认引用计入上限,超出时阻止并提示。
|
|
508
|
+
|
|
509
|
+
## v3.1.5(build 24,issue #10 note #379)— 工作区浏览与标签配置
|
|
510
|
+
|
|
511
|
+
> 版本:插件 `3.1.5` / App `3.1.5+24`。
|
|
512
|
+
|
|
513
|
+
- Git 浏览器改为全屏只读页,支持设置 1–3 个有序标签页。
|
|
514
|
+
- 新增已暂存、未暂存、未跟踪工作区分组,以及按需、受限的单文件差异预览。
|
|
515
|
+
- 保留授权、快照校验、提交图分页和共享 lane 布局;工作区变化仅提示刷新,不提供 Git 写操作。
|
|
516
|
+
|
|
517
|
+
## v3.1.5(build 23,issue #10)— 移动端 Git 只读导航
|
|
518
|
+
|
|
519
|
+
> 版本:插件 `3.1.5` / App `3.1.5+23`。
|
|
520
|
+
|
|
521
|
+
- 新增会话级 Git 只读浏览:仓库、分支、提交图和提交详情。
|
|
522
|
+
- 支持最多三个分支对比、图谱分页、提交文件分页和显式过期刷新。
|
|
523
|
+
- 服务端严格校验会话工作区、仓库身份、OID/ref、快照游标及文件路径;不提供 Git 写操作、状态、diff 或 patch。
|
|
524
|
+
|
|
145
525
|
## v3.1.5(2026-09-22,issue #12 / #15 / #19 / #22 / #24,PR #11 / #18 / #21)— 对话时间线 + 用量额度 + 复制对话 + 安全加固
|
|
146
526
|
|
|
147
527
|
> 版本:插件 `3.1.5` / App `3.1.5+22`。
|
|
@@ -372,6 +752,14 @@
|
|
|
372
752
|
|
|
373
753
|
## v3.0.0(2026-08-22)— LAN 桥:桌面版局域网直连(无需穿透)(二次 Code Review 落实集成于本版本内)
|
|
374
754
|
|
|
755
|
+
### App 自动更新(2026-08-23,App 3.0.0+8)——双更新源检查 / 下载 / 签名预检 / 安装
|
|
756
|
+
- **双更新源**(设置 → 关于,单选持久化,默认 GitHub):**GitHub Releases**(`releases/latest` 取首个 `DSH-Remote-*.apk` 资产直连下载)与 **dsh 运行主机**(插件新增 `updateDir` 配置 + `/api/update/manifest`、`/api/update/apk` 两个带 authToken 鉴权的端点,manifest 为唯一权威)。切换立即生效;GitHub 不可达时明确提示可切主机源。
|
|
757
|
+
- **检查触发**:设置页「检查更新」手动按钮(结果三分支:已是最新 / 确认弹窗 / 失败原因)+ 启动连接成功后静默自动检查一次(命中才提示:首页横幅 + 设置页版本行「● 有新版本」常驻,直到安装拉起或版本变更)。
|
|
758
|
+
- **版本判定(纯 Dart 模块 `update_core.dart`,14 例单测兜底)**:先比 major.minor.patch 再比 build;远端未显式带 `+build`(如 tag `v3.0.0`)时主段相等即不提示——本地热修 build 不被误判为降级;远端显式 build 更小按防降级异常处理(不更新并提示)。
|
|
759
|
+
- **下载与安装**:确认弹窗(版本/说明/大小/来源)→ App 内流式下载(进度可取消,取消即中止流并清理半成品文件)→ 主机源 sha256 校验 → **签名预检**(本机与下载 APK 证书 SHA-256 比对,不一致或读取异常一律取消并明确提示)→ FileProvider 拉起系统安装器。Android 8+ 首次安装由系统引导授权「安装未知应用」。
|
|
760
|
+
- **签名预检实现(AGP 9 适配)**:AGP 9 产物为纯 v2 签名(apksigner 实测 v1=false,`getPackageArchiveInfo(GET_SIGNATURES)` 读不到签名)——签名读取改用 **API 28+ `GET_SIGNING_CERTIFICATES`(signingInfo,兼容 v2/v3)**,API<28 回退 GET_SIGNATURES;构建签名配置改用 AGP 9 DSL(`enableV1Signing/enableV2Signing`)。
|
|
761
|
+
- **发布链路**:新增 Linux/WSL 发布脚本 `package-release.sh`(与 Windows `package-release.ps1` 等价);manifest.json 由共享生成器 `tools/gen-manifest.js` 统一生成(version 含 build / sha256 / size / notes=CHANGELOG 最新条目全文,JSON 合法且无 BOM),产物可用 `tools/verify-update-manifest.mjs` 校验。部署者把 APK + manifest 放进插件 `updateDir` 即完成主机源发布。
|
|
762
|
+
|
|
375
763
|
### 图像发送 64KB 误限修复(2026-08-23 热修)
|
|
376
764
|
- **根因**:`readJson(req, res, limit)` 从不接受第三个参数——`/send` 传入的 `64 * 1024 * 1024` 被静默丢弃,实际按 `readBody` 默认 **64KB** 计;图片 base64 一旦超过 64KB(≈48KB 原图,任何真实照片都超)即触发 `req.destroy()`,响应发不出去——手机端表现为「Connection reset by peer (errno 104)」;经 LAN 桥时桥把上游断连转成 502「upstream webserver unreachable」。
|
|
377
765
|
- **修复**:`readJson` 接受并透传 `limit`(其余 20 处调用不变,仍 64KB);`/send` 增加 `content-length` 预检——声明超 64MB 直接回 `413 payload-too-large` JSON(桥可透传),不再让客户端只看到 RST/502 拿不到原因;无 content-length 时仍由 `readBody` 流式兜底。
|
|
@@ -94,6 +94,9 @@
|
|
|
94
94
|
| D12 | 推送内容默认脱敏(minimal:仅事件类型+会话短码) | 第三方推送通道(Server酱/ntfy/Bark)不可信;核心内容默认不出本机(v2.6.0) |
|
|
95
95
|
| D13 | 消息链接 scheme 白名单(仅 http/https 可点击) | 防 file:/intent:/tel: 拉起任意应用(v2.6.0,App) |
|
|
96
96
|
| D14 | qr.png 与 qr-config 同策略(Host 校验 + loopback only) | 消除唯一无认证路由;桌面设置页本就要求 loopback 拉数据(v2.6.0) |
|
|
97
|
+
| D15 | 移动 Git 聚焦日常闭环,复杂历史操作后置 | 手机优先短时高频操作;按基础只读、日常写闭环、扩展管理分阶段交付 |
|
|
98
|
+
| D16 | Git 采用 Service Definition / Provider / Consumer 接缝 | App 零插件感知;mobile-remote 不依赖社区插件私有协议,也不重复实现 Git |
|
|
99
|
+
| D17 | Git 写操作采用仓库串行的可恢复任务 | 支持断线恢复和幂等;取消不冒充回滚;破坏性操作由服务端确认 |
|
|
97
100
|
|
|
98
101
|
## 7. 风险与应对
|
|
99
102
|
| 风险 | 应对 |
|
|
@@ -119,4 +122,4 @@
|
|
|
119
122
|
- `07-user-manual.md`:用户手册(含 FAQ)
|
|
120
123
|
- `08-扩展开发指南.md`:二次开发(动作区/推送/App 定制/分享你的版本)
|
|
121
124
|
- `09-compatibility.md`:兼容性(内核耦合点/多品牌/已知问题)
|
|
122
|
-
- `10-release.md`:发布操作手册(构建 → 预检 → 演练 → 试发布 → 正式发布 → 验证/回滚;含 Android
|
|
125
|
+
- `10-release.md`:发布操作手册(构建 → 预检 → 演练 → 试发布 → 正式发布 → 验证/回滚;含 Android 构建与排障附录 A)
|
package/docs/01-PRD.md
CHANGED
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
| 多地址自动切换 | 核心层 | bootstrap `server.urls` 收集(局域网 + 组网 IP,排除 169.254/16)+ 断线轮换(v2.4.1) |
|
|
138
138
|
| 连接自愈 | 核心层 | SSE 超时 + 心跳看门狗 + 地址轮换(v2.4.2/v2.5.1,黑洞约 10s 故障切换) |
|
|
139
139
|
| 手动切换连接地址 | 核心层 | 设置 → 电脑地址候选列表,探测后切换重连(v2.5.0) |
|
|
140
|
-
| 用量与额度 | 核心层 | `GET /api/account-usage`;来源独立成功/隐藏,服务端凭据隔离(v3.
|
|
140
|
+
| 用量与额度 | 核心层 | `GET /api/account-usage`;来源独立成功/隐藏,服务端凭据隔离(v3.1.5) |
|
|
141
141
|
|
|
142
142
|
## 11. 验收标准(v2.0,Phase 1 完成标志)
|
|
143
143
|
1. 手机完成「新建会话(选模式)→ 发消息 → 流式回复 → 通知 → 审批 → 翻历史记录」全链路。
|
package/docs/02-architecture.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 02 系统架构设计说明书 — dsh-mobile-remote
|
|
2
2
|
|
|
3
|
-
> 版本:v3.
|
|
3
|
+
> 版本:v3.1.5 · 状态:已实现(v2.3 问询/审批弹窗桥、v2.4~v2.5 连接自愈、v2.6 安全加固+模型提供商互通、v2.9/v3.0 LAN 桥 + 图像链路、v3.1.5 用量与额度) · 配套:01-PRD.md、03-api.md、04-security.md、09-compatibility.md
|
|
4
4
|
|
|
5
5
|
## 1. 背景与范围
|
|
6
6
|
DSH 由 Cordis 组合出宿主(desktop 版 `dsh-plugin-desktop` 或 web 版 `dsh --profile web`),webserver 默认只绑定 `127.0.0.1`(**桌面版 0.1.1-rc.2 起强制回环**,DesktopsWebServer 对非回环 host 直接 throw)。本插件在宿主侧挂载 Cordis 插件:在 webServer 上注册 `/m` 前缀路由,并在 **LAN 桥**(`lanBridge`,默认 `0.0.0.0:3080`)自建监听把移动端请求流式转发到回环 webserver——移动端形态为**原生 Flutter App**(`dsh-mobile-app`),经 `/m/api` 与插件通信。插件不修改桌面 GUI 的任何现有 UI。
|
|
@@ -217,7 +217,7 @@ sequenceDiagram
|
|
|
217
217
|
P-->>M: SSE `mobile/frame`(收起卡片,两端同步消失)
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
-
- **获取服务必须用 `ctx.inject(["apiProxy"])
|
|
220
|
+
- **获取服务必须用 `ctx.inject(["apiProxy"])`**:原因**不是**上下文隔离——同 realm 下 `ctx.get` 能读到兄弟插件注册的服务,官方指引也明确「可选服务用 `ctx.get(name)`,`ctx.<name>` 只留给已声明的注入」。真实原因是**激活时间点**:旧代 `ApiProxyService` 的依赖链比本插件的 `webServer` 更深,插件装配时它往往尚未 ACTIVE,严格 `ctx.get` 读到 `undefined`。因此同步探测用 `ctx.get`(包 try/catch),而要真正调用或订阅的能力一律走 `ctx.inject`——它是响应式依赖,服务迟到或卸载后重载都会自动重跑。(历史记录见 CHANGELOG v2.4.0 条目。)
|
|
221
221
|
- 只转发 question/approval/session-queue 瞬态帧;`session/event` 仍走 `ctx.on` 桥避免重复。
|
|
222
222
|
- **私有协议风险**:`events.mux` / `respond` 消息格式无稳定版本承诺;缺失时干净降级(`/m/api/respond` 返回 503、诊断 `respondBridge=false`),详见 docs/09-compatibility.md。
|
|
223
223
|
- 断线补发:App 重连 SSE 时插件回放 `pendingFrames`;从「需要你回答」通知进入会话即见挂起弹窗。
|