dsh-bundle-antigravity-host 0.1.23 → 0.1.25

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.
Files changed (75) hide show
  1. package/README.md +108 -303
  2. package/dist/adapter/antigravity-adapter.d.ts +24 -3
  3. package/dist/adapter/antigravity-adapter.js +169 -33
  4. package/dist/adapter/antigravity-adapter.js.map +1 -1
  5. package/dist/adapter/continuation-state.d.ts +8 -0
  6. package/dist/adapter/continuation-state.js +45 -0
  7. package/dist/adapter/continuation-state.js.map +1 -0
  8. package/dist/adapter/image-content.d.ts +13 -0
  9. package/dist/adapter/image-content.js +71 -0
  10. package/dist/adapter/image-content.js.map +1 -0
  11. package/dist/adapter/permission-diagnostic.d.ts +2 -2
  12. package/dist/adapter/permission-diagnostic.js +1 -1
  13. package/dist/adapter/permission-diagnostic.js.map +1 -1
  14. package/dist/adapter/permission-handoff.js +21 -7
  15. package/dist/adapter/permission-handoff.js.map +1 -1
  16. package/dist/adapter/prompt-transcript.d.ts +9 -14
  17. package/dist/adapter/prompt-transcript.js +17 -14
  18. package/dist/adapter/prompt-transcript.js.map +1 -1
  19. package/dist/adapter/prompt-turn.d.ts +16 -9
  20. package/dist/adapter/prompt-turn.js +69 -53
  21. package/dist/adapter/prompt-turn.js.map +1 -1
  22. package/dist/adapter/tool-args.d.ts +39 -0
  23. package/dist/adapter/tool-args.js +113 -0
  24. package/dist/adapter/tool-args.js.map +1 -0
  25. package/dist/bridge/mcp-bridge.d.ts +10 -0
  26. package/dist/bridge/mcp-bridge.js +24 -2
  27. package/dist/bridge/mcp-bridge.js.map +1 -1
  28. package/dist/client.js +237 -71
  29. package/dist/index.d.ts +6 -0
  30. package/dist/index.js +310 -170
  31. package/dist/index.js.map +1 -1
  32. package/dist/pool/pooled-adapter.d.ts +49 -0
  33. package/dist/pool/pooled-adapter.js +266 -0
  34. package/dist/pool/pooled-adapter.js.map +1 -0
  35. package/dist/protocol/agent-link.d.ts +4 -0
  36. package/dist/protocol/agent-link.js +53 -17
  37. package/dist/protocol/agent-link.js.map +1 -1
  38. package/dist/quota/control.d.ts +7 -1
  39. package/dist/quota/control.js +9 -6
  40. package/dist/quota/control.js.map +1 -1
  41. package/dist/quota/quota-remote.d.ts +7 -1
  42. package/dist/quota/quota-remote.js +6 -4
  43. package/dist/quota/quota-remote.js.map +1 -1
  44. package/dist/runtime/agy-cli.d.ts +2 -2
  45. package/dist/runtime/agy-cli.js +16 -10
  46. package/dist/runtime/agy-cli.js.map +1 -1
  47. package/dist/runtime/binary.d.ts +76 -22
  48. package/dist/runtime/binary.js +221 -47
  49. package/dist/runtime/binary.js.map +1 -1
  50. package/dist/runtime/catalog-cache.js +23 -3
  51. package/dist/runtime/catalog-cache.js.map +1 -1
  52. package/dist/runtime/credentials.d.ts +2 -0
  53. package/dist/runtime/credentials.js +21 -4
  54. package/dist/runtime/credentials.js.map +1 -1
  55. package/dist/runtime/lifecycle.d.ts +68 -0
  56. package/dist/runtime/lifecycle.js +147 -0
  57. package/dist/runtime/lifecycle.js.map +1 -0
  58. package/dist/runtime/proxied-fetch.d.ts +14 -7
  59. package/dist/runtime/proxied-fetch.js +76 -18
  60. package/dist/runtime/proxied-fetch.js.map +1 -1
  61. package/dist/runtime/proxy-env.js +4 -11
  62. package/dist/runtime/proxy-env.js.map +1 -1
  63. package/dist/runtime/quota.d.ts +5 -1
  64. package/dist/runtime/quota.js +27 -28
  65. package/dist/runtime/quota.js.map +1 -1
  66. package/dist/runtime/redact.js +3 -0
  67. package/dist/runtime/redact.js.map +1 -1
  68. package/dist/settings.d.ts +20 -0
  69. package/dist/settings.js +6 -1
  70. package/dist/settings.js.map +1 -1
  71. package/docs/changelog.md +67 -0
  72. package/docs/configuration.md +71 -0
  73. package/docs/development.md +114 -0
  74. package/docs/reference.md +189 -0
  75. package/package.json +7 -1
