dsh-agy-link 0.4.50 → 0.4.57

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,183 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.57 (2026-10-16)
4
+
5
+ ### English
6
+
7
+ - **Fix: transient network jitter no longer sticky-quarantines healthy accounts as "需重新登录".**
8
+ - **Background**: agy prints the same 939-byte "Authentication required" stderr banner whether the login is really dead OR its keyring auth merely missed its hard 10s window on a flaky network. One afternoon of proxy jitter (2026-10-16) quarantined three healthy accounts on first sight; `setActiveAccount` then refused the quarantined slot with 该账号当前不可用(冷却或需重新登录).
9
+ - **Changes**:
10
+ 1. **Log-evidence classification** (`src/host/agy-log.ts` + `looksLikeAuthVerificationJitter`): the adapter now snapshots agy's per-run `cli-*.log` set before spawning and reads this run's log on an auth-shaped failure. `keyringAuth: timed out after 10s` / `failed to fetch user info` / `userinfo request failed` prove a STORED credential existed and only the network was down — the failure is reclassified NETWORK (retryable, rotates, no quarantine). An authoritative token error (`invalid_grant`…) always wins over jitter. Verified against real logs: the genuine sign-out log contains zero occurrences of every jitter marker.
11
+ 2. **Confirmation-gated quarantine** (`pool.noteAuthFailure`): a bare, non-authoritative "not signed in" banner no longer sets the sticky `authRequired` flag on the first occurrence — it only rotates the account away for the current retry. The flag hardens into a real quarantine on a second consecutive failure with no success in between; a successful run resets the streak. Authoritative OAuth paths (`invalid_grant` from the token endpoint) and the explicit re-login paths still quarantine immediately.
12
+ - **Tests**: classifier fixtures from the real jitter and sign-out logs; log-reader run attribution; single-strike / streak-reset pool semantics; end-to-end `auth-jitter` fake mode ⇒ NETWORK with no flag, bare `auth` banner ⇒ AUTH with no flag on first sight.
13
+
14
+ ### 中文 (Chinese)
15
+
16
+ - **修复:瞬时网络抖动不再把健康账号错误地隔离为"需重新登录"。**
17
+ - **背景**:无论登录是真的失效,还是 keyring 鉴权在抖动网络上没赶上 10 秒硬超时,agy 都会打印同一段 939 字节的 "Authentication required" stderr 横幅。2026-10-16 一个下午的代理抖动就让三个健康账号被一次性隔离;随后 `setActiveAccount` 对被隔离账号直接返回 该账号当前不可用(冷却或需重新登录)。
18
+ - **变更**:
19
+ 1. **基于日志证据的分类**(`src/host/agy-log.ts` + `looksLikeAuthVerificationJitter`):适配器在 spawn 前对 agy 的本次运行日志(`cli-*.log`)做快照,出现鉴权形态失败时读取本次日志。`keyringAuth: timed out after 10s` / `failed to fetch user info` / `userinfo request failed` 证明本地确实存有凭据、只是网络不通 —— 此时失败改判为 NETWORK(可重试、轮转、不隔离)。权威的 token 错误(`invalid_grant` 等)永远优先于抖动证据。已用真实日志验证:真正登出的日志中所有抖动标记出现次数为 0。
20
+ 2. **隔离需二次确认**(`pool.noteAuthFailure`):不带权威证据的裸"未登录"横幅,第一次出现不再直接置粘性 `authRequired` 标记,仅为本次重试轮转走;只有连续两次失败且中间没有成功才升级为真正隔离;一次成功运行即清零计数。权威 OAuth 路径(token 端点返回 `invalid_grant`)与显式重新登录路径仍在首次即隔离。
21
+ - **测试**:取自真实抖动/登出日志的分类器用例;日志读取器的"仅本次运行"归属;单次不隔离/成功清零的池语义;端到端 `auth-jitter` 假模式 ⇒ NETWORK 且无标记,裸 `auth` 横幅 ⇒ AUTH 且首次不隔离。
22
+
23
+ ## 0.4.56 (2026-10-16)
24
+
25
+ ### English
26
+
27
+ - **Feature: Gemini 4 Argon (Pro/Ultra) now shows as its own quota family with its separate weekly limit.**
28
+ - **Background**: Antigravity now grants paid Google AI Pro / Ultra accounts access to **Gemini 4 Argon**, which bills against its OWN weekly quota pool (it does not consume the plain Gemini pool). The backend surfaces this as a dedicated quota group in `retrieveUserQuotaSummary` (display name like "Gemini 4 Argon") and as `gemini-4-argon-low/-medium/-high` model ids in `fetchAvailableModels`.
29
+ - **Changes**:
30
+ 1. Added a new `'argon'` entry to `ModelFamily`; `modelFamilyOf` now classifies any id containing `argon` into it BEFORE the generic `gemini-` gate — previously argon ids folded into the `google` family and their usage silently drained/reported the plain Gemini counter.
31
+ 2. `QuotaService.refreshAccountQuota` detects the Argon quota group (its display name still contains "gemini", so the argon gate must win) and ingests its weekly bucket into `quotas.argon`; argon model-level breakdown follows the same family.
32
+ 3. GUI quota panel: an **Argon** row renders directly under Gemini ONLY when the backend actually returned argon quota data for that account — free plans and accounts without the Argon permission never see an empty Argon panel. Since Argon is a weekly-only counter today, the ghost "5-hour / —" line is suppressed unless the backend reports one.
33
+ 4. `/agy pool` status appends `| Argon N% (weekly)` to the Quota line only for accounts that carry argon data.
34
+ 5. Cross-family auto-failover (`autoFallbackModel`) intentionally does NOT target the argon family: it is a paid-plan-only pool and must not become a silent fallback for exhausted Gemini quota.
35
+ - **Tests**: argon model-id classification; argon summary group lands in `quotas.argon` without clobbering `quotas.google`; accounts without argon access carry no argon entry (row hidden).
36
+
37
+ ### 中文 (Chinese)
38
+
39
+ - **功能:Gemini 4 Argon(Pro/Ultra 专属)现在作为独立的额度家族展示,并显示其单独的周额度。**
40
+ - **背景**:Antigravity 已向付费 Google AI Pro / Ultra 账号开放 **Gemini 4 Argon**,它消耗独立的周额度池(不占用普通 Gemini 额度)。后端在 `retrieveUserQuotaSummary` 中以独立的额度组返回(显示名形如 "Gemini 4 Argon"),并在 `fetchAvailableModels` 中返回 `gemini-4-argon-low/-medium/-high` 模型 ID。
41
+ - **改动**:
42
+ 1. `ModelFamily` 新增 `'argon'`;`modelFamilyOf` 在通用 `gemini-` 前缀判定**之前**优先识别包含 `argon` 的 ID —— 此前 argon 模型会被归入 `google` 家族,其用量会错误地挤占/上报普通 Gemini 计数。
43
+ 2. `QuotaService.refreshAccountQuota` 识别 Argon 额度组(其显示名仍包含 "gemini",因此 argon 判定必须优先)并把周额度桶写入 `quotas.argon`;模型级明细同样按该家族归类。
44
+ 3. GUI 额度面板:仅当后端确实返回了该账号的 argon 额度数据时,才在 Gemini 下方渲染 **Argon** 面板 —— 免费套餐及无 Argon 权限的账号绝不会看到空的 Argon 栏。由于 Argon 目前只有周额度,后端未上报 5 小时窗口时不再显示幽灵的「5 小时额度 —」行。
45
+ 4. `/agy pool` 状态输出仅为携带 argon 数据的账号在 Quota 行尾追加 `| Argon N% (weekly)`。
46
+ 5. 跨家族自动故障转移(`autoFallbackModel`)刻意不指向 argon 家族:它是付费专属额度池,不应在 Gemini 额度耗尽时被静默兜底。
47
+ - **测试**:argon 模型 ID 分类;argon 额度组写入 `quotas.argon` 且不覆盖 `quotas.google`;无 argon 权限的账号不产生 argon 条目(面板隐藏)。
48
+
49
+ ---
50
+
51
+ ## 0.4.55 (2026-10-16)
52
+
53
+ ### English
54
+
55
+ - **Fix: Gemini weekly quota displaying as empty/dash (`—`) after sync.**
56
+ - **Root Cause**: `AGY_ENDPOINTS` placed Google's internal staging endpoint (`https://daily-cloudcode-pa.googleapis.com`) ahead of the official production endpoint (`https://cloudcode-pa.googleapis.com`). While the staging endpoint responds HTTP 200, its `retrieveUserQuotaSummary` output completely omits the `Gemini Models` group (returning only `Claude and GPT models`). Consequently, `QuotaService.fetchQuotaSummary` took the 200 response and locked onto the staging endpoint; `familyQuotas['google']` never received the server's weekly bucket and fell back to model-level 5-hour discovery data (`weeklyFraction: undefined`), resulting in the UI rendering Gemini's weekly quota as `—`.
57
+ - **Resolution**:
58
+ 1. Reordered `AGY_ENDPOINTS` to prioritize the official production endpoint `https://cloudcode-pa.googleapis.com`, matching the official `agy` CLI binary.
59
+ 2. Added a completeness gate in `fetchQuotaSummary`: if an endpoint returns a partial summary that omits the primary `Gemini Models` group, `QuotaService` continues falling through to the remaining endpoints until a complete summary is obtained, rather than locking onto the partial staging response.
60
+ - **Feature/Fix: auto-repair common LLM Mermaid syntax flaws and graceful fallback.**
61
+ - **Auto-repair (`repairMermaidSource`)**: When models produce flowchart/graph diagrams with common pseudo-code syntax flaws (e.g. using `+` to join nodes `A + B --> C + D` instead of `A & B --> C & D`, unquoted subgraph titles with colons/spaces like `subgraph 链条1: 工具打制`, or node labels containing unquoted special characters like `T[人口 > 12]`, `S[私有制: 守罐人]`), the client-side renderer now automatically heals these patterns before passing to Mermaid, enabling diagrams to render successfully without errors.
62
+ - **Graceful fallback for auto-sniffed blocks**: If an unrecognized code block (`代码块`) sniffed as Mermaid fails parsing even after auto-repair, the plugin now silently falls back to displaying it as a normal clean code block without rendering an intrusive `Mermaid render failed:` error banner under it.
63
+
64
+ - **Fix: DSH "Stop generating" (停止生成) button failing in multi-turn tool continuation spans and queues.**
65
+ - **Root Cause**: While single-turn initial spans wired `options.signal` to process termination, tool continuation spans (`detectContinuation(messages) !== null`) and live run debounce rescue invoked `driveSpan` without forwarding `options.signal`. Furthermore, `driveSpanBody` lacked an `abort` event listener, causing the generator to wait indefinitely on `rec.eventsFrom(from)` even when DSH signaled an abort. Similarly, queued requests blocked on `Semaphore.acquire()` did not observe `signal` cancellations.
66
+ - **Resolution**:
67
+ 1. Forwarded `options.signal` across all `driveSpan` callsites (continuation, debounce rescue, and initial span).
68
+ 2. Attached an `abort` listener in `driveSpanBody` that immediately calls `rec.requestAbort?.()`, terminates the underlying `agy` process, pushes `{ type: 'finish', reason: { kind: 'aborted' } }` into the chunk queue, and closes the stream iterator cleanly.
69
+ 3. Added `signal` cancellation support to `Semaphore.acquire(signal)` and burst throttle backoff to release queued requests immediately upon abort.
70
+ - **Fix/Feature: Mermaid rendering swallowing source code, wide layout collapse, and interactive view toggle.**
71
+ - **Root Cause**:
72
+ 1. Language detection in `fenceLang` matched DSH's generic banner text `"代码块"`, erroneously treating explicitly tagged ````mermaid```` blocks as untagged generic blocks.
73
+ 2. Large multi-subgraph flowcharts using Chromium's default `<foreignObject>` HTML labels collapsed into invisible blank boxes when constrained by `max-width: 100%`.
74
+ 3. When Mermaid rendering threw or produced an error SVG, the CSS rule hiding code blocks paired with the suppression of error text resulted in swallowing all content—leaving a completely blank white container.
75
+ - **Resolution**:
76
+ 1. Corrected `fenceLang` to inspect code block classes and attributes before falling back to banner labels.
77
+ 2. Configured Mermaid with `flowchart: { htmlLabels: false }` to render reliable native SVG `<text>` elements, eliminating the Chromium `<foreignObject>` blank-paint bug.
78
+ 3. Added an interactive `查看源码 / 查看图表` toggle button allowing users to switch between the visual diagram and raw Mermaid source code at any time.
79
+ 4. Guarded against swallowed content: when rendering fails, the original code remains 100% visible alongside a subtle warning banner, ensuring source content is never lost.
80
+
81
+ ### 中文 (Chinese)
82
+
83
+ - **修复:DSH 界面中点击「停止生成」在多轮工具调用延续期失效的问题。**
84
+ - **根本原因**:在首轮对话中 `options.signal` 正确绑定了进程终止,但在原生工具镜像调用的后续延续轮次(`detectContinuation` 分支)以及防抖拯救调用中,`driveSpan` 均未向下传递 `options.signal`。此外,`driveSpanBody` 内部没有监听 `signal.abort` 事件,导致用户在 DSH 点击停止时,生成器依旧停在 `eventsFrom` 等待事件流,后台进程未被杀死,界面停止按钮卡住无效。同时跨会话并发信号量 `Semaphore.acquire()` 在排队等待时也未响应取消信号。
85
+ - **解决方案**:
86
+ 1. 在所有 `driveSpan` 调用处(工具延续、防抖拯救、首轮启动)完整传递 `options.signal`。
87
+ 2. 在 `driveSpanBody` 挂载 `abort` 监听器:一旦收到取消信号,立即触发 `rec.requestAbort?.()` 杀死底层 `agy` 进程,向输出队列推送 `{ type: 'finish', reason: { kind: 'aborted' } }` 并安全关闭队列,使 DSH 的流式迭代器瞬间退出。
88
+ 3. 升级 `Semaphore.acquire(signal)` 及并发节流延时,支持在排队中收到 abort 信号时立即退出并清理队列,杜绝无意义挂起。
89
+ - **修复/功能:Mermaid 图表内容被吞、超宽图表缩放空白及源码交互式切换。**
90
+ - **根本原因**:
91
+ 1. `fenceLang` 语言嗅探提取到了 DSH 顶部横幅文本 `"代码块"`,导致显式声明为 ````mermaid```` 的图表被误当成未指定语言的通用块。
92
+ 2. Mermaid 默认使用 HTML `<foreignObject>` 标签渲染文本,在 Chromium / Electron 宿主中遇到多子图超宽流程图(如 >3000px)并应用 `max-width: 100%` 缩放时,极易发生文本排版崩溃或整体空白不渲染的 bug。
93
+ 3. 当 Mermaid 渲染报错或生成空图时,由于隐藏原生代码块的 CSS 规则生效且错误提示被隐藏,导致原始代码和图表全部消失,形成一片空白区域(内容被吞)。
94
+ - **解决方案**:
95
+ 1. 修正 `fenceLang`:优先读取 `code` 标签 class 及属性,忽略无意义的横幅标签 `"代码块"`。
96
+ 2. 优化渲染配置:初始化 Mermaid 时启用 `flowchart: { htmlLabels: false }`,使用原生 SVG `<text>` 渲染节点,彻底规避 Chromium `<foreignObject>` 缩放渲染空白的底层缺陷。
97
+ 3. 增加交互式切换工具栏:在渲染图表右上角提供「查看源码 / 查看图表」按钮,用户可随时一键切换查看 Mermaid 原始 Markdown 代码与可视化图表。
98
+ 4. 兜底保护机制:若渲染异常,确保原始代码块 100% 完整保留可见,并在上方以友好提示条展示,绝不吞没用户和模型的内容。
99
+
100
+ - **修复:点击「同步」后 Gemini 周额度显示为空/短横杠(`—`)的问题。**
101
+ - **根本原因**:`AGY_ENDPOINTS` 此前将 Google 内部预演端点(`https://daily-cloudcode-pa.googleapis.com`)排在官方生产端点(`https://cloudcode-pa.googleapis.com`)之前。虽然预演端点返回 HTTP 200,但其 `retrieveUserQuotaSummary` 响应中完全缺失了 `Gemini Models` 额度组(仅返回了 `Claude and GPT models`)。这导致 `QuotaService.fetchQuotaSummary` 命中 200 后锁定该端点,`familyQuotas['google']` 无法获取到官方周配额桶,只能回退使用单模型 5 小时数据(`weeklyFraction` 始终为 `undefined`),前端进而将 Gemini 的周额度渲染为 `—`。
102
+ - **解决方案**:
103
+ 1. 调整 `AGY_ENDPOINTS` 顺序:优先请求与官方 `agy` CLI 保持一致的官方生产端点 `https://cloudcode-pa.googleapis.com`。
104
+ 2. 增强 `fetchQuotaSummary` 完整性校验门禁:若端点返回的配额摘要缺失了核心的 `Gemini Models` 组,自动顺次下穿到后续端点获取完整摘要,不再过早锁定仅包含第三方模型的残缺响应。
105
+ - **功能/修复:Mermaid 常见大模型语法自动自愈修复与优雅降级。**
106
+ - **语法自动自愈(`repairMermaidSource`)**:针对大模型输出流程图时高频出现的伪代码语法瑕疵(例如材料合成中用加号连接 `A + B --> C + D`、包含冒号的子图未加引号 `subgraph 链条1: 工具打制`、节点文本包含特殊字符未加引号 `T[人口 > 12]`、`S[私有制: 守罐人]` 等),客户端在解析前自动自愈修正,直接成功渲染图表。
107
+ - **自动嗅探代码块优雅降级**:对于未显式标注为 ````mermaid```` 的通用代码块(语言标签为 `代码块` 或未指定),若自愈后仍无法解析,安静降级为普通代码块展示,不再在代码下方直接打印刺眼的 `Mermaid render failed:` 错误文本。
108
+
109
+ ## 0.4.54 (2026-10-16)
110
+
111
+ ### English
112
+
113
+ - **Fix (macOS): complete resolution for recurring modal keychain password prompts.** Older versions (v0.4.41-v0.4.48) accidentally ran `security default-keychain -s <isolated-kc>`, permanently redirecting the user's desktop session `default-keychain`, `login-keychain`, and user search list (`list-keychains -d user`) to a locked per-account keychain under `~/.dsh/agy-accounts/` created with an un-unlockable random passphrase. On modern macOS, `Library/Keychains/login.keychain-db` is also a special-cased filename that SecurityServer associates with the user's OS login password, rejecting empty-passphrase unlocks. The plugin now:
114
+ 1. Automatically detects and repairs hijacked `default-keychain`, `login-keychain`, and `list-keychains` on boot (`repairMacSystemKeychain`), restoring the real user login keychain (`~/Library/Keychains/login.keychain-db`) safely and idempotently.
115
+ 2. Automatically purges legacy un-unlockable isolated keychains (`purgeStaleIsolatedKeychain`), unregistering them from `securityd` and deleting conflicting files so SecurityAgent never raises unanswerable password dialogs.
116
+ - **Feature (Multi-platform): comprehensive cross-platform logic unification.**
117
+ 1. **Unified Terminal Launcher (`openAccountTerminal`)**: Fully unified interactive terminal launching across macOS (AppleScript Terminal.app), Windows (`cmd.exe /c start` with `USERPROFILE` + `HOME` environment and `windowsHide: true`), and Linux (adaptive detection across `xdg-terminal-exec`, `x-terminal-emulator`, `gnome-terminal`, `konsole`, `xfce4-terminal`, `alacritty`, `xterm`).
118
+ 2. **Unified System Proxy Detection (`detectSystemProxy`)**: Automatically discovers system-wide proxy settings for GUI environments where shell env vars are missing—supporting macOS (`scutil --proxy`), Windows Registry (`HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings`), Linux desktop (`gsettings` GNOME proxy mode), and fallback environment variables (`ALL_PROXY`, `HTTPS_PROXY`, `HTTP_PROXY`).
119
+ 3. **Cross-Platform Credential Isolation**: Standardized credential boundaries across platforms—Windows Credential Manager targeted isolation, macOS isolated throwaway keychains with auto-repair, and standard Unix file-based isolation.
120
+
121
+ ### 中文 (Chinese)
122
+
123
+ - **修复(macOS):彻底解决钥匙串密码弹窗反复弹出问题。** v0.4.41-v0.4.48 曾调用 `security default-keychain -s <isolated-kc>`,导致用户的桌面会话全局 `default-keychain`、`login-keychain` 以及用户搜索列表被持久化重定向到了 `~/.dsh/agy-accounts/` 下由旧版本生成的随机密码隔离钥匙串中。此外 macOS 的 SecurityServer 会对名为 `login.keychain-db` 的路径做特殊绑定,强制要求系统用户登录密码,导致空密码解锁失败并引发系统 SecurityAgent 弹窗提示输入密码。本次修复:
124
+ 1. 插件启动时自动执行 `repairMacSystemKeychain`:检测并修复被篡改的 `default-keychain`、`login-keychain` 与用户搜索列表,自动恢复为用户真实的登录钥匙串(`~/Library/Keychains/login.keychain-db`),幂等且安全。
125
+ 2. 自动检测并清理历史遗留的无法解锁的废弃钥匙串(`purgeStaleIsolatedKeychain`),从 `securityd` 会话中彻底注销并删除文件,阻断 SecurityAgent 弹出任何死循环密码框。
126
+ - **功能(多平台):全面梳理并实现 Windows、macOS、Linux 跨平台逻辑统一。**
127
+ 1. **多平台统一终端唤醒器(`openAccountTerminal`)**:彻底统一账号登录终端的唤醒逻辑,原生支持 macOS(AppleScript 激活 Terminal.app)、Windows(`cmd.exe /c start` 注入 `USERPROFILE` + `HOME` 隔离目录并设置 `windowsHide: true` 避免控制台闪烁)以及 Linux(自适应探测 `xdg-terminal-exec`、`x-terminal-emulator`、`gnome-terminal`、`konsole`、`xfce4-terminal`、`alacritty`、`xterm` 等各种桌面环境)。
128
+ 2. **多平台系统代理自动感知(`detectSystemProxy`)**:针对 GUI 宿主未继承终端 Shell 代理环境变量的场景,全面支持三端系统级代理自动检测——macOS(`scutil --proxy` 解析 HTTP/HTTPS/SOCKS)、Windows(读取注册表 WinINet Internet Settings 代理设置)、Linux(通过 `gsettings` 读取 GNOME 桌面代理配置)以及标准环境变量兜底。
129
+ 3. **多平台凭据与隔离统一**:规范各端凭据存储边界——Windows 使用 Credential Manager 目标隔离、macOS 使用独立钥匙串配给加自愈防篡改机制、Linux 使用标准 Unix 用户目录隔离。
130
+
131
+ ## 0.4.53 (2026-10-15)
132
+
133
+ ### English
134
+
135
+ - **Fix: a NUL byte in a tool result can no longer kill the turn before agy starts.** Tool output that quoted binary content (an agent listing or reading a `.git` directory, a packed object, an image) carried U+0000 into the assembled prompt; because the prompt travels as an `-p` argv element, `spawn()` rejected it with `TypeError [ERR_INVALID_ARG_VALUE]: The argument 'args[16]' must be a string without null bytes` and the turn failed as "failed to spawn agy" before agy was ever launched — the retry re-sent the same history and failed identically, so the session could not make progress. `stripNulBytes()` now removes U+0000 from the rolling digest (per message text), from the final prompt on its single path into `buildArgs` — covering both the argv transport and the `--input-format stream-json` stdin transport — and from the one-shot/compaction prompt after file inlining. Every other control character is legal in argv and is left untouched.
136
+
137
+ ### 中文 (Chinese)
138
+
139
+ - **修复:工具结果里的 NUL 字节不再让整个轮次在 agy 启动前就崩溃。** 当工具输出引用了二进制内容(agent 列出或读取 `.git` 目录、packed object、图片等)时,U+0000 会被带进拼装好的提示词;提示词以 `-p` 参数进入 argv,`spawn()` 因此抛 `TypeError [ERR_INVALID_ARG_VALUE]: The argument 'args[16]' must be a string without null bytes`,整轮以「failed to spawn agy」失败——重试会重发同一段历史,于是同样失败,会话彻底卡死。现在 `stripNulBytes()` 会从三处移除 U+0000:滚动摘要中每条消息的文本、进入 `buildArgs` 前的最终提示词(同时覆盖 argv 与 `--input-format stream-json` 的 stdin 两种传输)、以及一次性/压缩任务内联文件后的提示词。其余控制字符在 argv 中合法,保持原样。
140
+
141
+ ## 0.4.52 (2026-10-15)
142
+
143
+ ### English
144
+
145
+ - **Fix: DSH `/goal` infinite continuation loop resolved.** In DSH, `/goal` runs a multi-round state machine (up to 256 rounds) that keeps injecting `<goal_round>` until the agent explicitly invokes `update_goal(action='complete')`. Because `agy` CLI uses its own native tools and terminates after finishing, DSH treated the goal as perpetually active (running up to 93+ rounds). The bridge now intercepts the completion event in goal mode and emits a synthetic `update_goal(complete)` tool-call, properly closing the goal state machine.
146
+ - **Feature: DSH `/plan` mode support.** When running in plan mode (prompt containing "You are in plan mode"), the bridge automatically emits the `exit_plan_mode` tool-call carrying the generated plan markdown for user interactive review and approval.
147
+ - **Feature: /agy goal command family.** Added `/agy goal [status|complete|pause|resume|clear]` allowing users to inspect the current goal state (ID, revision, objective, round count) or manually control/complete/clear the active goal.
148
+ - **Feature: /agy session command family.** Added `/agy session [info|clear]` for inspecting session workspace CWD, bound agy conversation ID, event counts, and safely dropping session bindings without guessing. `/agy clear` is also upgraded to prioritize the current session.
149
+ - **Feature: Intelligent quota-expiry-first rotation (Weekly & 5h).** Refactored pool candidate selection: when switching accounts, the pool prioritizes accounts whose weekly quota is expiring soonest (Priority 1: preventing irreversible weekly quota loss), followed by accounts whose 5-hour quota is expiring soonest (Priority 2). Execution maintains seamless sticky sequential drain, continuing on the current account until its quota is exhausted before cleanly advancing to the next optimal candidate.
150
+ - **UI: Simplified thinking turn banner.** Replaced verbose `[agy thinking turn · N thinking tokens]` chip with concise `[agy · N tokens]` (or `[agy]` when no count is present), avoiding long headers crowding out the collapsed reasoning summary in DSH.
151
+ - **UI: Removed redundant "Set as primary" action.** Dropped the confusing "Set as primary" button from the account cards across all locales. Manual account activation is cleanly handled via the existing "Set as in use" action.
152
+
153
+ ### 中文 (Chinese)
154
+
155
+ - **修复:彻底解决 DSH `/goal` 目标空转死循环问题。** DSH 的 `/goal` 状态机在模型未调用宿主原生 `update_goal(action='complete')` 前,会在每轮结束后自动注入 `<goal_round>` 启动下一轮(最多 256 轮,曾导致 93+ 轮空转)。由于 agy 是自闭环 Agent 引擎,完成任务后正常退出但不会直接调用 DSH 宿主工具。桥接层新增 `dsh-goal` 协议转换模块,在检测到目标轮次执行完毕后,自动向 DSH 发射 `update_goal(complete)` 工具调用块,使 DSH 目标状态机正常流转至完成态并停止重试。
156
+ - **功能:支持 DSH `/plan` 规划模式适配。** 当检测到会话处于规划模式(上下文携带 "You are in plan mode")时,桥接层在模型生成规划后自动发射 `exit_plan_mode` 工具调用块,将规划 Markdown 提交给 DSH 宿主渲染审核弹窗供用户审批。
157
+ - **功能:新增 `/agy goal` 目标管理命令。** 支持 `/agy goal [status|complete|pause|resume|clear]`,可实时查看当前会话的目标状态(目标 ID、版本号、目标描述、已执行轮次/上限),或手动完成、暂停、恢复、清除卡住的目标。
158
+ - **功能:新增 `/agy session` 会话管理命令。** 支持 `/agy session [info|clear]`,可精确查看当前 DSH 会话绑定的工作区 CWD、agy 会话 ID、事件总数等信息,或一键清除当前会话的 agy 绑定;同时增强 `/agy clear` 优先清理当前活动会话的绑定。
159
+ - **功能:按配额临期优先度智能轮换账号(周额度优先,5小时次优)。** 重构账号轮换调度算法:在切号时,第一优先级优先选取周额度剩余时间最少(最先到期)的账号(避免周硬额度清零浪费),第二优先级选取 5 小时窗口最先到期的账号;同时严格遵循无感黏性消耗原则(只要当前账号的 5 小时或周额度未耗尽绝不切号,耗尽后自动无缝切换下一个最优账号),最大化利用全部账号配额。
160
+ - **体验:精简思考过程标签(thinking banner)。** 将冗长的 `[agy thinking turn · N thinking tokens]` 简化为精炼的 `[agy · N tokens]`(无计数时为 `[agy]`),大幅缩减括号内字符宽度,让 DSH 折叠思考栏能够更完整展现具体的思维链与工具摘要。
161
+ - **体验:移除冗余的“设为主用”按钮。** 从前端控制台卡片操作栏和各语言包中彻底移除“设为主用”按钮,手动切换账号统一由“设为当前使用”负责,简化界面操作。
162
+
163
+ ## 0.4.51 (2026-10-15)
164
+
165
+ ### English
166
+
167
+ - **Feature: Per-account Enable / Disable toggles.** Added dedicated Enable / Disable buttons and status badges to each account card in the WebUI console and CLI (`/agy enable-account <id>`, `/agy disable-account <id>`). Disabled accounts are dimmed with a gray "Disabled" badge.
168
+ - **Fix: Account rotation and selection strictly skips disabled accounts.** Rotation algorithms (`selectAccount`, `advanceAccount`, sticky sequential drain, round-robin, and fallback model degradation) skip disabled accounts completely.
169
+ - **Fix: Cooldown & quota reset fallback never returns a disabled account.** `getActiveAccountId` previously fell back to `primaryAccountId` or the first account without checking `enabled`, which could surface a disabled slot as active; it now only falls back to eligible enabled accounts (or `undefined` if all accounts are disabled).
170
+ - **Fix: Background auth reverification skips disabled accounts.** `needsAuthReverify` now checks `account.enabled`, preventing the background quota poller from probing disabled slots.
171
+ - **Fix: Detailed error diagnostics when accounts are disabled.** When all or remaining accounts cannot serve a model family, the error message explicitly enumerates disabled slots and informs the user to re-enable them in the console or CLI rather than reporting misleading 0 cooldown/auth counts.
172
+
173
+ ### 中文 (Chinese)
174
+
175
+ - **功能:每个账号增加启用 / 停用按钮。** 在 WebUI 控制台的每个账号卡片上以及 CLI 命令中增加了启用/停用按钮与操作(`/agy enable-account <id>`、`/agy disable-account <id>`)。停用账号卡片以半透明呈现并标记灰色“已停用”徽章。
176
+ - **修复:切号与调度严格跳过停用账号。** 顺次耗尽(sequential)、轮询(round-robin)、主动切号(advanceAccount)、跨家族自动降级(autoFallbackModel)等调度算法在选号时全部严格跳过已停用账号。
177
+ - **修复:号池活动指针降级不再回退到已停用账号。** 修复了 `getActiveAccountId` 在全部账号限流时无条件 fallback 到主账号或首个账号导致停用账号被当作当前在用账号的缺陷;现在严格仅回退到已启用的账号(若全部账号均被停用则返回 `undefined`)。
178
+ - **修复:后台静默身份复验跳过已停用账号。** `needsAuthReverify` 增加了 `account.enabled` 检查,彻底杜绝后台轮询向 Google 请求复验已停用账号。
179
+ - **修复:账号不可用时清晰提示停用状态。** 当全部或部分账号不可用时,错误提示中会明确指出有几个账号处于“已停用”状态,并提示用户在控制台或通过 CLI 重新启用,不再报出误导性的 0 冷却/0 登录错误。
180
+
3
181
  ## 0.4.50 (2026-10-14)
4
182
 
5
183
  ### English