dsh-agy-link 0.4.70 → 0.4.74

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.74 (2026-10-28)
4
+
5
+ ### English
6
+
7
+ - **Feat(warmup): opt-in 7-day weekly quota auto-warmup and manual pre-warming (PR #60).**
8
+ - `WarmupService` activates an idle account's weekly reset timer with a minimal `loadCodeAssist` + one-token `generateContent` probe, only when the weekly bucket is explicitly full and its reset instant has passed (or the bucket is genuinely cold).
9
+ - Adds "Warmup" buttons to the account card and console header. `autoWarmup` (env `DSH_AGY_AUTO_WARMUP`) defaults to **false**: enabling it scans every 5 minutes with 1.5–3s jitter, a 30-minute failure backoff, and skips accounts in cooldown / auth quarantine.
10
+ - Hardened before release: a missing `weeklyFraction` is treated as unknown (never 100%), `cloudaicompanionProject` accepts both string and `{id}` shapes and never falls back to a foreign project id (the old `bamboo-precept-lgxtn` fallback produced 403s), malformed request bodies can no longer fan out to all accounts, and the scheduler cannot overlap itself.
11
+ - **Fix(mcpBridge): pass the required abort signal to bridged tool calls (PR #57).**
12
+ - Every bridged `/call` creates an `AbortController`, passes `signal` to `tools.execute()` (DSH declares it required; tools reading `exec.signal` previously died with `Cannot read properties of undefined (reading 'aborted')`), and aborts when the MCP client goes away.
13
+ - Session keys resolve in both shapes: `session-<uuid>` for top-level web sessions and bare `<uuid>` for sub-agent/fork sessions. A resolvable bare id is never rewritten; only a miss retries with the `session-` prefix.
14
+ - **Feat(mcpBridge): audit-log every bridged call (PR #58).**
15
+ - Each `/call` logs `mcp call <tool> [<outcome>] <ms>` through the plugin logger (journald), with the caller class and failure text. Arguments are never logged.
16
+ - **Docs(mcpBridge): DSH `send_message` can be bridged (PR #58, issue #59).**
17
+ - `send_message` is not restricted: add it to `mcpToolAllowlist` and call it explicitly on the `dsh-tools-<port>` MCP server. The DSH sub-agent footer names agy's native tool, which cannot resolve DSH agent ids — root cause is upstream in `@deepseek-ai/dsh-subagent`; `agent_teams_send_message` remains the reliable path for agy members.
18
+ - **Fix(client): isolate the console overlay to eliminate scroll flicker at the root.**
19
+ - The Antigravity console is a full-viewport overlay that neither froze the page behind it nor suspended the plugin's global DOM scanners, and its backdrop carried a full-viewport `backdrop-filter: blur()`. Every frame of motion behind it (wheel/inertia scrolling, the modal's 3s status polling, scanner DOM injection) was re-sampled through the GPU filter and re-laid-out → the recurring "打开控制台后滚动闪屏" root cause.
20
+ - Removed the full-viewport backdrop blur (stable `rgba` dim instead), added an explicit overlay-isolation contract (`agyModalStore.setOpen()` toggles `html.agy-modal-open`, which locks `[data-conversation-scroll]` with `overflow:hidden` and contains overscroll), and routed decisions/images/reasoning/mermaid scanners through `isInteractionLocked()` (scroll OR overlay) with a catch-up scan on resume and cleanup on teardown.
21
+ - Regression tests pin the contract: no full-viewport `backdrop-filter`, the scroller is locked while the overlay is open, and all four scanners gate on `isInteractionLocked()`.
22
+
23
+ ### 中文
24
+
25
+ - **新增(warmup):7 天周配额自动预热与手动预热(opt-in,PR #60)。**
26
+ - `WarmupService` 只在周额度明确满额且已到重置时间(或确实处于冷启动)时,发送一次极小的 `loadCodeAssist` + 单 token `generateContent` 探活,提前激活 7 天计时器。
27
+ - 账号卡片与顶栏新增「预热」按钮。`autoWarmup`(环境变量 `DSH_AGY_AUTO_WARMUP`)默认 **false**;开启后每 5 分钟巡检一次,带 1.5–3s 随机抖动、30 分钟失败退避,并跳过冷却中/需重新认证的账号。
28
+ - 发版前加固:缺失 `weeklyFraction` 一律视为未知(不再当成 100%);`cloudaicompanionProject` 同时兼容字符串与 `{id}` 结构,且不再回退到外部共享 project id(旧的 `bamboo-precept-lgxtn` 回退会 403);畸形请求体不会触发全账号预热;调度器不会自我重叠。
29
+ - **修复(mcpBridge):为桥接工具调用补上必需的 abort signal(PR #57)。**
30
+ - 每次桥接 `/call` 创建 `AbortController`,把 `signal` 传给 `tools.execute()`(DSH 声明为必填;此前读取 `exec.signal` 的工具会抛 `Cannot read properties of undefined (reading 'aborted')`),并在 MCP 客户端断开时中止。
31
+ - 会话 key 两种形态都能解析:顶层 Web 会话为 `session-<uuid>`,子代理/fork 会话为裸 `<uuid>`;能直接解析的裸 id 绝不会被改写,只有未命中时才重试 `session-` 前缀。
32
+ - **新增(mcpBridge):每次桥接调用记审计日志(PR #58)。**
33
+ - 每次 `/call` 通过插件日志(journald)输出 `mcp call <工具> [<结果>] <毫秒>`,含调用方类别与失败信息,**不记录参数**。
34
+ - **文档(mcpBridge):DSH 的 `send_message` 可被桥接(PR #58,issue #59)。**
35
+ - `send_message` 不受限制:把它加进 `mcpToolAllowlist`,在 `dsh-tools-<port>` 这个 MCP server 上显式调用即可。DSH sub-agent footer 指向的是 agy 原生工具,无法识别 DSH agent id——根因在 `@deepseek-ai/dsh-subagent` 上游;agy 成员仍应使用 `agent_teams_send_message` 上报。
36
+ - **修复(client):从根因消除「打开 Antigravity 控制台后滚动闪屏」。**
37
+ - 控制台是全屏浮层,却既没有冻结背后页面,也没有暂停插件自身的全局 DOM 扫描器,且遮罩带全屏 `backdrop-filter: blur()`。浮层背后的一切移动/重绘(滚轮/惯性滚动、控制台每 3s 状态轮询、扫描器注入)都会每帧被 GPU 滤镜重新采样并重新布局 → 即闪屏根因。
38
+ - 移除全屏遮罩模糊(改用稳定的 `rgba` 半透明遮罩);建立显式「浮层隔离契约」:`agyModalStore.setOpen()` 切换 `html.agy-modal-open`,锁定 `[data-conversation-scroll]`(`overflow:hidden`)并阻断滚动链;decisions/images/reasoning/mermaid 四个扫描器统一走 `isInteractionLocked()`(滚动中或浮层打开),关闭后补扫一次,卸载时清理锁类。
39
+ - 回归测试锁定契约:全屏遮罩不得再出现 `backdrop-filter`、浮层打开时滚动容器必须锁定、四个扫描器必须走 `isInteractionLocked()`。
40
+
41
+ ## 0.4.73 (2026-10-27)
42
+
43
+ ### English
44
+
45
+ - **Fix(digest): preserve chronological order in conversation digest and prevent latest task misplacement.**
46
+ - `buildDigest()` previously placed the latest user task at the top of the digest array before appending older history (`kept.push(taskLine)` followed by `kept.push(...keptOther)`), completely inverting the digest timeline. Agy received the newest request at the beginning of the context and the previous turn's request/response at the bottom, leading the model to treat the previous turn as the freshest instruction and ignore the new request.
47
+ - Corrected assembly order so historical messages precede the latest task (`[...keptOther, taskPart]`) while preserving priority budget reservation for the latest task.
48
+ - **Fix(sessions): prevent false-positive compaction detection from dropping healthy conversation bindings.**
49
+ - `adapter.ts` previously invalidated the session binding whenever `messages.length < binding.lastMessageCount`. Minor fluctuations in message counts (e.g. 1-2 messages dropped by telemetry filtering or message store pruning after reconnection) falsely triggered compaction detection, deleting the valid agy session binding and forcing an unnecessary full-context digest re-seed.
50
+ - Introduced threshold-based compaction detection: true compaction requires substantial history reduction (e.g. drop by >20% or down to <=4 messages), while minor fluctuations only adjust the message watermark without invalidating the agy conversation.
51
+
52
+ ### 中文
53
+
54
+ - **修复(digest):修复会话摘要时间线逆序导致的“最新任务被历史覆盖/失忆”缺陷。**
55
+ - 此前 `buildDigest()` 为给最新用户任务预留空间,先将任务推入数组首位,再追加其余历史记录(`kept.push(taskLine)` 后跟 `kept.push(...keptOther)`),导致摘要内部时间线颠倒:最新任务被排在最开头,而上一轮的指令与回复出现在历史摘要最末尾。agy 接收后将末尾上一轮历史误判为最新要求,进而忽略了用户的最新输入。
56
+ - 修正组装顺序,保证早期历史在前、最新任务在后(`[...keptOther, taskPart]`),同时保留优先为最新任务分配字符配额的设计。
57
+ - **修复(sessions):消除 Compaction 压缩检测假阳性,防止健康会话绑定被误删。**
58
+ - 此前一旦 `messages.length < binding.lastMessageCount` 即判定为历史压缩并清空绑定。当会话闲置重新激活时,遥测过滤或消息存储微调导致的消息数微小减少(如减少 1~2 条)会误触发该逻辑,彻底删除原有的 agy 会话绑定并退化为全量摘要重放。
59
+ - 引入梯度阈值判定:仅在历史大幅度缩减(如减少超 20% 或缩减至 4 条以下)时才判定为 Context Compaction,微小消息变动仅校准水位标尺,避免误断开底层长会话。
60
+
61
+ ## 0.4.72 (2026-10-27)
62
+
63
+ ### English
64
+
65
+ - **Fix(mcpBridge): publish MCP config to the agy 1.4+ registry and carry caller identity (Issue #55, PR #56).**
66
+ - `writeMcpConfig()` previously wrote `<workspace>/.mcp.json`, but `agy` 1.4+ loads MCP servers exclusively from `~/.gemini/config/mcp_config.json` (and per-account `.gemini` sandboxes), causing bridged tool calls to fail with `No MCP servers configured`.
67
+ - Added multi-target publishing supporting the global registry, isolated account homes, and workspace scopes (`mcpConfigScope: 'global' | 'workspace' | 'both'`, plus `mcpConfigPath` override).
68
+ - Port-keyed entries (`dsh-tools-<port>`) prevent collisions between multiple DSH hosts sharing the registry, with clean atomic LIFO restoration on disposal.
69
+ - Exported `DSH_MCP_SESSION` to the agy child process and forwarded it as `X-DSH-Session` to resolve the calling agent, fixing `agent_teams tools require a calling agent (exec.agent was undefined)`.
70
+ - **Fix(credential-slot): eliminate line-barging and concurrent holder race condition in `AsyncMutex`.**
71
+ - Identified and resolved a critical race condition where releasing the mutex dropped `holders` to 0 before the scheduled microtask ran, allowing synchronous callers to barge ahead and grant multiple concurrent holders simultaneously.
72
+ - Implemented direct ownership handoff without dropping holder count when waiters are queued, guaranteeing strict mutual exclusion and FIFO queueing under high concurrency.
73
+ - **Fix(client): eliminate session console first-open flicker.**
74
+ - Session status badge now claims primary modal host synchronously on mount, preventing asynchronous portal remount flicker.
75
+ - Status polling now gracefully relaxes to a 15s interval when idle to keep the cache warm, with complete timer cleanup upon client context disposal.
76
+ - **Fix(mermaid): prevent Dagre 0x0 / 16x16 collapsed SVG artifacts.**
77
+ - Render Mermaid diagrams without an unattached mount container so viewport metrics measure accurately, and detect/heal empty or collapsed SVGs.
78
+ - **Fix(keychain): provision isolated macOS Keychain on account creation.**
79
+ - Automatically provisions isolated login keychains when adding account slots or committing staging accounts on macOS, avoiding SecurityAgent system prompts.
80
+
81
+ ### 中文
82
+
83
+ - **修复(mcpBridge):发布 MCP 配置至 agy 1.4+ 实际读取的注册表并携带调用者身份(Issue #55,PR #56)。**
84
+ - 此前 `writeMcpConfig()` 仅写入工作区 `.mcp.json`,而 `agy` 1.4+ 仅从 `~/.gemini/config/mcp_config.json`(及子账号 `.gemini` 沙箱)加载 MCP 服务,导致会话提示 `No MCP servers configured`。
85
+ - 支持多目标发布(全局注册表、多账号隔离主目录及工作区范围,提供 `mcpConfigScope: 'global' | 'workspace' | 'both'` 及 `mcpConfigPath` 覆盖配置)。
86
+ - 每个桥接实例按端口隔离服务键名(`dsh-tools-<port>`),防止多实例覆盖,并在退出时原子化恢复原有内容。
87
+ - 会话生成时将 `DSH_MCP_SESSION` 注入子进程环境,经由桥接脚本转发为 `X-DSH-Session` 请求头,在宿主端通过 `agents` 服务解析调用者身份,彻底解决 `agent_teams tools require a calling agent (exec.agent was undefined)`。
88
+ - **修复(credential-slot):消除 `AsyncMutex` 的插队竞争与并发持有者缺陷。**
89
+ - 对抗性审计发现:旧实现中 `releaseOne()` 先将 `holders` 归零后通过 `queueMicrotask` 唤醒等待者,在此微任务微小窗口内同步调用的 `acquire()` 会发生插队并导致两个调用者同时进入临界区。
90
+ - 改造为排队时直接所有权移交机制(Direct Handoff),保证严格互斥与 FIFO 先入先出顺序,消除测试套件偶发的 flake。
91
+ - **修复(client):消除控制台首次打开时的宿主交接闪烁。**
92
+ - 会话状态角标在挂载时同步声明主宿主身份,消除异步交接导致的状态闪烁与 Portal 重新渲染。
93
+ - 状态轮询在无激活视窗时平滑降频至 15 秒保活缓存,并在客户端插件卸载时完整清理定时器。
94
+ - **修复(mermaid):修复离屏/虚拟容器中 Dagre 测绘产生的 16x16 / 0x0 折叠 SVG。**
95
+ - 避免将尚未有几何尺寸的容器传递给 Mermaid 渲染,结合 `isInvalidOrCollapsedSvg` 智能识别并修复空图或折叠伪影。
96
+ - **修复(keychain):在 macOS 账号槽位创建与提交时即时初始化独立 Keychain。**
97
+ - 避免 macOS SecurityAgent 在后续刷新凭据或打开终端时弹出系统钥匙串确认弹窗。
98
+
99
+ ## 0.4.71 (2026-10-27)
100
+
101
+ ### English
102
+
103
+ - **Fix: restore Argon quota reporting for isolated Pro-tier accounts (PR #54 regression).**
104
+ - PR #54 established that retrieveUserQuotaSummary with the agy User-Agent returns the separate Gemini 4 Argon quota group for accounts on paid Pro/Ultra plans.
105
+ - Removed premature clearQuotaFamily(account.id, 'argon') in readCliUsageFamilies fast-reject branches, allowing isolated accounts to receive authentic Argon quota from Google's REST API.
106
+ - Stale/orphaned Argon entries on free-tier accounts are now cleared cleanly when an authoritative summary (CLI or REST) succeeds without an Argon quota group.
107
+ - **Feat(quota): organic randomized jitter on sequential multi-account polling.**
108
+ - Replaced the fixed 2000ms sleep between account checks with an organic 2000ms~3500ms randomized jitter delay (staggerJitterMs), avoiding rigid clock-tick request signatures against upstream endpoints.
109
+ - **Fix: every pool row displayed the same account's quota (2026-10-26 report).**
110
+ - Root cause: agy resolves its credential from the platform keystore (Windows Credential Manager, macOS Keychain, Linux Secret Service) BEFORE the per-HOME token file, and that store is a single per-user entry. Handing an isolated HOME to agy -p /usage therefore does not isolate the identity — the CLI always answers for the store's owner, so CLI-first polling filed the owner's numbers under every secondary row (all four rows showed 97% / 55% / 56% with identical reset instants).
111
+ - The CLI is now scoped to the account that can actually own that store, and everything else takes the REST path, which signs with each account's own token file and runs concurrently on every platform.
112
+ - Isolated accounts are rejected BEFORE any keystore read, so a poll no longer pays a PowerShell cold start per account; the owner itself is still proven by sameCredentialGrant, because a running secondary temporarily holds the slot and a CLI read would then return that secondary's numbers.
113
+
114
+ ### 中文
115
+
116
+ - **修复:恢复子账号(如 Pro 订阅账号)的 Argon 额度显示(PR #54 回归)。**
117
+ - PR #54 证明了发送 agy User-Agent 时,Google REST API retrieveUserQuotaSummary 会正常返回 Pro/Ultra 账号独立的 Gemini 4 Argon 额度组。
118
+ - 移除了 readCliUsageFamilies 快速拒绝分支中对 argon 的误清理,子账号回落走 REST 时可完整展示其真实的 Argon 额度。
119
+ - 免费账号或降级账号上残留的伪 Argon 额度,现在由权威汇总(CLI 或 REST 成功返回且不含 Argon 组)统一精准清理。
120
+ - **功能(quota):多账号顺序轮询增加有机随机抖动。**
121
+ - 账号间的固定 2000ms 错峰间隔升级为 2000ms~3500ms 随机抖动(staggerJitterMs),避免向 Google Cloud Code 发送过于机械刻板的定频网络请求。
122
+ - **修复:号池每一行都显示了同一个账号的额度(2026-10-26 反馈)。**
123
+ - 根因:agy 解析凭据时**优先读系统钥匙串**(Windows 凭据管理器 / macOS Keychain / Linux Secret Service),且该存储是「每个 OS 用户只有一条」。因此给 agy -p /usage 一个隔离 HOME 并不能隔离身份——CLI 永远回答存储主人的额度,CLI 优先轮询就把主人的数字写进了每个子账号行(四行全部 97% / 55% / 56%,重置时刻完全相同)。
124
+ - 现在 CLI 只用于「真正能拥有该存储」的那个账号,其余账号全部走 REST —— 用各自的 token 文件签名,全平台并发执行。
125
+ - 隔离账号在**读取钥匙串之前**就被快速拒绝,轮询不再为每个账号付一次 PowerShell 冷启动;持有者本身仍要过 sameCredentialGrant 校验,因为子账号运行期间会临时占用该槽,此时 CLI 会返回子账号的数字。
126
+
3
127
  ## 0.4.70 (2026-10-25)
4
128
 
5
129
  ### English
package/README.md CHANGED
@@ -152,6 +152,8 @@ dsh plugin --profile web add dsh-agy-link
152
152
  | `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | 存在未完成工具步骤(ACTIVE)时的空闲预算(分钟);`0` = 不抬高预算,卡死的工具按 `timeoutMs` 快速失败 |
153
153
  | `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | 会话 cwd | agy 工作区根目录(默认跟随当前会话工作区) |
154
154
  | `suppressAgyAutoUpdate` | `DSH_AGY_SUPPRESS_AUTOUPDATE` | Windows `true`,其他平台 `false` | 每次 spawn 前刷新 agy 的更新检查时间戳,阻断 `--bg-updater` 子进程链(Windows 闪窗根因)。关闭后 agy 恢复自动更新检查 |
155
+ | `autoWarmup` | `DSH_AGY_AUTO_WARMUP` | `false` | 7 天周配额自动预热(opt-in):周额度到达重置时间或冷启动时发送极小探活请求,提前激活 7 天计时器。开启后每 5 分钟巡检一次;该路径直连 Google 内部端点,请自行评估风控风险 |
156
+ | `warmupModels` | `DSH_AGY_WARMUP_MODELS` | `gemini-3.8-flash,claude-sonnet-4-6` | 自动预热使用的模型列表(逗号分隔);空数组表示不自动预热 |
155
157
 
156
158
  ---
157
159
 
@@ -330,6 +332,8 @@ dsh plugin --profile web add dsh-agy-link
330
332
  | `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | Idle budget while a tool step is ACTIVE (minutes); `0` keeps the normal `timeoutMs` budget so wedged tools fail fast |
331
333
  | `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | session cwd | Working directory root |
332
334
  | `suppressAgyAutoUpdate` | `DSH_AGY_SUPPRESS_AUTOUPDATE` | `true` on Windows, `false` elsewhere | Refreshes agy's update-check timestamp before every spawn so its `--bg-updater` child chain (the Windows console-flash root cause) never starts. `false` restores agy's own auto-update checks |
335
+ | `autoWarmup` | `DSH_AGY_AUTO_WARMUP` | `false` | Opt-in 7-day weekly quota warmup: sends a minimal probe when the weekly window has reset or is cold, activating the 7-day timer. Scans every 5 minutes; this path talks directly to Google's internal endpoints, so assess the risk-control tradeoff yourself |
336
+ | `warmupModels` | `DSH_AGY_WARMUP_MODELS` | `gemini-3.8-flash,claude-sonnet-4-6` | Model list used for warmup probes (comma-separated); an empty list disables automatic warmup |
333
337
 
334
338
  ---
335
339
 
package/dist/bridge.mjs CHANGED
@@ -1,14 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  // dsh-agy-link MCP bridge script: a minimal stdio MCP server with zero
3
- // dependencies. agy launches it per the workspace .mcp.json; it forwards
3
+ // dependencies. agy launches it from its MCP registry; it forwards
4
4
  // tools/list and tools/call to the plugin loopback endpoint whose URL and
5
- // token arrive via env. Protocol: newline-delimited JSON-RPC 2.0.
5
+ // token arrive via env. DSH_MCP_SESSION carries the spawning DSH session so
6
+ // the host can resolve the calling agent (issue #55).
7
+ // Protocol: newline-delimited JSON-RPC 2.0.
6
8
  import { request as httpRequest } from 'node:http'
7
9
  import process from 'node:process'
8
10
  import { createInterface } from 'node:readline'
9
11
 
10
12
  const URL_BASE = process.env.DSH_MCP_URL || ''
11
13
  const TOKEN = process.env.DSH_MCP_TOKEN || ''
14
+ const SESSION = process.env.DSH_MCP_SESSION || ''
12
15
  const PROTOCOL = '2024-11-05'
13
16
 
14
17
  function post(path, body) {
@@ -28,6 +31,7 @@ function post(path, body) {
28
31
  'Content-Type': 'application/json',
29
32
  'Content-Length': Buffer.byteLength(data),
30
33
  Authorization: 'Bearer ' + TOKEN,
34
+ ...(SESSION === '' ? {} : { 'X-DSH-Session': SESSION }),
31
35
  },
32
36
  timeout: 600000,
33
37
  });