package/README.md CHANGED
@@ -1,310 +1,115 @@
1
- # dsh-bundle-antigravity-host
2
-
3
- DeepSeek Harness (DSH) host bundle:把 Google 官方 Antigravity ACP server
4
- (`agy-acp-server`,Gemini 背后的 agent)作为 LLM provider 接入 DSH。
5
-
6
- 工作方式:
7
-
8
- - 插件通过宿主注入的 `ctx.subprocess` 服务以 stdio 启动官方 ACP server,
9
- 并以 Agent Client Protocol v1(JSON-RPC over newline-delimited JSON)通信。
10
- - 本包通过 `src/index.ts` 向 `ctx.llm` 注册 provider `antigravity-acp`
11
- 的 `LlmAdapter`。
12
- - 工具执行留在 DSH 侧:进程内私有 `127.0.0.1` loopback MCP 桥把当前
13
- DSH 工具 schema 交给官方 agent;`tools/call` 被 park 后以 DSH
14
- `tool-call` 结束本轮,下一轮带着 tool result 续同一 ACP prompt。
15
- - 若官方在 MCP 调用之前要求 ACP 授权,插件可把可解析的当前目录工具请求
16
- 转为普通 DSH `tool-call`;**官方原始调用仍被拒绝**,工具审批、参数校验和
17
- 沙箱执行由 DSH 负责。该路径每回合只接管一个请求,回收旧官方进程,收到
18
- DSH 结果后按完整历史重建 ACP 回合,不在旧 prompt 上继续执行。
19
- - 登录态由本包**导入**:读本机官方 CLI 已登录的
20
- `~/.gemini/antigravity-cli/antigravity-oauth-token`(只读),换发一颗
21
- access token 后落成官方 server 认的 `~/.gemini/antigravity-acp/acp_token.json`,
22
- 并补写 `settings.json` 的 `auth.type = oauth-personal`。因此**不会拉起浏览器
23
- 登录页**,也不再发 `authenticate` 请求(该请求在没有交互式浏览器时会一直挂着)。
24
- 只有导入不到任何登录态时才回退到官方浏览器授权流程。
25
-
26
- 安全边界(自动下载路径):
27
-
28
- - 仅允许 `https://dl.google.com`,拒绝任何 HTTP 重定向;
29
- - zip 解压前逐条目校验路径(拒绝绝对路径、`..` 穿越、盘符/反斜杠异常路径);
30
- - 官方未提供校验和,因此不伪造任何签名/校验和声明;
31
- - 下载先落临时文件,成功后原子重命名,失败清理残留。
32
-
33
- 配置项:`binaryPath`(手动指定,优先级最高)、`autoDownload`(默认开启)、
34
- `extraArgs`、`acpVersion`、`requestTimeoutMs`、`authTimeoutMs`、
35
- `promptTimeoutMs`、`bridgeParkSettleMs`、`preferredModel`、`proxyUrl`、
36
- `proxyBypass`。
37
- 环境变量:`AGY_ACP_BIN`(二进制覆盖)、`AGY_ACP_URL`(下载 URL 覆盖,
38
- 供未验证平台组合使用)、`AGY_ACP_HOME`(可执行文件安装根目录覆盖)。
39
-
40
- ## 二进制装在哪里(重要)
41
-
42
- 自动下载的官方 server **不放在 DSH home 下**,默认装到用户级应用数据目录:
43
-
44
- - Windows:`%LOCALAPPDATA%\dsh-antigravity-host\<版本>\`
45
- - macOS / Linux:`$XDG_CACHE_HOME/dsh-antigravity-host/<版本>/`,其次 `~/.cache/...`
46
-
47
- 原因不是洁癖,而是**功能必需**:DSH 会把 `$DSH_HOME`(默认 `~/.dsh`)整棵树标为
48
- **Low 强制完整性**(`icacls` 可见 `Mandatory Label\Low Mandatory Level`),而 Windows
49
- 在创建进程时**会采用映像文件的强制完整性标签**。装在 `~/.dsh` 下的 exe 因此只能以
50
- LOW 运行,受 MIC「禁止向上写」约束,写不进中等完整性的 `~/.gemini/antigravity-acp/`:
51
- 官方 server 保存凭据用的 `tempfile.NamedTemporaryFile` 会在 `PermissionError` 上
52
- 无限重试,`session/new` 永不返回——表现为「Gemini 一直不回话」且没有任何报错。
53
-
54
- 插件在启动前会**只读**跑一次 `icacls` 探测该标签;一旦命中就直接报
55
- `AGY_BINARY_LOW_INTEGRITY` 并给出修法,而不是把卡死留给用户(探测本身失败不会阻断
56
- 启动)。手动指定 `binaryPath` 时请同样避开带该标签的目录。
57
-
58
- ## 出网代理
59
-
60
- 官方 `agy_acp_server` 自己连 Google(OAuth 与 Cloud Code Assist),而宿主
61
- `subprocess` 会 scrub 父进程环境,所以代理只能由本包显式注入子进程:
62
-
63
- - `proxyUrl`:如 `http://127.0.0.1:7890`;缺 scheme 按 `http` 处理,
64
- 支持 `http`/`https`/`socks5`/`socks5h`/`socks4`。留空继承宿主代理环境变量,
65
- 宿主也未配置时才直连;清空此项不等于强制关闭宿主代理。
66
- - `proxyBypass`:逗号分隔的排除列表,用户条目会与本机地址合并。
67
- - 注入 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 与对应小写键,
68
- Windows 上运行的 Python 栈读大写,小写键覆盖 POSIX 风格读取者。
69
- - `localhost`、`127.0.0.1`、`::1` 始终排除:私有 MCP 桥与 OAuth 回调都在
70
- loopback,走了代理工具回合会直接卡死。
71
- - 地址非法时在 spawn 之前报 `AGY_INVALID_PROXY`,不会先启动再失败。
72
- - 代理只在子进程启动时读取,改配置后需完全重启 Desktop(或让官方进程退出)。
73
-
74
- ## 模型目录
75
-
76
- ACP v1 没有「不建会话、不认证」就能读到模型目录的方法:`InitializeResponse`
77
- 只带 `protocolVersion` / `agentCapabilities` / `authMethods` / `agentInfo`,
78
- `configOptions` 只出现在会话响应与 `config_option_update` 里。因此:
79
-
80
- - 不再展示「首次对话登录」占位模型。没有缓存时目录可以为空,通过设置页显式
81
- 连接 ACP 或「一键拉取模型」获得目录,不必先发送聊天消息。
82
- - `preferredModel` 可从目录选择或手填自定义 ID,保存后优先列出;目录外 ID 明确
83
- 标记为用户配置、尚未验证。不会自动替换当前会话的已选模型。
84
- - 旧会话的 `server-default` 路由仍兼容:映射到 `preferredModel`,留空沿用官方默认,
85
- 但不再广告为新选择项。
86
- - 观测到的目录会写入 `$DSH_HOME/cache/antigravity-acp/catalog.json`(只含
87
- id/name/description/contextWindow,不含任何凭据),重启后用它兜住选择器;ACP server 版本变化
88
- 或文件损坏即失效;没有其它来源时目录为空。
89
- - **家族折叠 + 思考强度路由**(2026-10-16 用户指示):官方把思考强度编码进
90
- 模型 id(`claude-opus-5-5-{low,medium,high}`),但模型选择**只出家族一行**
91
- (`claude-opus-5-5`「Claude Opus 5.5」),强度由 DSH 的思考强度菜单(低/中/高)
92
- 决定,路由到对应档位模型(选「高」→ `claude-opus-5-5-high`;未选走默认档位
93
- `medium`,与官方默认 `Gemini 3.8 Flash (Medium)` 一致)。家族来源是会话观测
94
- 目录与官方 CLI 只读 `agy models` 清单(2026-10-16 授权「不 wrap agy CLI」
95
- **仅限只读取数用途**,缓存 `cli-models.json`)折叠去重;`gpt-oss-120b` 整族
96
- 排除(临近下架,用户指示不进选择器)。配置里显式钉住档位 id(如
97
- `gemini-3.8-flash-high`)且未选强度时,尊重钉住的档位。
98
- - **上下文容量**:官方目录不报告 context window,本包不填猜测值;首个回合收到
99
- 官方 `usage_update.size`(协议定义即 total context window size)后,把实测值
100
- 写进 `resolveModel().context` 并随目录落盘(目录条目是官方档位 id,落盘时按家族
101
- id 对齐,折叠前后都能读回),压缩引擎由此可量化上下文,不再每步报
102
- `no context capacity`。首轮回话之前仍是未知。
103
-
104
- ### 请求项映射
105
-
106
- ACP v1 没有采样参数通道,以下请求项的处理是明确的:
107
-
108
- | 请求项 | 行为 |
109
- | --- | --- |
110
- | `reasoningEffort` | **路由键**(不是不支持项):低/中/高 → 家族的 `-low`/`-medium`/`-high` 档位模型;家族缺该档位时取最接近档位。 |
111
- | `maxTokens` | **静默忽略**(输出上限由官方 agent 自己的会话配置决定)。宿主的会话标题等内建流程固定携带它,硬拒绝会让这些功能永久失败。 |
112
- | `temperature` / `stop` | 抛 `UNSUPPORTED_OPTION`:用户显式要求的效果无法兑现,不假装接受。 |
113
-
114
- ## 稳定性与诊断
115
-
116
- - **ACP 权限与 DSH 审批分层**:插件从不选择 ACP 的 `allow_once` 或 `allow_always`。
117
- 官方 1.4.0 的 `_meta.mcp` 来自参数信封,并非可靠执行身份;插件只用它解析一个
118
- **不可信的 DSH 工具请求**,且必须命中当前会话、当前桥名与当前工具目录,参数包装一致。
119
- 请求交给 DSH 后,官方原始调用被拒绝,旧桥凭证撤销、进程回收;重复或迟到请求不能
120
- 重复投递。DSH 工具结果的调用 id 和 `isError` 随完整历史进入新 ACP 会话,DSH 的拒绝
121
- 不会变成 ACP 自动放行。代价是这类调用每次重建回合,有额外启动开销。
122
- 无法解析的请求仍拒绝,不按标题或原始参数猜测授权,也不使用全局自动批准模式。
123
- 权限诊断只记录固定字段存在性、匹配关系与选项种类,不记录标题、调用 id、参数正文、
124
- 路径值或令牌。`Denied by user`/`pre-tool hook` 单独出现不能证明是 DSH 沙箱拒绝;
125
- 日志会区分插件拒绝与已转交 DSH。纯文本回复成功不代表真实工具链路已验收。
126
- - 主对话与后台标题可以并发调用同一个 provider。适配器在首次异步启动前占位、
127
- 串行调度;工具 park 期间保留主回合所有权,标题等待,不能覆盖当前回合或撤销工具桥。
128
- 同会话同步压缩则走放弃旧 prompt、按完整历史重建的兜底,避免等待自身工具结果而死锁。
129
- - 官方返回 `end_turn` 却没有可见文本或工具调用时,返回 `AGY_EMPTY_RESPONSE`,
130
- 不把空白、仅思考或仅进度通知当成成功回复。回合日志区分 `purpose`、文本/思考字符数与结束原因,
131
- 不记录回复正文。
132
- - MCP 调用在入桥时重新核对当前工具目录,未知或已撤销的工具直接返回错误,不进入
133
- DSH 工具执行队列;每个新 ACP 回合轮换 token 与授权代次,旧通道不能向新回合投递调用。
134
- MCP 会话通道按回合回收:新回合开始时关闭上一回合的全部通道(未完成 initialize 的
135
- 请求也会被就地收尾),通道数不随回合累积。
136
- - `finish(tool-calls)` 只封住当前 DSH 输出,不代表官方 prompt 结束。封口后到达的
137
- 调用与文本暂存到续轮,避免聚合窗口之外的并发调用丢失;等待工具期间仍响应取消。
138
- - 失败或取消会撤销桥授权,经宿主 `ctx.subprocess` 回收该连接的受管进程。
139
- 下一回合等待回收完成;无法确认退出时拒绝继续,不把本地 finish 当成后台已停止。
140
- 这是协议与进程生命周期保护,**不是 OS 文件系统沙箱**,不扩大原生工具权限。
141
-
142
- - `ensureAcpRuntime` 是 single-flight:并发首轮只 spawn 一条官方进程、只做一次
143
- `authenticate`,不会留下 dispose 杀不到的孤儿进程,也不会重复弹登录。
144
- - 官方 stderr 含**完整 OAuth 授权 URL**(`state`、`code_challenge` 等)。本包在把
145
- stderr 写进 `LlmError` 之前统一脱敏:URL userinfo 与敏感 query 参数一律打码,
146
- 非凭据上下文保留以便诊断。
147
- - 认证等待超时时不再回显授权 URL,而是提示「官方进程已打开 Google 登录页,
148
- 请在浏览器里完成授权」。认证超时使用独立错误码 `AGY_AUTH_TIMEOUT`,与普通
149
- 请求超时区分。
150
- - 本 provider **不声明任何可重试失败码**。宿主若消费重试策略会在失败步骤上整步
151
- 重放 `stream()`:握手失败会重复 spawn,认证超时会重复弹登录,`session/prompt`
152
- 超时会新建会话并重放全部历史(可能造成重复内容与重复工具调用)。三类都不可
153
- 安全重放,因此宁可一次不重试。
154
-
155
- ## 设置卡片
156
-
157
- 卡片走宿主真实存在的通道:`remote.settings.describe()` 读取、`remote.settings.mutate()`
158
- 写入(改 `preferredModel` / `proxyUrl` / `proxyBypass`),`remote.llm.listProviders()`
159
- 确认路由是否注册。宿主没有 `remote.llm.listModels`,本包通过自有
160
- `remote.agyQuota.models` 提供目录;强制刷新走官方 `agy models`,失败保留旧目录并显示错误。
161
-
162
- - **连接 / 登录 ACP**:需用户确认,复用本机官方登录态,必要时由官方进程打开浏览器
163
- 授权。只创建空工具会话验证连接,不发送模型 prompt;支持取消,结束后回收独立进程。
164
- 对话/工具回合进行中拒绝登录,不抢占当前聊天。状态只是最近一次连接验证,不代表
165
- CLI 已登录,也不展示任何令牌或账号凭据。
166
- - **CLI 登录独立**:额度与 CLI 模型目录仍需在官方 `agy` 中完成登录;不假装 ACP
167
- 登录同时解决两份登录态,不实现未经核实的 CLI 无头登录。
168
- - **额度手动刷新**:设置页与药丸共用读取器,刷新结果同步;失败、缓存及未知有明确标记。
169
- - **模型选择**:目录下拉框与手填 ID 共用 `preferredModel`,点击保存生效。不提供模型
170
- 删除、禁用或账户切换,也不自动开启 AI Credits 付费。
171
-
172
- 客户端插件的 `inject` 必须逐个声明用到的 remote 命名空间
173
- (`remote`、`remote.settings`、`remote.llm`):宿主把每个命名空间做成独立服务,
174
- 漏声明时连读属性都会抛 `cannot get property "remote.<ns>" without inject`,
175
- 击穿 `settings.section` 卡片。卡片对属性读取异常一律降级为卡内可读错误,
176
- 不再让异常穿出组件。
177
-
178
- ## 额度监控(模型选择器旁用量药丸)
179
-
180
- 选中 `antigravity-acp` 的模型时,输入区模型选择器**左侧**出现用量药丸
181
- (`conversation.input.right` 槽,宿主 InputBar 把它渲染在模型选择器之前;
182
- 实现手法参考 dsh-subusage 的同位置药丸)。药丸本身只有当前模型所属额度组的
183
- 迷你条(每个窗口一条),悬浮与无障碍标签提供窗口和百分比,不再显示服务商文字摘要。
184
- Gemini、Claude/GPT、Gemini 4 Argon 分开匹配,同 provider 切换模型也立即切换额度条。
185
- 未知自定义型号或旧 `server-default` 不借用其它模型的数字,而显示未知符号。
186
-
187
- 展开面板固定展示三个额度组,缺少的数据标为未提供;展示每窗剩余百分比、重置时间、
188
- 当前模型标记、缓存状态、更新时间和刷新按钮。适配深浅主题,支持 Escape / 外部点击关闭。
189
- AI Credits 余额通过官方 `agy -p /credits --output-format json` 读取,取
190
- `command.data.remaining_credits`,可选套餐名为 `plan_name`。只接受成功的 credits
191
- 本地报告与非负安全整数;真实零余额显示 0,缺字段/非法数字不转成零。
192
-
193
- 余额与套餐额度分别缓存、分别标记失败和更新时间,共用刷新按钮。暂时查询失败可显示
194
- 旧余额并明确标为缓存;官方明确不提供账户信息时撤下旧值。余额失败不影响正常模型
195
- 额度,额度失败也不掩盖有效余额。没有 CLI 时余额标为未提供,不从 HTTP 配额推算。
196
- 不会展示未经核验的升级链接,也不会开启 `useG1Credits` 付费回退。
197
-
198
- 2026-10-22 已用本机官方 CLI 实测 `/credits`:退出码 0、`status: SUCCESS`、
199
- `command.name: credits`,金额为 number,`num_turns: 0`、`usage.total_tokens: 0`。
200
- 该无头契约由本机实现与真实回包补充核验,官方 TUI 文档本身不完整覆盖其 JSON 接口;
201
- 不据此保证所有旧版 CLI 都支持,旧版本/无信息/请求失败会显式显示状态。
202
-
203
- UI 使用宿主 React 18.3.1,生命周期依照 [React 18 文档](https://18.react.dev/reference/react/useEffect)。
204
- CLI 登录与余额限制参见官方 [安装与认证](https://antigravity.google/docs/cli/install.md)、
205
- [无头模式](https://antigravity.google/docs/cli/headless.md) 和 [AI Credits](https://antigravity.google/docs/cli/commands/credits.md)。
206
- 可运行 `node scripts/preview-ui.mjs` 生成离线模拟预览;它不访问宿主页面、不执行登录,不能替代真实 GUI 验收。
207
-
208
- 取数链路(Host 侧 `remote.agyQuota.read`):
209
-
210
- 1. **首选官方 CLI 的只读额度查询**:`agy -p /usage --output-format json`(slash
211
- 命令由 CLI 本地处理,实测 `num_turns: 0`、`total_tokens: 0`,无模型回合),
212
- 结果取 `command.data.groups[].buckets[]`(`window`/`remaining_fraction`/
213
- `reset_time`)。CLI 路径可用 `AGY_CLI_BIN` 覆盖,缺省按
214
- `%LOCALAPPDATA%\agy\bin\agy.exe` 等默认位置探测。
215
- 2. 余额独立执行 `agy -p /credits --output-format json`,与套餐额度并发取数,各有
216
- 45 秒超时。多视图并发刷新合并为一轮,每个命令各执行一次;有效缓存不重复取数。
217
- 3. 无官方 CLI 时仅套餐额度退回 Cloud Code Assist HTTP 线(读 `antigravity-oauth-token`
218
- → 过期时内存内换发 → `loadCodeAssist` → `retrieveUserQuotaSummary`);余额不猜测回退接口。
219
-
220
- 取数边界:
221
-
222
- - CLI 取数仅使用 `/usage`、`/credits` 和 `models`,不发送聊天或修改付费设置;
223
- 子进程一律经 DSH 的 `ctx.subprocess`,环境和超时沿用同一套受管通道。
224
- - HTTP 额度回退对登录态只读,换发出的 access token 仅在内存里用;
225
- CLI 通道不由插件直接读写凭据,官方 CLI 自行管理其认证状态;
226
- - token 材料不进快照、不进错误文本、不进日志(错误统一过 `redactSensitiveText`,
227
- 含 `Bearer <token>` 打码);
228
- - 取数失败折叠成 `status: 'error'` 的可读快照,不把异常抛穿到界面。
229
-
230
- 实测状态(2026-10-16,本机账户,真实跑通):官方 CLI 额度查询解析出 3 组额度窗
231
- (Gemini Models / Claude and GPT models / Gemini 4 Argon,weekly 与 5h 窗、
232
- 剩余百分比与重置时间齐全)。Cloud Code Assist HTTP 线是 **Gemini Code Assist
233
- (企业授权产品)**:本账户 `retrieveUserQuotaSummary` 403「no valid license of
234
- this product (#3501)」,仅作备用。原生 gRPC 接口
235
- `google.gca.aicode.v1main.JetskiRemoteAgentProxyService/GetUserQuotaSummary`
236
- 已定位(宿主 `aicode.googleapis.com:443`)但服务端路由未接通,记录备查。
237
-
238
- ## 宿主(DSH Core)兼容性声明
239
-
240
- 宿主在**安装/启用时**会校验插件 manifest 里的 DSH 版本要求,不通过就拒绝安装
241
- (`ManagementFailure(incompatible-version)`,诊断文本以 `dsh: installation rejected:`
242
- 开头)。规则(读自宿主 `@deepseek-ai/dsh-app-boot` 的 `evaluatePluginCompatibility`):
243
-
244
- - 若声明了 `engines.dsh`,**该范围单独决定**,`peerDependencies` 一律忽略;
245
- - 否则逐个校验 `peerDependencies` 中名为 `@deepseek-ai/dsh` 或以 `@deepseek-ai/dsh-`
246
- 开头的项,其余包(含 `@deepseek-ai/cordis`)**不参与**该判定;
247
- - 比较对象是**运行时版本**,取 `@deepseek-ai/dsh-app-boot` 自身 `package.json` 的
248
- `version`(即实际加载的 Core 版本,不是壳版本、也不是任何全局 CLI 版本),
249
- 且按 `includePrerelease: true` 参与范围匹配。
250
-
251
- 本包当前声明(0.1.22):
252
-
253
- | peer | 范围 | 说明 |
254
- |---|---|---|
255
- | `@deepseek-ai/dsh-llm` | `>=0.2.0-rc.1 <0.2.1-0 \|\| >=0.2.1-0 <0.3.0-0` | 参与宿主校验 |
256
- | `@deepseek-ai/dsh-subprocess` | 同上 | 参与宿主校验 |
257
- | `@deepseek-ai/dsh-typert-protocol` | 同上 | 参与宿主校验 |
258
- | `@deepseek-ai/cordis` | `~4.0.4 \|\| 4.0.5-alpha.1 \|\| 4.0.5-alpha.2` | 宿主不校验,仅供 pnpm peer 解析 |
259
-
260
- 0.1.10 及更早版本把三个 `dsh-*` peer 写成了逐版本枚举(止于 `0.2.1-alpha.3`),
261
- 在宿主升到 `0.2.1-alpha.4` 后判定为不兼容;0.1.11 换成上面这条宽范围
262
- (与社区插件 `dsh-subusage` 0.13.4 一致),对 `0.2.1-alpha.x`、`0.2.2` 均为真,
263
- 对 `0.3.0-0` 及以后为假。
264
-
265
- 若宿主将来越过该范围:可以更新本包的范围,或在插件管理器 / `dsh plugin allow-version`
266
- 里为**精确的 name@version + 精确运行时版本**授予豁免(豁免记录在 profile 的
267
- `compatibility.json`)。豁免是显式接受风险,不是默认恢复步骤。
268
-
269
- 契约面(非声明面)的核对状态:以宿主 0.2.1-alpha.4 的实际产物逐项对比过——
270
- `dsh-subprocess` 与 `cordis` 的类型声明逐字节相同;`dsh-llm` 只有新增可选成员
271
- (`imageRequestTarget`、`defaultBaseURL` 等,基类提供默认实现);`dsh-typert-protocol`
272
- 新增 `resources`/`principal` 等可选访问控制面,`register(contribution)` 签名未变,
273
- 本包用的 contribution 形态(`{package, face, schemas, model, invocations}`)与同宿主上
274
- 可用的 `dsh-subusage` 0.13.4 完全一致;客户端依赖的 `conversation.input.right` /
275
- `conversation.input.model` slot、`__ModuleLoader__`、`listProviders` 在新壳中均存在。
276
- 开发依赖已对齐宿主版本并精确锁定(`dsh-llm` / `dsh-subprocess` / `dsh-typert-protocol`
277
- = `0.2.1-alpha.4`,`cordis` = `4.0.5-alpha.2`),`npm run check`(320 测试 / 21 文件 +
278
- 类型检查 + 构建)在该版本类型上全绿。**未做**:真机安装 0.1.22 后的 GUI 验收
279
- (对话与额度药丸)。
280
-
281
- ## 安装参考
282
-
283
- 通用 CLI 示例(`web` 只是文档用的 profile 名,不是本机 Desktop):
284
-
285
- ```sh
286
- dsh plugin --profile web add ./dsh-bundle-antigravity-host-0.1.22.tgz
1
+ <div align="center">
2
+
3
+ # Antigravity ACP for DSH
4
+
5
+ **在 DSH 里使用 Antigravity 模型,工具仍交给 DSH。**
6
+
7
+ 接入 Google 官方 Antigravity ACP agent,在同一个对话界面选择模型、查看额度、预热连接。
8
+
9
+ [![npm](https://img.shields.io/npm/v/dsh-bundle-antigravity-host?color=3b82f6&label=npm)](https://www.npmjs.com/package/dsh-bundle-antigravity-host)
10
+ [![license](https://img.shields.io/badge/license-MIT-64748b)](LICENSE)
11
+ [![Node.js](https://img.shields.io/badge/Node.js-%E2%89%A522.19-64748b)](#兼容性与验证范围)
12
+
13
+ [快速开始](#快速开始) · [功能亮点](#功能亮点) · [配置参考](docs/configuration.md) · [排障](docs/reference.md#排障) · [更新记录](docs/changelog.md)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ > **0.1.25**:修复冷启动时登录 / 预热握手超时(新增 `handshakeTimeoutMs`,默认 120 秒),默认开启预热并显示启动进度。类型检查、**33 个文件 / 515 项测试**与构建通过;真实 Desktop GUI 与跨平台验收尚未完成。[查看本次更新与限制](docs/changelog.md#0125--2026-10-22)。上一版 0.1.24 的并发池、模型发现与图片输入见[更新记录](docs/changelog.md#0124--2026-10-22)。
20
+
21
+ ## 快速开始
22
+
23
+ ```console
24
+ dsh plugin --profile web add dsh-bundle-antigravity-host
25
+ ```
26
+
27
+ `web` 是示例 Profile,请替换为实际目标。**DSH NEXT Desktop 使用目标桌面壳提供的 DSH Desktop CLI**;不要用独立 npm 公共 CLI 管理保留的 `desktop` Profile。[安装与更新说明](docs/reference.md#安装与更新)
28
+
29
+ 1. **安装并启用**:按部署方式重载或重启,让 Host 与 Client 一起生效;只刷新页面不保证 Host 已升级。
30
+ 2. **打开「设置 → Antigravity ACP」**:需要代理时先配置并保存,再点击 **连接 / 登录 ACP**。插件优先复用已有 ACP 登录态,或导入本机已登录的官方 CLI 登录态;必要时才进入官方浏览器授权。成功建会话后读取模型目录,不需要先发送聊天。
31
+ 3. **选择模型,开始对话**:提供商名称为 **Antigravity (ACP)**,路由 ID 为 `antigravity-acp`。模型选择器左侧出现额度药丸和预热按钮;工具调用继续走 DSH 的校验、审批与执行。
32
+
33
+ **额度或 AI Credits 没有显示?** ACP 连接与 CLI 登录是两条链路。额度查询优先使用已登录的官方 `agy`,AI Credits 仅从 CLI 读取;ACP 登录成功不代表 CLI 也已登录。[登录态与数据来源](docs/reference.md#登录态与额度来源)
34
+
35
+ ## 功能亮点
36
+
37
+ ### 多个对话,不再共用一个待审批回合
38
+
39
+ 默认按需启动最多 **2 个独立 worker**,可配置为 1–4 个。一个会话等待工具审批时,其它会话可使用空闲 worker;同一工具回合的结果仍回到原 worker。容量用满后排队,支持取消,默认等待上限 120 秒,主对话优先于排队中的后台标题。
40
+
41
+ 这不是无限并发,也不保证上游账户额度随 worker 数增加。[并发与续轮边界](docs/reference.md#并发与工具续轮)
42
+
43
+ ### 先连接、拿目录,再开始聊天
44
+
45
+ 设置页区分 **立即预热** 与 **连接 / 登录 ACP**:前者准备连接但不创建会话,后者验证会话并读取模型目录,两者都不发送聊天 prompt。目录使用缓存即时显示,支持主动刷新、选择默认模型或手填模型 ID;目录外 ID 明确标记为未验证。
46
+
47
+ 模型家族与思考强度分开:选择家族,再由 DSH 的思考强度菜单路由到官方对应档位。不硬编码账号应当拥有的模型清单。[模型与请求项映射](docs/reference.md#模型目录与请求项)
48
+
49
+ ### 图片传给模型,不只传一段文字说明
50
+
51
+ 在 **宿主附件服务可用且上游声明 image capability** 时,当前消息、历史消息和工具返回的图片通过真实图片内容传入。支持 PNG、JPEG、WebP 与 GIF;只读取宿主附件,不自行抓取图片 URL。已被宿主卸载的图片会明确说明未发送像素。
52
+
53
+ 这是输入能力,不包含图片生成、音频或视频;真实图片识别效果尚未实机验收。[多模态限制](docs/reference.md#图片输入)
54
+
55
+ ### 额度、余额与连接状态,就在对话旁
56
+
57
+ - **额度药丸**:随当前模型切换对应额度组;展开查看三个组的窗口、剩余百分比、重置时间与缓存状态。
58
+ - **AI Credits**:与套餐额度独立展示、独立缓存与报错;未知不是零,不会自动开启 Credits 付费回退。
59
+ - **预热与诊断**:药丸可直接预热;设置页显示连接阶段、排队、进程复用,以及建会话、首块和工具续轮耗时。
60
+ - **设置不丢草稿**:后台刷新保留未保存字段,外部冲突明确提示;遵守宿主只读状态。
61
+
62
+ ## 它如何工作
63
+
64
+ ```mermaid
65
+ flowchart LR
66
+ D[DSH 对话] --> A[本插件 LlmAdapter / worker 池]
67
+ A -->|stdio · ACP v1| G[官方 Antigravity agent]
68
+ G -->|私有 loopback MCP| B[本插件工具桥]
69
+ B -->|挂起调用| T[DSH 校验 / 审批 / 执行]
70
+ T -->|工具结果回填原 prompt| B
71
+ B --> G
287
72
  ```
288
73
 
289
- 本机 Desktop 壳独占 `desktop` profile,公共 `dsh` 不能对它执行 `plugin add`。
290
- 请在 DSH NEXT 的插件管理器里添加本地包,路径示例:
74
+ 本包是 **Host + Web Client bundle**:Host 注册模型 provider、管理官方进程和工具桥,Client 提供设置页与额度药丸。不修改 DSH Core,也不把官方 CLI 包装成聊天接口;CLI 仅用于只读模型目录、额度与余额查询。
75
+
76
+ **它不是直接的 Gemini 模型 API。** 普通新用户回合会创建 ACP 会话并重放完整 DSH 历史;工具续轮才复用同一 prompt。角色消息、采样控制、延迟与计费不能视为和原生 API 相同。
77
+
78
+ ## 使用前,先知道这些边界
79
+
80
+ | 边界 | 当前行为 |
81
+ |---|---|
82
+ | 工具与权限 | AGY 内置工具、ACP fs / terminal 关闭;只允许已识别的私有桥请求进入 DSH,`allow_once` 不等于绕过 DSH 审批。协议约束**不是 OS 沙箱**。 |
83
+ | 登录材料 | 插件可能读取 CLI 登录文件,并为官方 ACP 写入 / 更新本机凭据文件;这些文件不是加密凭据库,Windows 访问保护依赖目录 ACL。 |
84
+ | 官方程序 | 按需从 `https://dl.google.com` 下载,拒绝重定向并检查 ZIP 路径;官方未提供校验和,不宣称签名验证通过。默认 server 版本为 **1.4.0**,不跟随 registry 自动升级。 |
85
+ | 模型参数 | `reasoningEffort` 映射官方档位;`maxTokens` 忽略;显式 `temperature` / `stop` 返回 `UNSUPPORTED_OPTION`。 |
86
+ | 数据可信度 | 缓存、失败、缺字段和未知分别标记;额度与余额仅供参考,不是计费依据。 |
87
+ | 版本与测试 | 宽 peer 范围是安装条件,不是全部 Core / 平台版本实机兼容证明;隔离测试不替代真实账号与 GUI 验收。 |
88
+
89
+ ## 兼容性与验证范围
90
+
91
+ | 项目 | 当前声明 / 证据 |
92
+ |---|---|
93
+ | Node.js | `>=22.19` |
94
+ | DSH Core peer 范围 | `>=0.2.0-rc.1 <0.2.1-0 \|\| >=0.2.1-0 <0.3.0-0`,适用于所声明的三个 `dsh-*` peer |
95
+ | 开发契约基准 | `dsh-llm` / `dsh-subprocess` / `dsh-typert-protocol` / `dsh-attachment` **0.2.1-alpha.4**,Cordis **4.0.5-alpha.2** |
96
+ | 上游协议 | ACP **v1**;SDK **1.4.0** 与默认 server **1.4.0** 是两个独立版本 |
97
+ | 本次本地验证 | 类型检查、33 个文件 / 515 项隔离测试、构建 |
98
+ | 尚未覆盖 | 0.1.24 安装后的 Desktop GUI、真实上游生成与图片识别、非 Windows 实机 |
99
+
100
+ 宿主附件服务是可选依赖,缺少时仍可文本聊天,但不声明图片能力。安装准入、开发类型检查和真实运行兼容性分别看待。[完整声明与验证方法](docs/development.md)
291
101
 
292
- `D:\dsh-antigravity-acp\.local-install\dsh-bundle-antigravity-host-0.1.22.tgz`
102
+ ## 文档导航
293
103
 
294
- 装好后需要完全退出并重开 Desktop。只要本机官方 CLI 已登录过,
295
- `oauth-personal` 登录态会自动导入,**不会**弹浏览器登录页。模型路由名为
296
- `antigravity-acp`。
104
+ | 你想做什么 | 文档 |
105
+ |---|---|
106
+ | 安装、连接、查看额度或排查错误 | [使用与技术参考](docs/reference.md) |
107
+ | 调整并发、超时、模型、代理或二进制位置 | [完整配置与环境变量](docs/configuration.md) |
108
+ | 查看 0.1.24 更新、迁移注意与剩余限制 | [更新记录](docs/changelog.md) |
109
+ | 构建、测试、打包或维护 npm 发布流程 | [开发、验证与发布](docs/development.md) |
297
110
 
298
- ## 排障
111
+ ## 许可与反馈
299
112
 
300
- | 现象 | 原因 | 处理 |
301
- |---|---|---|
302
- | 首次对话后 Gemini 完全不回话、也没有报错 | 二进制落在 Low 强制完整性目录,官方进程被降权后卡在凭据保存 | 插件现在会直接报 `AGY_BINARY_LOW_INTEGRITY`;删掉 DSH home 下的旧 `cache/antigravity-acp/*/extract-*` 即可,新版本默认装到 `%LOCALAPPDATA%` |
303
- | 启动即失败 `AGY_BINARY_MISSING` | 未配置 `binaryPath`、无缓存且 `autoDownload=false` | 打开 `autoDownload` 或指定 `binaryPath` |
304
- | 认证环节等到超时 | 导入不到任何本机登录态,退回官方浏览器授权 | 先用官方 CLI 登录一次,或在插件配置里填 `proxyUrl` 后重试 |
305
- | 官方进程连不上 Google | 宿主 scrub 了父环境,代理需显式注入 | 填 `proxyUrl`(留空时会自动转发宿主自身的 `*_PROXY`) |
306
- | 磁盘被 `_MEI*` 目录吃掉几十 GB | onefile 解压目录在进程被强杀后不会自清理 | 装载插件时会自动清理超过 1 小时的陈旧目录 |
307
- | 选某个具体型号后「没有反应」,默认项(首次对话登录)正常 | 该型号去索要原生 `fs`/`terminal` 能力(不同模型对工具的使用风格不同),回合被护栏终止 | 0.1.17 起改为「**拒绝但继续**」:原生请求与权限询问一律照旧**拒绝**(不授予任何本地能力),但不再当场终止回合,模型会改用桥过去的 DSH 工具;只有同一回合反复索要超过 3 次(明确坚持绕开工具桥)才按 fail-closed 终止 |
308
- | 药丸空着 / 药丸消失 | 贡献型 remote 的客户端挂载与依赖声明 | 插件必须在客户端 `ctx.remote.$mount(...)` 一次(0.1.15 起);**不要**把 `remote.<ns>` 写进 `inject`(注册回调会永远等待 → 元素消失)|
113
+ 本插件采用 [MIT License](LICENSE)。Google Antigravity 官方程序是独立下载的第三方软件,不随本包再分发;本插件并非 Google 官方产品。
309
114
 
310
- 本 README 仅描述代码与产物现状,不构成已安装或兼容性承诺。
115
+ 遇到问题请[提交 Issue](https://github.com/KouzakiUmi/dsh-antigravity-acp/issues),附插件版本、**实际 DSH Core 版本**、操作系统、操作步骤和已脱敏错误码。不要附 token、Cookie、完整 OAuth URL、代理密码或凭据文件。
@@ -4,8 +4,8 @@
4
4
  * 形态:官方 ACP server(Gemini 主模型)走 stdio,工具留在 DSH 侧,经插件
5
5
  * 进程内的私有 loopback MCP 桥暴露给 agent(见 ../bridge/mcp-bridge.ts)。
6
6
  *
7
- * 历史权威是 DSH:**本文件不建任何会话存储/数据库/文件**。每次 `stream` 都
8
- * 用完整的 `options.messages` + `options.system` 重建一条 ACP prompt
7
+ * 历史权威是 DSH:**本文件不建任何会话存储/数据库/文件**。新轮用
8
+ * 完整的 `options.messages` + `options.system` 建立 ACP prompt,工具结果续轮复用该 prompt
9
9
  * (见 prompt-transcript.ts);唯一的跨回合内存态是「当前 ACP 回合」与
10
10
  * 「park 中的 MCP tools/call」,它们都随回合结束而释放。
11
11
  *
@@ -17,6 +17,8 @@ import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelIn
17
17
  import type { SessionConfigOption } from '@agentclientprotocol/sdk';
18
18
  import type { AgentLink, AgentLinkHandlers } from '../protocol/agent-link.js';
19
19
  import { McpToolBridge } from '../bridge/mcp-bridge.js';
20
+ import type { ImageReader } from './image-content.js';
21
+ import type { AcpLifecycle } from '../runtime/lifecycle.js';
20
22
  /** DSH 侧 provider 标识符;与 cordis.patch.yml 的 id 及文档保持一致。 */
21
23
  export declare const AGY_PROVIDER_ID = "antigravity-acp";
22
24
  /**
@@ -39,12 +41,13 @@ export declare const AGY_ADAPTER_ERROR: {
39
41
  };
40
42
  /** MCP 桥与回合的可调参数(由 index.ts 从插件配置注入)。 */
41
43
  export interface AntigravityAcpAdapterOptions {
44
+ lifecycle?: AcpLifecycle;
42
45
  /**
43
46
  * 惰性启动工厂:返回完成 initialize + authenticate 的 AgentLink。传入的
44
47
  * handlers 必须在整个 adapter 生命周期内保持**同一对象**——index.ts 会把
45
48
  * 首个 handler 集合固化到被缓存的 AgentLink 上,后续回合只更换其内部状态。
46
49
  */
47
- getLink: (handlers: AgentLinkHandlers, signal?: AbortSignal) => Promise<AgentLink>;
50
+ getLink: (handlers: AgentLinkHandlers, signal?: AbortSignal, purpose?: 'warmup') => Promise<AgentLink>;
48
51
  /** 回收指定连接及其受管子进程;完成前禁止开启下一个回合。 */
49
52
  recycleLink: (link: AgentLink) => Promise<void>;
50
53
  /** 登记桥的关闭钩子(index.ts 把它挂到 ActiveAcpRuntime.bridgeTeardown)。 */
@@ -64,6 +67,10 @@ export interface AntigravityAcpAdapterOptions {
64
67
  loadCachedCatalog?: () => Promise<CachedModel[] | undefined>;
65
68
  /** 观测到真实目录后的落盘回调;失败由实现方自行吞掉。 */
66
69
  saveCatalog?: (models: readonly CachedModel[]) => Promise<void> | void;
70
+ /** Metadata only, for sharing catalog/context observations across isolated workers. */
71
+ onMetadataChanged?: (metadata: AdapterMetadata) => void;
72
+ readImage?: ImageReader;
73
+ canReadImages?: () => boolean;
67
74
  /**
68
75
  * 官方 CLI 模型清单(`agy models` 的只读取数,2026-10-16 授权仅限只读取数
69
76
  * 用途)。用于补齐会话观测之外的官方型号;失败由 adapter 吞掉。
@@ -91,11 +98,25 @@ export interface CachedModel {
91
98
  /** 实测上下文容量(usage_update.size);官方目录不报告,故可缺省。 */
92
99
  contextWindow?: number;
93
100
  }
101
+ export interface AdapterMetadata {
102
+ catalog: CachedModel[];
103
+ contextWindows: Array<[string, number]>;
104
+ imageSupported?: boolean;
105
+ }
94
106
  export declare class AntigravityAcpAdapter extends LlmAdapter {
95
107
  #private;
96
108
  constructor(options: AntigravityAcpAdapterOptions);
97
109
  /** 设置页连接不能与正在进行的对话/工具回合竞争同一登录态。 */
98
110
  get busy(): boolean;
111
+ get streamActive(): boolean;
112
+ get awaitingToolResults(): boolean;
113
+ ownsRequest(options: Pick<GenerateOptions, 'sessionId' | 'purpose'>): boolean;
114
+ exportMetadata(): AdapterMetadata;
115
+ importMetadata(metadata: AdapterMetadata): void;
116
+ /** Explicit discovery is allowed to authenticate, but never sends a model prompt. */
117
+ discoverModels(signal?: AbortSignal, interactive?: boolean): Promise<readonly LlmModelInfo[]>;
118
+ /** 预热复用聊天的同一组 handlers 和运行时;不建临时会话、不消耗模型请求。 */
119
+ warmup(signal?: AbortSignal, interactive?: boolean): Promise<void>;
99
120
  /** 私有 MCP 桥(诊断与测试可见;agent 侧只经 ACP mcpServers 访问它)。 */
100
121
  get bridge(): McpToolBridge;
101
122
  providerInfo(provider: string): LlmProviderInfo;