dsh-agy-link 0.4.44 → 0.4.49
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 +210 -0
- package/README.md +1 -0
- package/dist/assets/mermaid.min.js +3636 -0
- package/dist/client.js +1948 -262
- package/dist/index.js +4957 -3033
- package/docs/KNOWN-GAPS.md +18 -0
- package/docs/README.en.md +1 -0
- package/docs/README.es.md +1 -0
- package/docs/README.pt-BR.md +1 -0
- package/docs/adr-012-account-pool.md +6 -2
- package/docs/merge-2026-10-13-review.md +102 -0
- package/package.json +1 -1
package/docs/KNOWN-GAPS.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Deliberate v1 boundaries and upstream-behavior notes.
|
|
4
4
|
|
|
5
|
+
## Platform limits
|
|
6
|
+
|
|
7
|
+
- **Windows: pool credential isolation is implemented by handing the shared
|
|
8
|
+
slot over (issue #45)** — agy on Windows resolves its Google credential from
|
|
9
|
+
ONE process-global Credential Manager slot `gemini:antigravity`
|
|
10
|
+
(go-keyring); `HOME`/`USERPROFILE`/`GEMINI_CLI_HOME` move files only. Rather
|
|
11
|
+
than pretending the pool is isolated, the plugin now owns the slot: the
|
|
12
|
+
primary credential is kept in a durable, identity-verified store
|
|
13
|
+
(`agy-accounts/.primary-credential.json`), and every run acquires the slot
|
|
14
|
+
through `acquireCredentialSlot` — a process-wide FIFO mutex that writes the
|
|
15
|
+
target account's verified credential into the slot, then restores the
|
|
16
|
+
primary's on release. `SlotUnavailableError` aborts a run instead of letting
|
|
17
|
+
it silently spend the wrong account when the primary cannot be verified.
|
|
18
|
+
Remaining boundary: the mutex is **per process**, so two DSH hosts (web +
|
|
19
|
+
headless) running agy at the same moment can still interleave slot writes;
|
|
20
|
+
keep `maxConcurrent` at 1 on Windows and avoid driving two hosts at once.
|
|
21
|
+
A cleaner upstream fix would be per-HOME keyring namespacing in agy.
|
|
22
|
+
|
|
5
23
|
## Not forwarded to agy
|
|
6
24
|
|
|
7
25
|
- **Images as true multimodal blocks** - agy print mode (`-p`) has no image
|
package/docs/README.en.md
CHANGED
|
@@ -52,6 +52,7 @@ In DSH, click the `AGY (n)` badge and choose **Add Account** to complete Google
|
|
|
52
52
|
| `defaultModel` | `DSH_AGY_DEFAULT_MODEL` | agy default | Default model slug |
|
|
53
53
|
| `defaultEffort` | `DSH_AGY_DEFAULT_EFFORT` | model default | `low`, `medium`, or `high` |
|
|
54
54
|
| `timeoutMs` | `DSH_AGY_TIMEOUT_MS` | `600000` | Activity watchdog timeout in ms |
|
|
55
|
+
| `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | Idle budget (minutes) while an agy tool step is still open; `0` = keep `timeoutMs` so a wedged tool fails fast |
|
|
55
56
|
| `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | session cwd | Workspace root |
|
|
56
57
|
|
|
57
58
|
## `/agy` commands
|
package/docs/README.es.md
CHANGED
|
@@ -52,6 +52,7 @@ En DSH, haga clic en la insignia `AGY (n)` y seleccione **Add Account** para com
|
|
|
52
52
|
| `defaultModel` | `DSH_AGY_DEFAULT_MODEL` | predeterminado de agy | Slug del modelo predeterminado |
|
|
53
53
|
| `defaultEffort` | `DSH_AGY_DEFAULT_EFFORT` | predeterminado del modelo | `low`, `medium` o `high` |
|
|
54
54
|
| `timeoutMs` | `DSH_AGY_TIMEOUT_MS` | `600000` | Timeout del watchdog en ms |
|
|
55
|
+
| `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | Presupuesto de inactividad (minutos) mientras un paso de herramienta sigue abierto; `0` = mantener `timeoutMs` |
|
|
55
56
|
| `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | cwd de la sesión | Raíz del workspace |
|
|
56
57
|
|
|
57
58
|
## Comandos `/agy`
|
package/docs/README.pt-BR.md
CHANGED
|
@@ -52,6 +52,7 @@ No DSH, clique no selo `AGY (n)` e selecione **Add Account** para concluir o log
|
|
|
52
52
|
| `defaultModel` | `DSH_AGY_DEFAULT_MODEL` | padrão do agy | Slug do modelo padrão |
|
|
53
53
|
| `defaultEffort` | `DSH_AGY_DEFAULT_EFFORT` | padrão do modelo | `low`, `medium` ou `high` |
|
|
54
54
|
| `timeoutMs` | `DSH_AGY_TIMEOUT_MS` | `600000` | Timeout do watchdog, em ms |
|
|
55
|
+
| `longToolIdleMinutes` | `DSH_AGY_LONG_TOOL_IDLE_MINUTES` | `240` | Orçamento de inatividade (minutos) enquanto um passo de ferramenta está aberto; `0` = manter `timeoutMs` |
|
|
55
56
|
| `workspaceRoot` | `DSH_AGY_WORKSPACE_ROOT` | cwd da sessão | Raiz do workspace |
|
|
56
57
|
|
|
57
58
|
## Comandos `/agy`
|
|
@@ -37,12 +37,16 @@ Spawning agy for Account $X$ simply injects `HOME=/path/to/~/.dsh/agy-accounts/a
|
|
|
37
37
|
### 2. Sticky Sequential Drain Strategy (按模型家族顺次耗尽)
|
|
38
38
|
- **Family-Scoped Cooldown**: Quota is tracked per model family (`google`, `anthropic`, `openai`). If Account A hits 429 on Claude 4.6, only Account A's `anthropic` family is marked in cooldown. Account A can still serve Gemini 3.7 Flash requests.
|
|
39
39
|
- **Sticky Affinity**: Requests stick to the first healthy account (e.g., Account A) to maximize conversation continuity and token caching.
|
|
40
|
-
- **Transparent Fallback**: When
|
|
40
|
+
- **Transparent Fallback**: When a request on Account A is refused for an account-scoped reason (429 / quota, region eligibility, transport-flavoured auth, soft capacity), the adapter records the cooldown or rotates the sticky pointer, and the SAME step continues on Account B — either through DSH's automatic retry (the first-span case) or by discarding the dead recording and re-assembling on the next account (the post-tool case). The user experiences no interruption and never resends.
|
|
41
|
+
- Account failover is bounded by the pool: DSH's retry budget is `min(enabled accounts - 1, 2)` retries, and the post-tool failover allows at most `enabled accounts - 1` re-spawns per session inside a 2-minute window. A deterministic (request-level) failure is never failed over, so a broken request cannot loop through the pool re-running its tools.
|
|
42
|
+
- A genuine sign-out (`AUTH`) is retryable only when the pool has another account that may still be signed in; the failed account is flagged `authRequired` and leaves rotation.
|
|
41
43
|
|
|
42
44
|
### 3. Cooldown & Reset Handling
|
|
43
45
|
- If the error contains a server reset time (or `Retry-After`), cooldown is set to `Date.now() + resetMs`.
|
|
44
|
-
- Default cooldown window is
|
|
46
|
+
- Default cooldown window is 15 minutes (`defaultCooldownMs`, tiered up to 60 minutes on consecutive 429s).
|
|
45
47
|
- Cooldown expires automatically; when Account A recovers, it resumes primary position.
|
|
48
|
+
- Soft capacity refusals ("model overloaded" / high traffic) NEVER set a cooldown: nothing was spent. They rotate the pointer and are retryable anyway, so an idle account can still serve the turn.
|
|
49
|
+
- "All accounts unavailable" reports the real state (N in cooldown, N signed out) with the earliest availability, which includes quota-window resets and not just cooldowns; a reset that is ≤ 20s away is waited out instead of failing the turn.
|
|
46
50
|
|
|
47
51
|
### 4. Optional Per-Account Proxy (防关联支持)
|
|
48
52
|
Each account can optionally specify a dedicated proxy URL (`socks5://...` or `http://...`). When set, `ALL_PROXY` / `HTTPS_PROXY` / `HTTP_PROXY` are scoped exclusively to that account's child process. If unconfigured, it inherits the global host environment proxy.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# 2026-10-13 两线合并评审清单
|
|
2
|
+
|
|
3
|
+
本次会话把「上游 main 线」与「被舍弃的工作区快照」两条分叉合并为一个可构建、可测试的状态。
|
|
4
|
+
本文是一次性评审依据:逐项列出**做了什么取舍、为什么、怎么改回去**。
|
|
5
|
+
|
|
6
|
+
## 1. 背景与根因
|
|
7
|
+
|
|
8
|
+
1. 你记忆里「已经修好」的 Windows 凭据隔离 + 客户端增强,**从未提交、从未推送**——它只存在于
|
|
9
|
+
`D:\proj\dsh-agy-link` 的未提交工作区里(v0.4.44 草案,2026-10-03 起草)。
|
|
10
|
+
2. `origin/main`(v0.4.46)**只包含那条警告横幅的披露逻辑**,没有任何真实隔离实现:
|
|
11
|
+
- `src/client/locales.ts` 的 `pool.winIsolationWarn` 文案
|
|
12
|
+
- `src/index.ts` 的 `credentialIsolationLimited` 状态字段
|
|
13
|
+
- `src/host/adapter.ts` 的 `warnOnce` 日志
|
|
14
|
+
- 全仓库没有 `src/host/wincred.ts` / `src/host/credential-slot.ts`
|
|
15
|
+
3. 运行中的 GUI 通过 **Junction** 直接吃本目录的 `dist/`:
|
|
16
|
+
`C:\Users\zand\.dsh\profiles\desktop\node_modules\dsh-agy-link -> D:\proj\dsh-agy-link`。
|
|
17
|
+
清理工作区 + `pnpm install` 触发 `prepare: npm run build` 后,`dist/` 由**上游源码**重建,
|
|
18
|
+
于是界面从「你的版本」切成了「上游版本」:横幅出现、样式回退。**源码一份没丢**。
|
|
19
|
+
|
|
20
|
+
## 2. 三方对象
|
|
21
|
+
|
|
22
|
+
| 角色 | 引用 | 内容 |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| 基线(第一父) | `main` = `b29e29b` | 上游 0.4.46(含 20 个提交) |
|
|
25
|
+
| 你的工作区快照(第二父) | `recovered/local-afternoon` = `b26271e` | 0.4.44 草案,+9452 / −80 |
|
|
26
|
+
| 合并结果 | `merge/restore-afternoon` | `140d257` 起的合并提交 |
|
|
27
|
+
|
|
28
|
+
相对 `main` 的净变更:**28 个文件、+3401 / −76**;新增 11 个文件:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
.npmrc scripts/repair-pool.mts
|
|
32
|
+
scripts/verify-credential-store.mts src/client/decisions.ts
|
|
33
|
+
src/client/images.ts src/host/credential-slot.ts
|
|
34
|
+
src/host/media-route.ts src/host/wincred.ts
|
|
35
|
+
test/client-enhancers.test.ts test/credential-slot.test.ts
|
|
36
|
+
test/media-route.test.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 3. 十处冲突的落定
|
|
40
|
+
|
|
41
|
+
| # | 文件 | 处理 | 理由 | 想改回去 |
|
|
42
|
+
| --- | --- | --- | --- | --- |
|
|
43
|
+
| 1 | `CHANGELOG.md` | 两边全保留;你的 0.4.44 草案提为顶栏 **0.4.47** 并加合并说明 | 历史不丢、本次发布有说明 | 直接编辑 |
|
|
44
|
+
| 2 | `package.json` | 取 main(**不加 `mermaid` 依赖**),版本 bump `0.4.47` | 上游改为内置 `assets/mermaid.min.js`,不需要 npm 依赖 | 加回依赖 |
|
|
45
|
+
| 3 | `assets/mermaid.min.js` | 取 main(3.57 MB 官方构建) | 与 main 的 `/plugins/agy-link/mermaid.min.js` 路由匹配 | 换回你的 4.37 MB 版 |
|
|
46
|
+
| 4 | `src/client/mermaid.ts` | 取 main(337 行,无 CDN 回退 + 错误炸弹清理 + `ctx.effect` 生命周期) | 你的 598 行版本已被上游同类修复覆盖 | 恢复快照文件 |
|
|
47
|
+
| 5 | `src/client/toolview.ts` | main 的 i18n `tv.delete` + 你的 `question` / `image` 卡片类型 | 两边都是增量,可兼得 | 直接编辑 |
|
|
48
|
+
| 6 | `src/client/index.ts` | main 的 `ctx.effect` 安装器 + 你的图片/决策增强(**已补真实 disposer**) | 保留 main 的重载不叠加 observer 契约 | 直接编辑 |
|
|
49
|
+
| 7 | `src/host/quota.ts` | main 的**异步** Windows 凭据读取 + 你的「持久存储优先」主账号解析;刷新写盘保留你的保形 `doc` 并补 main 的 `0600` | 你那份 `execFileSync` 会让事件循环冻结(上游专门修过);你的持久库逻辑是防串号关键 | 直接编辑 |
|
|
50
|
+
| 8 | `src/host/runner.ts` | 取 main(`nodeScriptEnv` / `ELECTRON_RUN_AS_NODE`) | 同上问题上游已有更完整修复 | 直接编辑 |
|
|
51
|
+
| 9 | `test/mapper.test.ts` | **两边用例全保留**(#43 思考横幅 + 你的图片重写) | 两者互不冲突 | 无需 |
|
|
52
|
+
| 10 | `test/proxy-keychain.test.ts` | 取 main | 与 main 的 kill 升级语义一致 | 恢复快照版 |
|
|
53
|
+
|
|
54
|
+
## 4. 语义变更(你已确认)
|
|
55
|
+
|
|
56
|
+
1. **删除 `credentialIsolationLimited` 警告**:状态字段、adapter `warnOnce`、设置面板横幅、
|
|
57
|
+
四语言文案全部移除。理由:凭据槽交接恢复后轮巡是真隔离,横幅已是假陈述。
|
|
58
|
+
`docs/KNOWN-GAPS.md` 改写为「已实现交接 + 剩余边界」。
|
|
59
|
+
2. **`node:test` 下跳过真实凭据槽**(检测 `NODE_TEST_CONTEXT`):你的严格拒绝语义与上游
|
|
60
|
+
「额度耗尽自动转移账号」测试在 Windows 上互斥;若不跳过,`pnpm test` 会往**真实凭据管理器**
|
|
61
|
+
写测试凭据。生产的严格语义(`SlotUnavailableError`:无法验证主账号 / 副账号无凭据 /
|
|
62
|
+
同一授权)**完整保留**;`test/credential-slot.test.ts` 仍通过注入 IO 直测交接逻辑。
|
|
63
|
+
|
|
64
|
+
## 5. 被取代或删除的内容(知情项)
|
|
65
|
+
|
|
66
|
+
| 内容 | 去向 | 说明 |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `src/client/mermaid.ts`(你的 598 行) | 未进入合并 | 上游同类修复已覆盖(`MERMAID_CSS` 抑制 + `cleanupTempElements` 清扫) |
|
|
69
|
+
| `test/client-enhancers.test.ts` 内 5 个 mermaid 用例 | 已删除 | 随上一条;保留图片相关用例 |
|
|
70
|
+
| `quota.ts` 中经 `wincred` 的同步 CredRead | 改用 main 异步实现 | `wincred.ts` 仍用于槽交接与系统代理探测 |
|
|
71
|
+
| 4 条 `pool.winIsolationWarn` 文案 | 已删除 | 横幅移除后成为死数据 |
|
|
72
|
+
|
|
73
|
+
## 6. 保留清单
|
|
74
|
+
|
|
75
|
+
**来自 main(上游)**:适配器 spawn 窗口槽位归属 try/finally、异步钥匙串/凭据管理器读取、
|
|
76
|
+
桌面端思考可见性 #43、内置 mermaid 渲染器(无 CDN)、模型可见性开关、`prepare` 构建、
|
|
77
|
+
账号池/数据加固、`docs/KNOWN-GAPS.md` 框架。
|
|
78
|
+
|
|
79
|
+
**来自你的快照**:`credential-slot.ts`(持久主凭据库 + 身份校验 + 进程级 FIFO 互斥 +
|
|
80
|
+
`SlotUnavailableError`)、`wincred.ts`(CredRead/CredWrite/CredDelete + WinINet 代理探测)、
|
|
81
|
+
`media-route.ts` + `images.ts` + `decisions.ts`(本地图片路由 / 灯箱 / 决策芯片)、
|
|
82
|
+
`repair-pool.mts`、`verify-credential-store.mts`、`.npmrc`、`.gitignore` 的 `Microsoft/`、
|
|
83
|
+
以及 4 个测试文件(`credential-slot` / `media-route` / `client-enhancers` / `mapper` 图片用例)。
|
|
84
|
+
|
|
85
|
+
## 7. 验证
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
pnpm run check -> exit 0(0 错误)
|
|
89
|
+
pnpm run build -> exit 0(dist/client.js 187KB、dist/index.js 1.32MB、dist/assets/)
|
|
90
|
+
pnpm test -> exit 0(31 个测试文件、328 用例通过、0 失败)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`dist/` 已由合并后的源码重建。
|
|
94
|
+
|
|
95
|
+
## 8. 生效方式与后续
|
|
96
|
+
|
|
97
|
+
- **客户端半**:刷新页面即生效——`dist/client.js` 中已无 `win-isolation` 渲染,横幅不会再出现。
|
|
98
|
+
- **宿主半**:需要**重启 DSH / 重载插件**。当前 `GET /plugins/agy-link/status` 仍返回
|
|
99
|
+
`credentialIsolationLimited`,证明运行中的宿主进程还是旧代码;宿主半决定凭据交接是否真的生效。
|
|
100
|
+
- **未做**:没有 `push`、没有打 tag、没有发布(遵循 AGENTS.md:发布需你显式下令)。
|
|
101
|
+
- **已知边界**:凭据槽互斥锁是**进程级**的——web 与 headless 同时驱动 agy 仍有交叉写风险;
|
|
102
|
+
Windows 上建议 `maxConcurrent=1`,并避免两个宿主同时跑。彻底解决需上游 agy 按 HOME 命名 keyring。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agy-link",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.49",
|
|
4
4
|
"description": "Google Antigravity (agy CLI) models for DeepSeek Harness — stream Gemini/Claude/GPT-OSS subscriptions into DSH with thinking, tool activity, token usage and in-GUI Google OAuth login.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|