🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

订阅转模型 wanzdoan/agy2dsh

DeepSeek Harness
wanzdoan10 天前有提交已提供中文文档扫描:含敏感能力

把 Antigravity 与 Codex 订阅接入为可用模型

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/22 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add wanzdoan/agy2dsh
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · model
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 10 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 38 处,展示前 36 条)
  • 读取本地文件
    lib/index.js:45
    try { pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version || '' } catch { }
  • 读取本地文件
    lib/accounts.js:14
    const content = readFileSync(p, 'utf8')
  • 写入本地文件
    lib/accounts.js:29
    mkdirSync(join(p, '..'), { recursive: true })
  • 写入本地文件
    lib/accounts.js:36
    writeFileSync(p, JSON.stringify(obj), 'utf8')
  • 读取密钥环境变量
    lib/accounts.js:175
    const envKey = process.env.DSH_SUBSCRIPTIONS_MASTER_KEY
  • 发起网络请求
    lib/proxy.js:25
    return new Agent({
  • 发起网络请求
    lib/proxy.js:53
    return new ProxyAgent({
  • 发起网络请求
    lib/proxy.js:66
    f = (url, init = {}) => undiciFetch(url, { ...init, dispatcher: d })
  • 写入本地文件
    lib/history.js:38
    mkdirSync(this.dir, { recursive: true })
  • 读取本地文件
    lib/history.js:41
    const raw = JSON.parse(readFileSync(this.path, 'utf8'))
  • 写入本地文件
    lib/history.js:77
    mkdirSync(this.dir, { recursive: true })
  • 写入本地文件
    lib/history.js:78
    writeFileSync(this.path, JSON.stringify(this.rows))
  • 读取本地文件
    lib/alerts.js:5
    pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version || ''
  • 写入本地文件
    lib/tools/generate-image.js:230
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    lib/tools/generate-image.js:232
    await writeFile(path, result.data)
  • 读取本地文件
    lib/vault.js:14
    cachedVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version || '0.0.0'
  • 读取密钥环境变量
    lib/http.js:209
    const expectedToken = process.env.DSH_AUTH_TOKEN
  • 读取本地文件
    lib/routes/status.js:72
    try { pkgVersion = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version || '' } catch { }
  • 发起网络请求
    lib/routes/proxy.js:85
    const out = await subscriptions.request({
  • 读取本地文件
    lib/updater.js:36
    if (!existsSync(entry)) return undefined
  • 读取本地文件
    lib/updater.js:39
    if (existsSync(manifestPath)) {
  • 读取本地文件
    lib/updater.js:41
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
  • 发起网络请求
    lib/updater.js:115
    const response = await fetch(`${registry.replace(/ $/, '')}/${encodeURIComponent(packageName)}/latest`, {
  • 读取本地文件
    lib/updater.js:129
    const value = JSON.parse(await readFile(manifestUrl, 'utf8'))
  • 读取本地文件
    lib/updater.js:151
    if (!existsSync(lockPath)) return undefined
  • 读取本地文件
    lib/updater.js:152
    const stat = statSync(lockPath)
  • 删除本地文件递归
    lib/updater.js:190
    rmSync(lockPath, { recursive: true, force: true })
  • 删除本地文件递归
    lib/updater.js:199
    rmSync(lockPath, { recursive: true, force: true })
  • 删除本地文件递归
    lib/updater.js:207
    rmSync(lockPath, { recursive: true, force: true })
  • 执行外部命令来自配置/变量
    lib/updater.js:226
    const child = spawn(process.execPath, [
  • 执行外部命令固定命令
    lib/import-auth.js:67
    const out = execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', ps], {
  • 读取本地文件
    lib/import-auth.js:91
    const text = await readFile(path, 'utf8')
  • 读取本地文件
    lib/import-auth.js:246
    entries = await readdir(vaultDir)
  • 读取本地文件
    lib/agy-usage.js:65
    if (fromEnv && existsSync(fromEnv)) return fromEnv
  • 读取本地文件
    lib/agy-usage.js:72
    return candidates.find((candidate) => existsSync(candidate)) || null
  • 执行外部命令来自配置/变量
    lib/agy-usage.js:139
    execFile(bin, args, { ...options, windowsHide: true }, (error, stdout, stderr) => {
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-credentials@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-settings@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 插件:把 Antigravity(Gemini/Claude)和 Codex 订阅当作 LLM 服务商使用,OAuth 自动刷新,额度显示准确。

README

由 DeepSeek 最新模型翻译生成
agy2dsh 一个 DeepSeek Harness 插件,把两份面向消费者的 AI 订阅变成普通的 DSH LLM 服务商: Google Antigravity(agy,提供 Gemini 和 Claude 模型)和 ChatGPT/Codex。它把两者都注册到宿主机的 llm 服务,自己刷新 OAuth token,把请求分摊到你添加的多个账号上,并报告这些订阅实际计量的配额。它面向已经为 Antigravity 或 ChatGPT 付费的人:与其买 API 额度,不如直接从 DSH Desktop 里花掉这份额度。 包名 agy2dsh,版本 0.8.0,MIT。设置命名空间仍是 dsh-subscriptions,HTTP 路由仍在 /dsh-subscriptions/... 下:这是有意为之,好让已有的安装跨过这次改名后保留账号、槽位和偏好。 功能 - 两个 LLM 服务商。 antigravity 模型来自 fetchAvailableModels,过滤到计量系列 (claude-、gemini-3.8-flash-{low,medium,high});codex 行带上目录公布的推理等级和 上下文窗口;两者都会回退到内置目录。 - 自刷新凭据。
展开完整文档(README 剩余 1 节)
agy2dsh

一个 DeepSeek Harness 插件,把两份面向消费者的 AI 订阅变成普通的 DSH LLM 服务商: Google Antigravity(agy,提供 Gemini 和 Claude 模型)和 ChatGPT/Codex。它把两者都注册到宿主机的 llm 服务,自己刷新 OAuth token,把请求分摊到你添加的多个账号上,并报告这些订阅实际计量的配额。它面向已经为 Antigravity 或 ChatGPT 付费的人:与其买 API 额度,不如直接从 DSH Desktop 里花掉这份额度。

包名 agy2dsh,版本 0.8.0,MIT。设置命名空间仍是 dsh-subscriptions,HTTP 路由仍在 /dsh-subscriptions/... 下:这是有意为之,好让已有的安装跨过这次改名后保留账号、槽位和偏好。

功能

- 两个 LLM 服务商。 antigravity 模型来自 fetchAvailableModels,过滤到计量系列
(claude-、gemini-3.8-flash-{low,medium,high});codex 行带上目录公布的推理等级和
上下文窗口;两者都会回退到内置目录。
- 自刷新凭据。 每个账号同时只有一个刷新在途,失败退避重试,校正时钟偏移,刷新被拒时从 CLI 存储重读更新的 token 再试一次。
- 账号与轮换。 每个账号是一个槽位,有自己的凭据引用(ANTIGRAVITY_OAUTH_1、CODEX_OAUTH_2、……)、代理、并发上限和标签;支持轮询、最少使用或粘性排序,429 后按系列冷却,隔离并带预热探测。
- UI 里的配额,且来源正确。 会话标题栏上的胶囊,带每窗口进度条和重置倒计时的订阅中心,可选的输入框配额;Antigravity 的数字在 CLI 登录同一账号时来自 agy,否则来自 Cloud Code HTTP 摘要,Codex 的数字来自 ChatGPT 用量端点。
- 图片、重置额度、运维。 generate_image 用订阅的 Google 图片模型画图并在对话里展示(见图片生成),Codex 账号可以承接宿主的图片生成服务(subscriptionImages), Codex 重置额度可在确认步骤后消耗,插件还保留请求历史、诊断、仅限 localhost 的仪表盘和可选的加密保险库(WebDAV/Gist/S3)。

要求

- DSH Desktop,带 @deepseek-ai/dsh-llm、dsh-credentials、dsh-settings 和 dsh-host-webserver
版本 ^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2,以及 @deepseek-ai/cordis ^4.0.1 和 schemastery ^3.18.4。
不用自己装 Node:宿主那一半跑在 DSH Desktop 的运行时里(2.x 应用声明
node ^22.19.0 || >=24.0.0)。
- agy CLI,仅 Antigravity 需要——用于「从 CLI 导入」和 CLI 配额来源。查找顺序是 DSH_AGY_PATH、AGY_PATH,然后是 %LOCALAPPDATA%\agy\bin\agy.exe、%APPDATA%\agy\bin\agy(.exe)、 %USERPROFILE%\AppData\Local\agy\bin\agy.exe。
- 不需要 Codex CLI;如果本机已装,可以导入 ~/.codex/auth.json。

安装

agy2dsh 是配置档来源的 bundle:DSH Desktop 按当前配置档的 manifest 组装宿主。把它加进这份 manifest(配置档目录里的 package.json,通常在 <DSH home>/profiles/desktop),既作为依赖,也要写进 dsh.profile.bundles:

{
"dependencies": { "agy2dsh": "github:wanzdoan/agy2dsh" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "agy2dsh"] } }
}

保留配置档原有的 bundle 条目:dsh.profile.bundles 决定宿主怎么组装,包不在其中就只安装、永不加载。然后重装配置档(配置档目录是 pnpm workspace,这一步就是 DSH Desktop 对它执行的安装),并重启 DSH Desktop。插件入口、路由和后台定时器只在启动时加载,装完不重启,内存里还是旧构建;浏览器端代码在 lib/client.js 里,同样要重启才生效。

连接账号

打开会话标题栏上的胶囊按钮进入 Subscription Hub,或到设置里的插件卡片。两处都是每个服务商一个标签页。

| 操作 | Antigravity | Codex |
| 从 CLI 导入 | 读取 agy 已存在本机的记录 | 读取 ~/.codex/auth.json |
| 粘贴 token | OAuth refresh token | refresh token,或 API key(只按 API key 存储、原样发送,所以不会像会话那样过期) |
| 手动 OAuth | 你自己的 Google OAuth 客户端(见下文) | 内置 Codex 客户端,重定向 http://localhost:1455/auth/callback;无头主机可用设备码流程 |

导入会把凭据复制进 DSH 凭据存储,不向 CLI 回写任何东西。Antigravity 的来源是 CLI token 文件(~/.gemini/antigravity-cli/antigravity-oauth-token、~/.gemini/oauth_creds.json、~/.cli-proxy-api/antigravity.json),Windows 上还有 Credential Manager 条目 gemini:antigravity。凭据块保留 token 里的 client id,对已知 CLI 客户端还带上插件内置的公开 client secret,账号无需任何配置即可自行刷新。手动登录 Antigravity 则需要 antigravityClientId(机密客户端还要 antigravityClientSecret)和已注册的重定向 URI —— antigravityRedirectUri 为空时用 http://localhost:8085/oauth/callback;用 /login antigravity 启动,开启 autoLoopback 后该端口上的临时服务器会接住回调(否则粘贴重定向后的 URL,或设置 useWebCallback)。

Import all from CLI 是多账号路径:对 Antigravity,它会扫描实时的 Credential Manager 记录,以及账号管理器留在 ~/.gemini/account-vault/sessions/.json 下的每份按账号副本,对解析到同一 refresh token 的记录去重,复用服务商已占用的槽位并为每个不同账号生成一个新账号。对 Codex 来说,这只是一次导入。之后插件会自行刷新这些账号;你无需再次运行厂商命令行。

配额

Antigravity 计量两个系列,每个系列都有每周和5 小时窗口,因此插件会为每个账号报告四个数字:Gemini [weekly|5h] 和 Claude [weekly|5h]。胶囊显示状态点、服务商、每个系列一个标签(品牌标记、系列名、[weekly|5h] 剩余百分比,每周在前),连接多个账号时还显示 +N:Gemini [94%|91%] | Claude [0%|100%] 表示 Gemini 每周窗口还剩 94%,其 5 小时窗口还剩 91%。重置倒计时显示在 Hub 的行上;点击胶囊会打开 Hub。

状态点跟随 Gemini 5 小时窗口:剩余 60% 或以上为绿色,低于 60% 为琥珀色,低于 20% 为红色。没有 Gemini 窗口的账号(Codex,或不完整的快照)回退到该服务商的 5 小时窗口,再回退到其最紧的窗口。编辑器指示器以 percent 或 bar 模式显示活动账号剩余最少的窗口。

命令行是首选来源:lib/agy-usage.js 运行 agy --print "/usage" --output-format json 并解析 command.data.groups[].buckets[](remaining_fraction、reset_time),但仅当二进制文件存在且命令行已登录到正在显示的账号时——一次一个进程,五分钟缓存(cliQuotaTtlMs),20 秒超时(cliQuotaTimeoutMs),从不抛错,从不交互。这些快照标记为 cli。否则插件会用账号的 Code Assist 项目调用 :retrieveUserQuotaSummary,当摘要缺少四个窗口时再调用 :retrieveUserQuota,并将结果标记为 api。Codex 使用 GET https://chatgpt.com/backend-api/wham/usage,缩减为其命名窗口(primary_window / secondary_window,显示为 5h 和 7d)。

探测刻意保持非交互。agy 将 token 保存在 Windows 凭据管理器中,并在每次运行时用自己的过期副本重写该记录,因此它会在启动时通过网络刷新;如果该刷新缓慢或被阻止,打印模式会回退到交互式 OAuth 流程并打开浏览器登录页。用 AGY_CLI_NONINTERACTIVE_HEADLESS=1 运行它会把这种情况变成打印 URL 并退出,探测失败会退避(5 分钟,出现登录提示后 15 分钟),而不是每两分钟重试。

命令行胜出,因为没有任何云调用能复现其 Gemini 数字:在同一分钟、使用同一 token,:retrieveUserQuotaSummary(gRPC 和 REST,生产和每日,带和不带 project)回答 1.0,重置时间随时钟向前滑动,而 agy /usage 报告 0.9481,重置时间固定。Claude 在所有路径上都一致——详情见 docs/agy-usage-re.md。由于摘要不是安全的替代品,探测失败期间命令行读数会保留最多 30 分钟,而不是被 HTTP 路径返回的更乐观数字取代。

GET /dsh-subscriptions/status 会报告是哪个来源应答的,写在 active.usageSource(cli 或 api),以及最近一次探测的结果,写在 cliQuota(ok、reason、backoff、cachedAt); DSH_SUBSCRIPTIONS_QUOTA_SOURCE=api 强制走 HTTP 路径。用量最多每两分钟刷新一次,写入凭据 blob,因此 Hub 重启后仍保留最近已知的窗口。

图片生成

Antigravity 随订阅附带一个 Google 图片模型,但只有厂商自家的智能体能使用它:命令行把图片请求交给内置的 image-generator 子代理,所以只会说 generateContent 的 LLM 适配器永远看不到它,模型被要求画图时反而去写 PIL 代码。插件用一个真正的工具补上了这个缺口:

prompt: "a single ripe red apple on a white seamless background, studio product photo"
aspect_ratio: "1:1" # 1:1, 2:3, 3:2, 3:4, 4:3, 9:16, 16:9

该工具从 FetchAvailableModels 的 imageGenerationModelIds 解析图片模型 id(从不硬编码,缓存十分钟,可用 imageModelId 覆盖),POST :generateContent,带上
responseModalities: ["TEXT","IMAGE"],把文件保存到 <DSH home>/artifacts/agy2dsh/images(imageOutputDir
可改位置),返回一个文本信封加一个 ImageBlock —— 图片出现在对话里,智能体下一步就能查看它,和宿主自带的 read_image 完全一样。

针对真实账号测出的两个怪癖都已处理:图片模型 id 不在聊天 models 目录里(只出现在 imageGenerationModelIds),以及生产宿主对它返回 429 RESOURCE_EXHAUSTED,而 daily 宿主能服务同一请求 —— 所以先试 daily 宿主,记住能用的宿主十分钟,遇到 401/403 就停止重试,因为那个 token 在所有地方都被拒绝。请求计入订阅的 Gemini 配额(与聊天同一个池);一张 1024x1024 图片约花费 1.5k token。
详见 docs/image-generation.md。

imageGeneration(true)会关闭该工具,/dsh-subscriptions/status 把检测到的模型报告为 image.model —— 设置面板也会显示它,这是确认能力已生效最快的方式。

配置

所有内容都在 dsh-subscriptions 设置命名空间里,可从设置面板编辑,也可通过 GET/PUT /dsh-subscriptions/config 编辑。所有字段都是易变的,所以设置服务接受任何写入;密钥往返时掩码为 ••••••,并在服务端还原。

| 通用 | 默认值 | 含义 |
| language | en | en 或 vi;作用于面板和胶囊。 |
| privacyMask | false | 在 UI 中掩码账号邮箱和标签。 |
| composerQuota | off | 输入框旁的配额显示:off、percent 或 bar。 |
| usageTimeoutMs | 15000 | 单次配额请求的上限,包括 agy 命令行探测。 |
| imageGeneration | true | 暴露 generate_image 工具。 |
| imageModelId | '' | 覆盖图像模型;留空则用后端按账号发布的 id。 |
| imageOutputDir | '' | 生成图像的保存位置;留空则用 <DSH home>/artifacts/agy2dsh/images。 |
| imageTimeoutMs | 120000 | 单次图像请求的超时时间。 |
| cliQuotaTtlMs | 300000 | 复用 agy 配额读数,超过这个时长再重新探测;0 表示每次刷新都探测。 |
| cliQuotaBackoffMs | 300000 | agy 探测失败后,等这么久再重试(登录提示则等 15 分钟)。 |
| cliQuotaTimeoutMs | 20000 | 单次 agy 探测的硬超时;到点直接杀掉进程。 |
| streamIdleTimeoutMs | 180000 | 流静默超过这个时长就中止;0 表示关闭。超时不会把账号标记为限流。 |
| useWebCallback | false | 用 DSH Web 源 + /dsh-subscriptions/oauth/callback 作为 redirect_uri。 |
| autoLoopback | true | 在服务商的 loopback 端口上接收 OAuth 回调(Codex 1455,Antigravity 8085)。 |
| masterKey | '' | 加密存储的凭据;留空则回退到 DSH_SUBSCRIPTIONS_MASTER_KEY。 |

| 轮换与限制 | 默认值 | 含义 |
| rotationStrategy | round-robin | 账号选取顺序;面板提供轮询、最少使用、粘滞直到限流三种,每个选项都对应一个真实的比较器。排序还会权衡自动调速风险、最近重置、权重和健康度。 |
| switchAtRemaining | 0.01 | 剩余额度等于或低于这个值时视为耗尽(小于 1 的小数,或绝对值);0 表示关闭。 |
| cooldownMs | 1800000 | 遇到 429/配额失败后,跳过该账号这么久。 |
| enableQueue | true | 按账号限长的队列,配合 accountMaxConcurrency(1,槽位可覆盖)、maxQueueSize(20)和 queueTimeoutMs(30000)。 |
| drainBeforeReset | false | 优先选窗口最早重置的账号,把即将过期的额度用掉;drainSafetyPercent(5)在有更新账号时保留一个下限。 |
| autoPacing | true | 账号之间按消耗速率排序;enableSoftFailureSentinel(true)在 HTTP 200 却附带容量致歉时切换账号。 |

告警。 notifyLimits(true)在窗口用量越过 70%、90% 或 100% 时记录一条通知并发出 subscriptions.limit-notice;alertThresholds([80, 90, 95])设置记录告警的阈值,webhookUrl('')是配额、隔离和会话过期告警的 JSON POST 目标,enableToasts(true)控制应用内浮层提示。

服务商字段。 Antigravity:antigravityClientId('',仅用于手动登录)、antigravityClientSecret('',用于机密客户端)、antigravityRedirectUri('' = 服务商的 loopback 回调)、antigravityClientVersion('' = 内置 1.18.3)和 antigravityModels([] = 已发布的目录,过滤到计费系列)。Codex:codexClientId('' = 内置公开 client)、codexRedirectUri('' = http://localhost:1455/auth/callback)、codexBaseUrl('' = https://chatgpt.com/backend-api/codex)、codexOriginator('' = codex_cli_rs)、codexClientVersion ('' = 0.160.0,/models 目录的准入版本)、codexVerbosity('' 或 low/medium/high)、 codexFastMode(false,发送 service_tier: priority)和 codexModels([] = 后端目录)。

按账号配置(slots[])。 provider 和 index 固定槽位及其凭据引用;label 默认取账号邮箱;proxyUrl 让该账号的所有请求(包括 token 刷新和配额查询)都走 http/https/socks5;maxConcurrency 默认 1;expiresAt 供过期标签使用;monthlyCost、tags、weight、isPro、vipOnly、maxQueueSize 调整轮换统计。

Vault 同步。 vaultSyncEnabled(false)、vaultSyncBackend(webdav、gist 或 s3)、 vaultSyncPassphrase('')、vaultSyncIntervalHours(24,0 表示停止拉取)和 vaultSyncAutoPush (true);目标配置是 vaultSyncWebdavUrl/Username/Password、vaultSyncGistId/Token/BaseUrl 和 vaultSyncS3Endpoint/Bucket/Key/Region。

高级项,未列入表格:refreshAheadMs(300000)和 refreshRetryMs(600000)控制刷新心跳,probeIntervalMin(15)控制健康探测,expiryNotifyDays(7)控制过期标签,hideDeprecatedModels(false)控制模型选择器,codexSystemPrefix 在开头追加一段系统提示词。

语言

默认英文。选择 Tiếng Việt 会写入 language: "vi",并切换插件贡献的所有文案:胶囊、Hub(账号卡片、窗口标签、按钮、状态词、通知)、输入框指示器和设置面板。两套词典都注册到宿主的 locale 服务(MESSAGES.en、MESSAGES.vi),所以改动在下一次轮询时生效,无需重启;模型 id 和 API 错误文本这类厂商字符串保持原样。

工作原理

- lib/index.js 是入口(export const name = 'agy2dsh', inject = ['llm', 'credentials', 'webServer', 'settings'])。它构建设置快照,创建账号存储和适配器,注册路由(/dsh-subscriptions/{config,status,models,health, check,history,diagnostics,accounts,oauth,import-local,import-token,vault,...} —— 同源写入,仪表盘仅限回环地址),并负责后台任务:一分钟一次的刷新心跳、两分钟一次的配额循环、健康探测、每小时一次的 Vault 同步检查,以及待处理 OAuth 的清扫。
- lib/accounts.js 是凭据与槽位层:数据块经由凭据服务处理(密钥绝不写入设置),按账号的冷却、隔离、配额采样和健康状态都保存在这里(隔离记录持久化在 $DSH_HOME/subscriptions/quarantines.json)。lib/vendors/{antigravity,codex}.js 实现厂商侧逻辑(授权、换取、刷新、列出模型、用量、流式传输), lib/code-assist.js 负责 Cloud Code 契约,lib/agy-usage.js 负责命令行配额路径。
- lib/adapter.js 实现 LlmAdapter(模型解析、能力标签、图片物化、按请求选择账号、429 时重试与故障转移、历史记录),只要有一个服务商拿到凭据,就注册为
ctx.llm.registerAdapter(['antigravity', 'codex'], adapter)。
- lib/client.js 挂载浏览器界面:conversation.session.header.actions 上的胶囊(order 15)、 conversation.input.right 上的输入框指示器(order 5)、plugins.item / plugins.bundle.config / plugins.row.config 上的卡片与设置面板,以及 /login 和 /logout 斜杠命令。它轮询 /dsh-subscriptions/config,并通过 portal 渲染 Hub。

故障排查

重启后账号显示为未连接。 槽位是设置,token 是凭据;启动时,只要某个槽位 ref 对应的凭据存在,插件就会重新添加该槽位。如果面板仍显示 Not connected,先确认 agy2dsh 还在 dsh.profile.bundles 里(重装配置档可能把它丢掉),再读取 GET /dsh-subscriptions/status 中的 loggedIn。如果你启用了 masterKey,同一个密钥必须传到宿主,否则每次调用都会失败并报 encrypted at rest 错误。

配额与 agy /usage 不一致。 检查 GET /dsh-subscriptions/status 中的 active.usageSource 和 cliQuota。api 表示没有走命令行:找不到可执行文件、设置了 DSH_SUBSCRIPTIONS_QUOTA_SOURCE=api、agy 登录的账号与槽位的邮箱不一致,或者子进程超时。cliQuota.reason 会说明是哪种情况:auth-required(命令行无法使用已存凭据,要求重新登录)、timeout、unreadable 或 error,并给出重试时间。这类故障期间,最近一次命令行读数会保留最多 30 分钟,所以胶囊停在最后一个真实数字上,而不是 HTTP 摘要里更乐观的 Gemini 数字——摘要对 Gemini 来说也确实不同(见 Quota)。

屏幕上闪过终端窗口。 插件启动的某个程序打开了控制台。宿主是 GUI 进程,所以任何没有带 windowsHide: true 启动的控制台程序,在运行期间都会拥有自己的控制台窗口。0.8.3 已修复 Credential Manager 读取(lib/import-auth.js)的问题,这段代码每隔几分钟运行一次;现在只要有新的启动点忘了这个标志, test/no-window-flash.mjs 就会失败。

图片请求变成了 Python 代码,而不是图片。 检查 GET /dsh-subscriptions/status 中的 image。
没有 model 意味着工具已关闭(imageGeneration)、没有 Antigravity 账号登录,或者读不到目录(此时工具回退到 gemini-3.1-flash-image)。如果模型已列出,智能体却仍在写 PIL 代码,那是有人让它这么做的:说一次「use the generate_image tool」,或者检查是否有别的插件遮蔽了该工具。这里不涉及 Imagen API key——订阅 token 就够了。
浏览器窗口会打开 Antigravity 登录页。 这是 agy 的行为,不是插件:命令行在启动时会刷新已过期的 Credential Manager token,刷新失败就会启动交互式 OAuth 流程。从 0.8.2 起,探测以 AGY_CLI_NONINTERACTIVE_HEADLESS=1 运行,因此命令行会打印 Authentication required. Please visit the URL to log in: ... 后退出,不再打开浏览器。如果你仍想修复底层状态,交互式运行一次 agy 并登录;命令行会继续用过期副本重写自己的记录,所以下次探测还会走网络刷新。

模型选择器里缺少某个服务商。 适配器只为凭据可读的服务商注册,所以选择器为空通常意味着 loggedIn 为 false。如果 loggedIn 为 true 但该服务商始终不出现,说明配置档里另一个 bundle 已经注册了同一个服务商 id —— 插件会记录 syncAdapter skipping already-bound providers,并保留已有的服务商不动。如果模型列出来了但已过期,点账户卡片上的 Sync models;Antigravity 只从已发布目录中保留 claude-* 和 gemini-3.8-flash-{low,medium,high},其余回退到内置目录。

请求失败并返回 429,或某个账户不再响应。 429 或配额错误只会给受影响的模型系列设置冷却(默认 30 分钟);其他账户继续服务。调低 accountMaxConcurrency、保持 enableQueue 开启,或再加一个槽位。请求成功或调用 POST /dsh-subscriptions/quarantine/probe 可解除隔离(传 release: true 则直接释放,不做探测)。状态保存在 $DSH_HOME/subscriptions/quarantines.json。

Antigravity 总是回退到 HTTP,或导入找不到任何东西。 查找只接受存在的路径:先 DSH_AGY_PATH,再 AGY_PATH,然后是上面列出的 %LOCALAPPDATA% / %APPDATA% / %USERPROFILE% 候选路径。agy 装在别处时,把 DSH_AGY_PATH 设为可执行文件的完整路径 —— 包装脚本也行,只要它接受 --print /usage --output-format json。导入会读取命令行 token 文件,并且仅在 Windows 上读取 gemini:antigravity 的 Credential Manager 条目。

保存设置时报冲突失败。 PUT /dsh-subscriptions/config 会校验修订号:修订号过期返回 409 configuration has been modified concurrently,请求不带修订号返回 428。让面板重新加载(它约每 25s 轮询一次,会重新读取修订号)后再保存,不要同时开着两个设置面板。

安全与隐私

- 凭据留在 DSH 凭据存储中,写在 <PROVIDER>_OAUTH_<index> 下。设置只保存槽位元数据;GET /dsh-subscriptions/config 会隐去密钥字段,写入前再从存储值恢复,因此浏览器永远收不到它们。配置了 masterKey(或 DSH_SUBSCRIPTIONS_MASTER_KEY)时,数据块会先加密再存储;加密数据块缺少对应密钥会被拒绝,而不是悄悄损坏。
- 配额数据不会离开本机。 它用账号自己的 token 从 Google Cloud Code 和 chatgpt.com 读取,与请求历史、隔离状态一起保存在本地。不上传遥测或分析数据;/dsh-subscriptions/telemetry 只汇总本地历史。
- 对外流量由你决定开启。 设置 webhookUrl 后,告警会 POST 到该地址;vault 同步会把加密归档上传到你的后端;proxyUrl 会让该账号的流量走你的代理;调用 /dsh-subscriptions/update 时会向 npm registry 查询最新版本。配置写入和账号操作仅限同源;仪表盘及其历史仅限回环地址访问。

许可证

MIT — 见 LICENSE。

通过第三方工具使用消费级订阅,可能违反出售该订阅的服务商的服务条款。你需要对自己账号的使用方式负责,本项目不保证任何特定用法被允许。本项目与 Google、OpenAI 和 DeepSeek 均无关联。
预览分享卡片长什么样 ↓wanzdoan/agy2dsh
分享 · DeepSeek Harness Hub
wanzdoan/agy2dsh

把 Antigravity 与 Codex 订阅接入为可用模型

回到顶部