dsh-agy-link 0.4.67 → 0.4.70

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
@@ -1,5 +1,129 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.70 (2026-10-25)
4
+
5
+ ### English
6
+
7
+ - **Fix: the 5-hour quota row showed the weekly numbers (2026-10-22 report).**
8
+ - `fetchAvailableModels` returns a per-model `quotaInfo` with NO window label. For some accounts it carries the 5-hour bucket, for others the WEEKLY bucket: live `daoxzeex@gmail.com` reported `0.1736 / reset 2026-10-24T18:19:18Z` on every Gemini model, which is exactly the weekly bucket of `retrieveUserQuotaSummary`.
9
+ - The merge took "the lowest remaining across all sources" and filed it into the family 5-hour slot, so the GUI painted `5-hour quota 19% / Weekly 19%` with the SAME weekly reset on both rows (the filed screenshot) while the account actually had 82% of its 5-hour quota left.
10
+ - The reset instant now decides the window (`sameQuotaWindow`, 5-minute tolerance): a reading that matches the summary weekly reset tightens ONLY the weekly row; one that matches the 5-hour reset tightens the 5-hour row; an unmatchable reading keeps the old conservative behaviour. Eligibility is unchanged — the weekly row still drives the 5% drain check.
11
+ - **Fix: a queued turn no longer looks frozen for 15 minutes.**
12
+ - Windows has ONE machine-global agy credential slot, so sessions serialize: a healthy long run in one workspace made two other sessions sit with a completely empty transcript for `dispatchTimeoutMinutes` (15m) and then silently re-queue for another cap — indistinguishable from a hang (2026-10-22: the promo-tcn sessions, while a 15-minute run in another project held the slot).
13
+ - The wait now streams a session-visible `[agy] waiting for the agy credential slot …` line into the transcript, with an escalating cadence (20s → 60s → 3m → 9m) so even a 15-minute queue leaves a handful of lines. Re-queues after a cap are announced too.
14
+ - A generator abandoned while waiting (Stop / stream closed) now hands a late grant back instead of leaking a concurrency slot.
15
+ - **Fix: the machine-wide credential slot is held only until agy has READ it — different accounts now run concurrently.**
16
+ - Measured on agy 1.4.3 with a live 14-minute run: print mode resolves its credential ONCE at startup (`printmode.go:403 "not authenticated, trying silent auth"` → `:405 "silent auth succeeded"` at +3.2s) and performs zero further token/auth work for the rest of the run. Holding the Windows slot for the whole run was pure serialization, and it is what parked the 2026-10-22 promo-tcn sessions for 15 minutes behind another project's run.
17
+ - `armSlotHandoff` releases the lease on the child's FIRST output line (45s ceiling for a slow startup, run-end fallback, idempotent), while the identity is still installed under the mutex immediately before each spawn — so a later switcher cannot change what an already-started run read.
18
+ - `JETSKI_OAUTH_TOKEN` (the only env-based credential route in the binary) was probed with a bogus token: the run still authenticated from the keyring, so true per-process injection remains unavailable upstream. Recorded in KNOWN-GAPS with the measurement.
19
+ - **Fix: a rejected credential-slot write now refuses the run instead of billing the account that happens to be installed.**
20
+ - The Windows write is a PowerShell cold start that compiles a C# P/Invoke shim; its old 8-second ceiling made it time out and return `false` **without touching the slot** on a loaded machine (reproduced 2026-10-23: delete then write reported false and left the slot empty). All four install sites ignored that boolean, so the next spawn authenticated as the PREVIOUS account — silent cross-account quota spend, the exact corruption class the module exists to prevent.
21
+ - Install sites now verify the write (one retry, then `SlotUnavailableError` → the turn fails visibly); teardown/restore paths log loudly instead of failing a finished turn. Writes get a 30s ceiling; reads stay at 8s because they sit on the poll path.
22
+ - New test: a write that always reports false refuses the run, leaves the slot untouched and does not leak the mutex.
23
+
24
+ ### 中文
25
+
26
+ - **修复:5 小时额度行显示成了周额度(2026-10-22 反馈)。**
27
+ - `fetchAvailableModels` 的 per-model `quotaInfo` 不带窗口标签:有的账号返回 5 小时桶,有的账号返回**周**桶(实测 `daoxzeex@gmail.com` 每个 Gemini 模型都返回 `0.1736 / reset 2026-10-24T18:19:18Z`,正是 `retrieveUserQuotaSummary` 里的周桶)。
28
+ - 旧合并逻辑「取所有来源里最低的余量」把它塞进了 5 小时行,界面于是显示 `5 小时额度 19% · 周额度 19%`、两行 reset 完全相同(反馈截图),而该账号 5 小时其实还剩 82%。
29
+ - 现在由 reset 时刻判定窗口归属(`sameQuotaWindow`,5 分钟容差):命中周 reset 的读数只收紧周行;命中 5 小时 reset 的收紧 5 小时行;无法判定的读数保持原有保守行为。可用性判定不变——周行依旧参与 5% 耗尽检查。
30
+ - **修复:排队中的回合不再看起来卡死 15 分钟。**
31
+ - Windows 只有一个全局 agy 凭据槽,会话之间必须串行:另一个工作区一次正常的长任务就能让其它会话的转录区**整整 15 分钟一片空白**(`dispatchTimeoutMinutes`),随后再静默重排一轮——和卡死无法区分(2026-10-22 的 promo-tcn 两个会话就是被另一个项目 15 分钟的运行挡住)。
32
+ - 等待期间现在会向会话流里写入可见的 `[agy] 正在等待 agy 凭据槽 …` 提示,节奏递增(20s → 60s → 3m → 9m),15 分钟排队也只留几行;超时重排同样会写明。
33
+ - 等待中被 Stop / 关流放弃的请求,现在会把迟到的许可归还,而不是漏掉一个并发槽。
34
+ - **修复:全局凭据槽只占用到 agy 读完凭据为止——不同账号现在可以真正并发。**
35
+ - 实测 agy 1.4.3 一次 14 分钟的运行:print 模式只在启动瞬间解析一次凭据(`printmode.go:403` 未认证 → `:405` silent auth 成功,+3.2 秒),之后 14 分钟**再无任何 token/auth 操作**。把 Windows 全局槽占满整个 run 纯属多余串行——2026-10-22 的 promo-tcn 两个会话正是被另一个项目那 14 分钟的运行堵了 15 分钟。
36
+ - 新增 `armSlotHandoff`:在子进程输出**第一行**时立刻交还租约(启动慢则 45 秒上限、run 结束兜底、幂等),而身份安装依旧在每次 spawn 前、在互斥锁内完成,因此后来的切换不可能改变已启动 run 读到的凭据。
37
+ - 二进制里唯一的进程级凭据入口 `JETSKI_OAUTH_TOKEN` 已用假 token 实测:仍然从系统 keyring 认证成功,说明上游还不支持真正的进程级注入;该结论连同测法已写入 KNOWN-GAPS。
38
+ - 补充实测:**把全局凭据条目删掉后,agy 确实会改读家目录凭据文件**(假 token → `UNAUTHENTICATED 401`)。但 keyring 在写入侧同样优先(`Failed to save token to keyring, falling back to file`),任何一次成功运行都会把全局条目写回来,所以"永久空槽 + 纯文件隔离"仍不成立;凭据隔离目前只是读取侧能力。
39
+ - **修复:凭据槽写入被拒绝时,拒绝启动,而不是用"当前碰巧装着"的账号去计费。**
40
+ - Windows 侧写入是一次 PowerShell 冷启动(Add-Type 编译 C# P/Invoke),旧实现的 8 秒上限在机器繁忙时会**超时并返回 false,而槽位根本没被改动**(2026-10-23 实测:删除后再写入返回 false,槽位保持空)。四个安装点都没检查这个布尔值,于是紧接着的 spawn 会以**上一个账号**的身份认证 —— 静默跨账号扣额度,正是本模块要防的那类污染。
41
+ - 现在安装点会校验写入(失败重试一次,仍失败则抛 `SlotUnavailableError`,让这一轮可见地失败);收尾/恢复路径改为大声告警而不毁掉已完成的轮次。写入超时提到 30 秒,读取保持 8 秒(在轮询路径上)。
42
+ - 新增测试:写入恒返回 false 时必须拒绝运行、槽位保持原状、互斥锁不泄漏。
43
+
44
+ ## 0.4.69 (2026-10-23)
45
+
46
+ ### English
47
+
48
+ - **Feat: Google risk-control hardening and CLI-first quota architecture.**
49
+ - Implemented CLI-first quota detection via official `agy -p /usage`: 100% genuine Go TLS fingerprint and client handshake, eliminating Node.js-level direct REST calls (`v1internal:retrieveUserQuotaSummary`) that trigger JA3/JA4 fingerprint mismatch warnings.
50
+ - Purged internal test endpoints (`daily-cloudcode-pa.sandbox.googleapis.com` and `autopush-cloudcode-pa.sandbox.googleapis.com`) from `AGY_ENDPOINTS` to prevent sandbox probe alarms on consumer accounts.
51
+ - Token refresh is fully delegated to the native `agy` CLI Go runtime; Node.js host process no longer issues direct refresh requests to `oauth2.googleapis.com/token`.
52
+ - Background quota polling interval widened from 15m to 60m (`quotaPollIntervalMs: 60m`), and account polling incorporates a 2-second stagger sleep to avoid simultaneous process bursts.
53
+ - **Feat: Full concurrency on Windows credential slot via global primary account alignment (Scheme A).**
54
+ - Resolved Windows single-slot mutex serialization: concurrent sessions align to the current primary healthy candidate, hitting the `parallelSameAccount: true` fast path for 100% lock-free concurrency across sessions.
55
+ - Single-direction migration to the next candidate only occurs when the active account encounters a 429 quota exhaustion.
56
+ - **Feat: Two-tier dual-loop test framework aligned with academic-agent & test suite speedup.**
57
+ - Introduced `pnpm run test:fast` (powered by `scripts/fast-test.mjs`) for inner TDD vibe loops (0.5s~5s), running only Git-affected test files or specified module keywords (`pnpm run test:fast <keyword>`).
58
+ - Tuned simulated asynchronous delay timers in `test/adapter.test.ts` and `fake-agy.mjs` from 5000ms/8000ms down to 300ms/400ms, speeding up adapter unit test execution by ~4x.
59
+ - **Feat: Scroll guard & tool view expansion state persistence.**
60
+ - Added `scroll-guard.ts` to suspend DOM mutations and heavy scans (decisions, images, reasoning, mermaid) during active scrolling and smooth momentum settling.
61
+ - Preserved user expanded/collapsed tool card states across TanStack Virtualizer dynamic remount cycles.
62
+
63
+ ### 中文
64
+
65
+ - **新功能:针对 Google 敏感风控强化防护与 CLI 优先配额体系。**
66
+ - 配额查询全面转向官方 `agy -p /usage` 解析:100% 走官方原生 Go 二进制握手与正规 TLS 指纹,消除 Node.js 层使用 `undici` 直接裸调 Google 内部 `v1internal` 接口带来的 JA3/JA4 客户端指纹断层风险。
67
+ - 从 `AGY_ENDPOINTS` 中彻底移除 `daily-cloudcode-pa.sandbox.googleapis.com` 与 `autopush-cloudcode-pa.sandbox.googleapis.com` 内部测试端点,杜绝异常沙箱端点探测对正式 Google 账号的风控隐患。
68
+ - OAuth 令牌刷新完全交由 `agy` 官方 Go 运行时在日常使用中原生完成,Node.js 宿主停止主动向 `oauth2.googleapis.com/token` 发送换票请求。
69
+ - 默认后台巡检周期放宽至 60 分钟(`quotaPollIntervalMs: 60m`),多账号后台轮询增加 2 秒错峰休眠,避免瞬时并发拉起 CLI 进程造成的系统负载颠簸。
70
+ - **新功能:Windows 凭证槽位并发性能全面解锁(方案 A:全局主导账号收敛)。**
71
+ - 解决 Windows 系统下因全局唯一定制凭证槽位 `gemini:antigravity` 导致的跨 Session 串行卡顿问题:所有会话默认对齐到号池主导活跃健康账号,命中 `parallelSameAccount: true` 快速通道,实现跨会话 100% 无锁全并发执行。仅当主导账号 429 配额耗尽时,全局指针单向整体迁移至下一账号。
72
+ - **新功能:对齐 academic-agent 的两级双环极速测试架构与用例调优。**
73
+ - 新增 `pnpm run test:fast` 极速内环测试工具(`scripts/fast-test.mjs`),实现基于 Git 变动的秒级精准回归(0.5s~5s)以及按模块关键字直跑(`pnpm run test:fast <keyword>`)。
74
+ - 优化 `adapter.test.ts` 与 `fake-agy.mjs` 中的异步等待延迟(由 5000ms/8000ms 降至 300ms/400ms),单测执行速度提升近 4 倍,保障日常开发极速反馈心流。
75
+ - **新功能:页面平滑滚动守卫与工具卡片展开状态持久化。**
76
+ - 增加 `scroll-guard.ts` 滚动守卫机制,在用户主动滚屏及平滑滑动期间挂起 DOM 探测(decisions/images/reasoning/mermaid),彻底杜绝滚屏时内容突变抖动与闪烁。
77
+ - 工具卡片折叠/展开状态跨 TanStack-Virtual 虚拟列表重新挂载自动持久化保留(`expandedToolBlockKeys`)。
78
+
79
+ ## 0.4.68 (2026-10-23)
80
+
81
+ ### English
82
+
83
+ - **Feat: Dynamic model picker reflects active account eligibility (Gemini 4 Argon isolation).**
84
+ - Accounts in the pool now discover and cache models independently (`ModelCatalog` keyed by `accountId`).
85
+ - When switching the active account in the UI or pool, the DSH composer model picker automatically refreshes (`llm/adapters-updated`).
86
+ - If the active account lacks Argon access (free/standard tier), `gemini-4-argon` is dynamically excluded from the picker to prevent generation errors. When an account with Pro/Ultra subscription is active, Argon models are immediately restored.
87
+ - **Fix: Eliminate page scrolling and violent screen flickering in Antigravity client.**
88
+ - Root cause: In `src/client/decisions.ts`, decision chip toolbar was repeatedly injected into TanStack-Virtual dynamic measurement containers because container-level marker `data-agy-decisions-scanned` was checked but never set, and re-rendering reconstructed heading nodes. The item height expansion triggered scroll position adjustments, which caused a re-render and re-injection flywheel.
89
+ - In addition, settings nav row `MutationObserver` watched the entire subtree including `characterData` and re-triggered on its own marker writes without an attribute filter, and account button busy states repainted the entire account list instead of scoping to the target account.
90
+ - Resolved with container-level idempotence guards (`data-agy-decisions-scanned` written before mutation), pre-checking existing toolbar containers, filtering nav mutation observer strictly to marker attribute changes, and scoping button busy states and shimmer animations to target accounts.
91
+ - **Fix: Send agy CLI User-Agent in quota requests so Argon quota group is returned (PR #54, Fixes #53).**
92
+ - Google's Cloud Code backend requires a genuine `agy` CLI User-Agent header (format `Antigravity/<version> (darwin; arm64)`) to return the `Gemini 4 Argon` quota bucket in `retrieveUserQuotaSummary`. Without this header, only generic Gemini and 3P groups were returned.
93
+ - Quota service now detects the installed `agy` CLI version and passes the proper User-Agent header in HTTP requests. When an account transitions or drops dedicated groups, obsolete cooldowns and stale last-known-good entries are cleanly evicted.
94
+ - **Fix: DSH Host 100% CPU busy loop on macOS caused by copying active SQLite WAL files (Fixes #52).**
95
+ - Root cause: `loadAgyDbData()` previously copied `conversation.db`, `-wal`, and `-shm` to a temporary directory before querying tool step parameters and model thoughts. On macOS (and other BSD-derived libuv platforms), when an active SQLite WAL file is checkpointed or truncated to 0 during `copyFile`, libuv's `uv_fs_copyfile` enters an infinite busy loop in a worker thread, causing the Host process to permanently consume 100% of a CPU core.
96
+ - Solution: Replaced file copying with direct SQLite reads (`node:sqlite` DatabaseSync with `readOnly: true`, falling back to `sqlite3` CLI with `-cmd ".timeout 2000" -cmd "PRAGMA query_only = ON;"`). SQLite's native WAL architecture provides atomic, consistent MVCC read snapshots concurrently with active writers without blocking or file-copying races.
97
+ - Added regression test covering active WAL querying, WAL truncation/checkpointing during active use, sqlite3 CLI fallback, and zero-byte database handling.
98
+ - **Fix: Transport failures outlast a real egress outage, and no longer rotate a shared-egress pool.**
99
+ - Live case (2026-10-21 16:34–16:48): the machine's proxy answered `CONNECT 200` and then killed TLS for ~14 minutes. Every `agy` run on every account died in its startup probe with `Post "https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist": EOF`, which agy wraps as `Eligibility check failed: …`. DSH retried twice inside ~4 seconds and gave up — while the Antigravity desktop's own language server simply kept retrying and recovered.
100
+ - Transport (`NETWORK`) failures now state their own backoff via `providerRetryAfterMs`: **5s → 15s → 30s** for consecutive failures in one session, reset on success or any non-transport failure, and treated as fresh after 10 minutes of quiet. `providerRetryPolicy` grew to 3 retries with `maxDelayMs: 45s` (the retry plugin *drops* a retry whose requested delay exceeds that cap, so it must sit above the longest transport delay).
101
+ - A transport failure is only account-scoped when accounts leave through **different** proxies. With a single shared egress (every account on the config/system proxy, including pool accounts seeded with a copy of the system proxy) the retry stays on the current account: the sticky pointer is not advanced, the conversation binding is kept, and the account-rotation budget stays available for real quota/eligibility hops. The in-step failover of a settled recording also skips the budget without changing accounts.
102
+ - Non-transport retries keep their 2s/4s starting schedule; nothing else about classification (AUTH vs NETWORK vs ELIGIBILITY) changed.
103
+
104
+ ### 中文
105
+
106
+ - **新功能:模型选择框按当前活动账号资格动态隔离(Gemini 4 Argon 自动感知)。**
107
+ - 号池内账号支持按账号独立发现并缓存模型目录(`ModelCatalog` 按 `accountId` 隔离)。
108
+ - 在前端或号池切换当前活动账号后,DSH 输入框模型选择列表即时联动刷新(`llm/adapters-updated`)。
109
+ - 若当前活动账号无 Argon 权限(标准/免费层),输入框模型列表中自动剔除 `gemini-4-argon`,防止误选调用报错;当切回 Pro/Ultra 订阅账号时,Argon 模型自动呈现。
110
+ - **修复:解决 Antigravity 插件设置及历史页面来回滚动疯狂闪屏问题。**
111
+ - 根因定位:在 `src/client/decisions.ts` 中,决策按钮增强器容器级标记 `data-agy-decisions-scanned` 此前只读未写,且在 TanStack-Virtual 动态虚拟列表中,重新挂载渲染会重建 heading 节点。工具条反复注入导致项高度变化,进而触发虚拟列表重算 scrollTop 并再次触发重渲染注入飞轮。
112
+ - 此外,设置导航图标的 `MutationObserver` 监听范围过广且在修改属性时自身被反复触发,且操作账号按钮的全局 busy 状态导致 40+ 个元素属性全量刷新并引发重排重绘。
113
+ - 修复方案:在变更 DOM 前对容器写入 `data-agy-decisions-scanned` 并严格预检容器已有工具条;导航 Observer 限制仅监听对应属性变更(`attributeFilter`)并剥离 `characterData`;按钮 loading 状态与额度进度条 shimmer 动画改为账号级别作用域隔离。
114
+ - **修复:配额请求中上报 agy CLI 原生 User-Agent 以获取 Argon 额度分组(合并 PR #54,修复 #53)。**
115
+ - Google Cloud Code 后端要求在 `retrieveUserQuotaSummary` 请求中携带真实的 `agy` CLI User-Agent(格式如 `Antigravity/<version> (darwin; arm64)`)才会返回 `Gemini 4 Argon` 独立额度桶。缺少该头时后端仅下发普通 Gemini 与 3P 组。
116
+ - 配额探测服务现在自动探测本地 `agy` 版本并携带该头发送请求;当账号升级或移出专用桶时,旧版冷却记录与失效缓存自动淘汰。
117
+ - **修复:macOS 下复制活跃 SQLite WAL 时触发 libuv `copyFile` 忙循环导致 DSH Host 持续 100% CPU(修复 #52)。**
118
+ - 原因分析:`loadAgyDbData()` 此前在读取工具参数和思考内容时,顺序将 `conversation.db`、`-wal` 和 `-shm` 复制到临时目录。在 macOS(以及其他基于 BSD 的 libuv 平台)上,当活跃 WAL 文件在复制过程中被 SQLite checkpoint 截短为 0 字节时,libuv 的 `uv_fs_copyfile` 工作线程会陷入无限忙循环,导致 DSH Host 进程持续耗尽单核 100% CPU。
119
+ - 修复方案:完全移除临时目录与文件复制逻辑,改为直接通过 SQLite 引擎一致性读取(优先使用 `node:sqlite` 的 `DatabaseSync` 只读模式并开启 `PRAGMA query_only = ON;` 与 `busy_timeout`,后备使用 `sqlite3` CLI)。SQLite WAL 模式天然支持多读一写并发 MVCC 快照,既消除了文件截短忙循环与临时文件 I/O 争用,又保证了读取一致性。
120
+ - 补充回归测试:覆盖活跃 WAL 读取、WAL 截短/检查点处理、sqlite3 CLI 后备路径及 0 字节文件防御。
121
+ - **修复:网络抖动时重试不再 4 秒内放弃,共用出口的号池不再被无意义轮换。**
122
+ - 实测案例(2026-10-21 16:34–16:48):本机代理对 `CONNECT` 返回 200 后直接掐断 TLS 长达约 14 分钟。每个账号上每次 `agy` 运行都在启动探测阶段死于 `Post "https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist": EOF`,被 agy 包成 `Eligibility check failed: …`。DSH 约 4 秒内重试两次即宣告失败,而 Antigravity 桌面端自己的 language server 只是一直重试,网络恢复后照常工作。
123
+ - 传输类(`NETWORK`)失败现在通过 `providerRetryAfterMs` 自带退避:同一会话连续失败按 **5s → 15s → 30s** 递增;成功或出现非传输类失败即归零,静默超过 10 分钟后重新从 5s 起算。`providerRetryPolicy` 提升为 3 次重试、`maxDelayMs: 45s`(重试插件对**超过上限**的请求延迟会直接放弃该次重试,因此上限必须高于最长退避)。
124
+ - 只有当各账号走**不同代理**时,传输失败才算账号级问题。共用同一出口时(所有账号都走配置/系统代理,含新建号池账号被写入系统代理副本的情况)重试留在当前账号:不推进粘性指针、保留会话绑定、也不消耗本该留给配额/资格跳转的轮换预算;已结算记录的步内失败切换同样不再计数、不再换号。
125
+ - 非传输类重试仍从 2s/4s 起步;AUTH / NETWORK / ELIGIBILITY 的判定逻辑未做任何改动。
126
+
3
127
  ## 0.4.67 (2026-10-20)
4
128
 
5
129
  ### English