@eddyskywalker/dsh-chatgpt-subscription 0.2.21 → 0.3.0

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 (74) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +115 -1
  3. package/lib/client.js +2825 -512
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +8630 -389
  6. package/lib/types/client/ProviderHubSection.d.ts +15 -0
  7. package/lib/types/client/ProviderHubSection.d.ts.map +1 -0
  8. package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts +24 -0
  9. package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts.map +1 -0
  10. package/lib/types/client/command-code/CommandCodeSection.d.ts +11 -0
  11. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -0
  12. package/lib/types/client/command-code/locales.d.ts +401 -0
  13. package/lib/types/client/command-code/locales.d.ts.map +1 -0
  14. package/lib/types/client/index.d.ts +2 -0
  15. package/lib/types/client/index.d.ts.map +1 -1
  16. package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts +25 -0
  17. package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts.map +1 -0
  18. package/lib/types/client/kimi-code/KimiCodeSection.d.ts +11 -0
  19. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -0
  20. package/lib/types/client/kimi-code/KimiModelCapabilities.d.ts +16 -0
  21. package/lib/types/client/kimi-code/KimiModelCapabilities.d.ts.map +1 -0
  22. package/lib/types/client/kimi-code/locales.d.ts +665 -0
  23. package/lib/types/client/kimi-code/locales.d.ts.map +1 -0
  24. package/lib/types/client/kimi-code/styles.d.ts +4 -0
  25. package/lib/types/client/kimi-code/styles.d.ts.map +1 -0
  26. package/lib/types/client/locales.d.ts +3 -1
  27. package/lib/types/client/locales.d.ts.map +1 -1
  28. package/lib/types/client/styles.d.ts.map +1 -1
  29. package/lib/types/host/command-code/adapter.d.ts +34 -0
  30. package/lib/types/host/command-code/adapter.d.ts.map +1 -0
  31. package/lib/types/host/command-code/client.d.ts +99 -0
  32. package/lib/types/host/command-code/client.d.ts.map +1 -0
  33. package/lib/types/host/command-code/mapper.d.ts +102 -0
  34. package/lib/types/host/command-code/mapper.d.ts.map +1 -0
  35. package/lib/types/host/command-code/model-catalog.d.ts +31 -0
  36. package/lib/types/host/command-code/model-catalog.d.ts.map +1 -0
  37. package/lib/types/host/command-code/oauth.d.ts +89 -0
  38. package/lib/types/host/command-code/oauth.d.ts.map +1 -0
  39. package/lib/types/host/command-code/plans.d.ts +40 -0
  40. package/lib/types/host/command-code/plans.d.ts.map +1 -0
  41. package/lib/types/host/command-code/routes.d.ts +27 -0
  42. package/lib/types/host/command-code/routes.d.ts.map +1 -0
  43. package/lib/types/host/command-code/token-store.d.ts +88 -0
  44. package/lib/types/host/command-code/token-store.d.ts.map +1 -0
  45. package/lib/types/host/command-code/types.d.ts +138 -0
  46. package/lib/types/host/command-code/types.d.ts.map +1 -0
  47. package/lib/types/host/kimi-code/adapter.d.ts +112 -0
  48. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -0
  49. package/lib/types/host/kimi-code/client.d.ts +161 -0
  50. package/lib/types/host/kimi-code/client.d.ts.map +1 -0
  51. package/lib/types/host/kimi-code/mapper.d.ts +334 -0
  52. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -0
  53. package/lib/types/host/kimi-code/modalities.d.ts +94 -0
  54. package/lib/types/host/kimi-code/modalities.d.ts.map +1 -0
  55. package/lib/types/host/kimi-code/model-catalog.d.ts +77 -0
  56. package/lib/types/host/kimi-code/model-catalog.d.ts.map +1 -0
  57. package/lib/types/host/kimi-code/oauth.d.ts +133 -0
  58. package/lib/types/host/kimi-code/oauth.d.ts.map +1 -0
  59. package/lib/types/host/kimi-code/routes.d.ts +26 -0
  60. package/lib/types/host/kimi-code/routes.d.ts.map +1 -0
  61. package/lib/types/host/kimi-code/token-store.d.ts +135 -0
  62. package/lib/types/host/kimi-code/token-store.d.ts.map +1 -0
  63. package/lib/types/host/kimi-code/types.d.ts +174 -0
  64. package/lib/types/host/kimi-code/types.d.ts.map +1 -0
  65. package/lib/types/host/relay-probe.d.ts +161 -0
  66. package/lib/types/host/relay-probe.d.ts.map +1 -0
  67. package/lib/types/host/responses-client.d.ts.map +1 -1
  68. package/lib/types/index.d.ts +13 -0
  69. package/lib/types/index.d.ts.map +1 -1
  70. package/lib/types/shared/command-code-contracts.d.ts +119 -0
  71. package/lib/types/shared/command-code-contracts.d.ts.map +1 -0
  72. package/lib/types/shared/kimi-code-contracts.d.ts +203 -0
  73. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -0
  74. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,80 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - 新增 Kimi Code(Kimi For Coding 订阅)线路:注册 `kimi-code` Provider,把 Moonshot 的 Kimi Code 订阅作为本插件第四条线路接入 DSH。Kimi Code 与 Moonshot 开放平台(pay-as-you-go)是**两套互不通用的系统**:订阅走 `https://api.kimi.com/coding/v1`、凭据来自 `auth.kimi.com` 的 OAuth;开放平台的 key 与 base URL 在订阅端会被判为 `401 Invalid Authentication`,插件据此把两者严格分开。
6
+ - OAuth 采用 RFC 8628 设备码流程(`src/host/kimi-code/oauth.ts`),复刻官方 CLI 的协议细节:`POST /api/oauth/device_authorization` 只带 `client_id`(公共客户端,**无 client secret、无 PKCE、无 scope**),`POST /api/oauth/token` 轮询用 `grant_type=urn:ietf:params:oauth:grant-type:device_code`;令牌响应字段(`access_token` / `refresh_token` / `expires_in` / `scope` / `token_type`)与官方实现逐字段对应。`slow_down` 按 RFC 把轮询间隔永久 `+5s`;`authorization_pending` 继续等待;`expired_token` **不当作失败**,而是像官方 CLI 一样重新申请设备码(用户授权慢了仍能登入);`access_denied` 单独分类。设置卡展示用户码、一次性链接与到期时间,可复制用户码、可取消。
7
+ - 令牌自动续期:阈值取 `max(300s, expires_in × 0.5)`(与官方一致),同一进程内并发调用**共用一次刷新请求**(避免订阅侧并发轮换同一 refresh token);被拒的 refresh token 记入进程级 tombstone 并进入 5 分钟冷却,之后直接提示重新登录而不是反复打扰服务端。
8
+ - **重试语义按错误类别区分**(`src/host/kimi-code/adapter.ts` 的 `classifyKimiFailure`),这是本线路的关键设计:服务把多种含义压进同一个状态码,因此分类读取响应正文而不只看状态码。
9
+ - **会重试**:任意 5xx(含截图里那条 `502 {"error":{"message":"Upstream model provider is temporarily unavailable. Please try again in a moment.","type":"server_error"}}`——上游模型供应商瞬时故障,与账号、模型、凭据都无关);真正的 429 背压(`We're receiving too many requests`、`The engine is currently overloaded`);连接层失败(`TRANSPORT`);流停滞(`TIMEOUT`,由 idle watchdog 触发)。策略固定为 `maxRetries: 3`、`retryableCodes: ['RATE_LIMIT','SERVER','TIMEOUT','TRANSPORT']`、1.5s 起步、15s 上限、0.2 抖动,并**honor `Retry-After`**(作为 `providerRetryAfterMs` 随错误上抛,由 DSH 重试策略原样等待)。402(`unable to verify your membership benefits`)被官方描述为「通常是暂时问题」,同样归类为可重试。
10
+ - **不重试**:401 里其实是**套餐权限**被拒的情况(`does not have access to k3`、`supports only … up to … context`、`model id does not exist`)——与真正凭据失效分开,前者提示换模型/降上下文/升级套餐,后者才提示重新登录;403 的各类账号额度上限(5 小时 / 7 天 / 月度共享池 / 并发上限),提示等待重置或加油包;**配额耗尽型的 429**(`exceeded_current_quota_error`、`insufficient balance`、`please recharge` 等)——这与背压型 429 是两回事,重试只会白白消耗请求并推迟用户该看到的提示;以及 400 请求格式错误。
11
+ - K3 系列行为按其官方文档精确实现(`src/host/kimi-code/mapper.ts`):
12
+ - **思考档位只发 `low` / `high` / `max`**,其余输入被收敛映射(`ultra`/`max`/`xhigh`→`max`、`high`/`medium`→`high`、`low`/`minimum`/`light`→`low`、`none`→`thinking:{type:'disabled'}`),未知档位**不发送**而不是发出去吃 400;Anthropic 线路映射为 `thinking` 预算(low 2048 / high 8192 / max 16384),预算放不下时不启用。
13
+ - **当思考开启时,带工具调用的 assistant 消息必须回传 `reasoning_content`**,否则服务返回 400 `thinking is enabled but reasoning_content is missing in assistant tool call message`。本线路因此**保留 reasoning 块**(同插件的其他线路是丢弃的,因为那些上游要求签名),无工具调用的普通回复则不回传。
14
+ - **不发送 `temperature`**:采样参数按模型固定(1.0 / 0.95 / n=1),服务对显式值直接报错而非钳制,因此调用方的 temperature 被有意丢弃;输出上限统一用 `max_completion_tokens`(旧字段会被服务归一化掉)。
15
+ - 工具调用 id 截断到服务要求的 **64 字符**上限。
16
+ - 发送 `prompt_cache_key`(由首轮用户消息推导的稳定会话标识),让续接的会话能命中前缀缓存;模型或思考档位切换会使缓存失效。
17
+ - 模型目录为官方四款订阅模型(`src/host/kimi-code/model-catalog.ts`):`k3`(1M 上下文,需 Allegretto+;Moderato 上限 256K,故默认按 **256K** 计算以免会话悄悄超出后被 401 拒绝,可用上下文覆盖升到 1M)、`k3-256k`(固定 256K、无视频输入)、`kimi-for-coding`(K2.8 Preview,各套餐均 1M,默认档位 max)、`kimi-for-coding-highspeed`(约 6× 输出速度、3× 额度消耗,需 Allegretto+)。运行时仍以 `GET /v1/models` 为准(含每模型 `context_length`、`think_efforts`、`supports_image_in`),30 分钟缓存、可手动刷新、离线回落内置表。
18
+ - 额度卡片读取 `GET /v1/usages`:5 小时 / 7 天 / 月度(会员共享池)/ 月度(Kimi Code 池)四个窗口各自显示百分比与重置时间——把两个月度池**分开标注**,因为共享池耗尽时即使 Code 池还有余额也会被拒;加油包(booster wallet)按服务的定点数换算(1e-6 分,正数不足 1 分记 1 分;`priceInCents` 已是分,不再二次换算)。同时容忍社区记录到的另一种 `usage` + `limits[]` 形状,且从 `used`/`limit` 推导比例,避免服务换形状时卡片直接空白。账号资料取自 `/me`,失败只降级为「已登录但无资料」而不影响额度。
19
+ - OAuth 凭据只存 Host:Windows CurrentUser DPAPI、macOS 登录钥匙串、Linux Secret Service(与 Antigravity / Command Code 同一存储栈),明文 JSON 仅作迁移来源;存储的 oauth/API 主机需为绝对 https 源,防止被篡改的凭据文件把刷新请求指向他处。
20
+ - 新增 `/kimi-code/api` 设置路由(status / login / login/status / login/cancel / logout / quota / models / settings / catalog/refresh / connection/test),改状态的操作只接受同源 JSON POST;设置页新增「Kimi Code」卡片,对话输入框新增该线路的额度胶囊(最短窗口优先,余额兜底)。
21
+ - 修复 Kimi Code 已登录后账号显示为 `—`、以及刷新用量与实际状态不符的问题,根因是三个独立缺陷:
22
+ - **账号资料接口不存在**。此前 `fetchUserInfo` 会去请求 `/coding/v1/me`,而该端点在订阅侧并未提供,非 2xx 时静默返回 null,于是卡片永远是空白。Kimi 的 access/refresh token 本身是 **JWT**,账号身份(`user_id` 优先、`sub` 兜底、`email` 小写化)就在其 payload 里——现在从 token 解码得到账号并在登录时落盘(刷新时也会补齐旧凭据缺失的声明),卡片不再依赖任何网络调用即可显示已登录身份;套餐名仍以 `/usages` 返回的 `user_level_name` 为准并写回凭据。
23
+ - **测试连接按钮没有任何反馈**。`/connection/test` 的处理函数**缺少 return**,响应永远不会结束(按钮点了没反应);而且探测目标正是那个不存在的资料接口。现在改为以真实的 `/usages` 调用作为探测(200 即证明凭据可用,同时顺带刷新额度卡片),并在卡片上显示结论与延迟。
24
+ - **刷新用量会把失败吞掉**。`/quota` 与 `/status` 都用 `.catch(() => null)` 包住上游错误,于是上游 401/403/5xx 时接口照样返回 200 空数据——这正是「刷新不正常」的观感:按钮看似成功、面板依旧为空。现在显式刷新会把真实原因以 502 + 文案返回,背景刷新则通过新的 `quotaError` 字段随状态一起展示,既说明原因又不隐藏已登录账号;对 `/usages` 的 401 也改为抛出类型化的未授权错误(此前是普通 Error),使「凭据失效」与「服务瞬时故障」在测试连接里能被区分。
25
+ - 修复 Kimi Code 套餐一直显示为空,并补齐模型能力展示(新增 `test/kimi-code-plan.test.ts`,19 条):
26
+ - **套餐名的来源是 `/me`,而它被我上一轮误删了**。Kimi **在 2026 年 9 月把 `user_level_name` 从 `/usages` 里移除**,因此 `/usages` 不再返回套餐名——而该字段正是我当时唯一的来源。现在恢复调用 `GET /coding/v1/me`(仅用 OAuth 访问令牌,不导入粘贴的套餐 key;4 秒超时、失败只降级不影响卡片),并保留 `/usages` 作为回退;两者都拿不到时再读凭据里缓存的套餐名。
27
+ - 新增**会员等级代码映射表**:`LEVEL_STANDARD`/`LEVEL_MODERATO` → Moderato、`LEVEL_INTERMEDIATE` → Allegretto、`LEVEL_ADVANCED` → Allegro、`LEVEL_PREMIUM` → Vivace(旧代码 `LEVEL_FREE`/`LEVEL_BASIC` → Adagio、`LEVEL_ANDANTE` → Andante 也一并支持)。此前若服务只发机器代码,卡片会显示原始枚举;现在映射为 Kimi 定价页使用的名称。昵称同样从 `/me` 读取。
28
+ - **修复 `buildModelOptions` 丢弃目录能力的问题**:`supportsVideo` 与 `minimumPlan` 此前被硬编码为 `false`/`null`,`description` 恒为 `null`——即实时目录与静态注册表已知的信息被直接丢掉。现在按「实时目录 > 静态注册表」取值,视频输入标记与描述都能正确显示。
29
+ - 关于截图里两个特殊能力的说明(已核对官方文档与实测资料,并据此决定是否接入):
30
+ - **视频输入**:`k3` 与 `kimi-for-coding` 确实支持视频,`k3-256k` **只支持图片**。但 **DSH 的模态词汇表只有 `text` 与 `image` 两项**(`ModelModalityMap`),没有 video——若谎报支持视频,DSH 会把无法投递的字节交给该线路。因此**不将其声明为可发送模态**,只在模型提示与能力行中如实标注,避免误导。
31
+ - **`dynamically_loaded_tools`**:这是 K3 的独有能力,允许在会话中途以「不含 content 的 `system` 消息 + `tools` 数组」注入额外工具定义,从而让顶层工具列表保持小而稳定(`system`/`tools` 属于缓存前缀,改动会使整个前缀缓存失效)。DSH 没有对应概念,本插件也无法从适配器层注入消息,因此**仅作展示说明**,不实现——这也解释了为什么官方把工具集稳定性作为优化建议。
32
+ - 依据官方文档与实测数据补齐 K3 系列的能力、参数与优化(新增 `test/kimi-code-k3.test.ts`,31 条):
33
+ - **保留思考 (Preserved Thinking) 默认开启**。官方 CLI 的默认是 `[thinking] keep = "all"`,即服务会跨轮保留推理内容——其错误参考里要求「每个缺 `reasoning_content` 的 assistant 消息都要补上」正以此为前提。此前我们只在**带工具调用**时回传 `reasoning_content`,普通文本轮次不带,这既与官方 `keep=all` 的约定不符,也在长会话里丢失了多轮推理的连贯性。现在思考开启时(含未显式指定档位,因为模型默认就推理)**每条 assistant 消息都写该字段**,无推理时写空串(服务要求的正是空值而非省略);思考关闭则完全不写。可用 `DSH_KIMI_CODE_PRESERVE_THINKING=0` 关闭,卡片会显示当前状态。
34
+ - **输出上限改为跟随上下文窗口**(`maxOutputTokensFor(modelId, contextWindow)`)。`reasoning_content` 计入输出,而此前固定 32768 的上限会把 `max` 档的长思考**中途截断**并返回 `length`;官方客户端是按窗口封顶(并夹到 窗口 − prompt)——这正是官方文档所说「官方 kimi-code 行为」的 `computeCompletionBudgetCap`。现在按窗口封顶并保留 4096 余量,同时不低于模型声明的下限,避免小窗口把答案饿死。
35
+ - **新增请求前夹取**(`clampOutputToContext` + `estimatedInputTokens`):调用方若已知 prompt 规模,`max_tokens` 会被下调到 prompt + 输出可容纳;prompt 规模未知时**不做猜测**——猜小会截断推理、猜大被直接拒绝,只有服务知道真实大小。
36
+ - **请求体超过 2 MB 时本地拒绝**(`assertRequestBodyFits`)。这是该端点最常被触发的 400(`total message size N exceeds limit 2097152`),官方文案不给出路;现在按真实序列化体积判断并直接提示「压缩会话/开新会话、检查大工具结果与图片」,既给出可操作建议也省掉一次注定失败的往返。
37
+ - **stop 序列按服务的硬上限裁剪**:最多 5 条、每条不超过 32 字节。超长的序列**整条丢弃而不是截断**——截断后的停止串会在错误位置终止生成,静默改变答案是比不停止更糟的结果。
38
+ - **新增缓存与 K3 调优卡片**:滚动统计命中/新处理的 prompt tokens、输出 tokens 与**缓存命中率**。Kimi 的缓存按内容哈希自动命中、无需也无法手动声明(实测 `prompt_cache_key` 与 Anthropic `cache_control` 标记均被忽略),所以读缓存比例是唯一能证明缓存真的生效的证据;卡片同时说明「同一会话内系统提示与工具列表一旦变化会使整个前缀缓存失效,应保持工具集合稳定、把新增内容追加在末尾」。
39
+ - 澄清并锁定一个此前的错误假设:`prompt_cache_key` 在订阅端**完全是 no-op**(实测:设与不设、相同与不同 key 均命中同一缓存)。我们仍发送它(与官方 CLI 行为一致且无害),但代码注释已改为如实说明,不再声称它能提高命中率。
40
+ - 新增 `test/kimi-code-identity.test.ts`(15 条:JWT 解码、`user_id` 优先于 `sub`、邮箱归一化、不透明 token 回退、账号解析与套餐来源、刷新补全身份、连接测试的成功/401/5xx 三分支)与 `test/kimi-code-routes.test.ts`(8 条:无额度时仍显示账号、status 携带 `quotaError`、显式刷新的成功与失败、连接测试的结论与延迟、未登录拒绝、目录与启用集合)。
41
+ - 新增 79 条单测:`test/kimi-code-oauth.test.ts`(设备码请求只带 client_id、区域主机切换、`expires_in`/`interval` 缺省回落、刷新对 502/429 的重试与对 401/invalid_grant 的立即失败、刷新阈值下限、并发共用刷新、被拒令牌不再重试)、`test/kimi-code-mapper.test.ts`(档位映射全表、未知档位不发送、temperature 被丢弃、`reasoning_content` 仅在带工具调用时回传、cache key 稳定、两条线路的请求形状与流式解码、usage 与工具增量拼接)、`test/kimi-code-adapter.test.ts`(重试策略取值、上文那类 502 判定为可重试、配额型 429 不重试、403 额度与 401 权限/凭据的区分、`Retry-After` 透传、目录与上下文覆盖)、`test/kimi-code-quota.test.ts`(四窗口标签与重置时间、字符串比例、越界钳制、两种响应形状、定点数换算、套餐名解析、模型目录能力)。
42
+ - 在 `README` 增补 Kimi Code 线路说明与故障排查条目,并更新客户端注册用例以覆盖新增的设置区块与额度胶囊。
43
+
44
+ - 修复 Command Code 额度卡片显示 `meter-1` / `meter-2` 的问题:`/alpha/billing/credits` 的窗口是按名字键控的(`windowLimits.fiveHour` / `weekly`),记录本身**只有数字没有名称字段**,此前的通用扫描找不到可用的 id/label,只能回退到序号占位。现在按名字读取该区块并套用官方 CLI 同款标签(`5-hour` / `Weekly`,另支持 `daily` / `monthly`),排序固定为最短窗口在前;`credits.monthlyCredits` / `purchasedCredits` / `freeCredits` 三笔余额也各自成条。通用扫描保留为兜底,并改为按对象身份跳过已读记录,避免同一份数据被重复上报。
45
+ - 修复 Command Code 套餐名称为空的问题:服务只在订阅(或账单)里给出机器 id(`individual-goat`),`/alpha/whoami` 完全不提套餐,因此卡片一直是空白。新增 `src/host/command-code/plans.ts`,转录官方 CLI 的套餐表(Go / GOAT / Pro / Pro / Provider / Max / Ultra / Teams Pro 及各自月度额度),按**最长前缀**匹配——`individual-pro` 同时是 `individual-pro-v1` 与 `individual-provider` 的前缀,按最短匹配会把 Provider 误判成 Pro;同时按服务实际大小写与 `_`/`-` 混用做归一化,未识别的 id 原样显示而不是隐藏。
46
+ - 额度卡片同时补齐订阅状态与续费日期(`active` / `trialing` / `past_due` 等)与套餐月度额度;余额解析此前查 `credits` 只会命中外层对象而返回 null(这也是余额一直空白的原因),现按三个池求和。
47
+ - 修正无名称的额度条目不再被静默丢弃:仍会展示,但改用可读标签(`Extra allowance`)与说明,而不是此前既不可读、又可能掩盖真实额度的 `meter-N`。
48
+ - 新增 `test/command-code-quota.test.ts`(13 条),fixture 为**从真实账号抓取的原样响应**:套餐名解析(含最长前缀与归一化)、订阅状态与周期、5 小时/周窗口的标签与毫秒级 resetAt 保真、窗口排序、三个余额池求和、无名称额度标签,以及 usage/summary 不产生伪额度。
49
+ - 修复 Command Code 线路按“厂商/模型名前缀”猜测模型能力的错误做法:模型是否支持图片输入、支持哪些思考深度,都改由官方 CLI 自带的模型能力表(`src/host/command-code/model-catalog.ts`)逐模型查表决定,未知模型回落到纯文本。此前的前缀启发式把 **DeepSeek V4.1 Flash 这类真正的视觉模型判成了纯文本**,导致设置页不声明图片能力、DSH 不会把粘贴的图片交给该线路。同类错误还有多处:`moonshotai/Kimi-K3`、`xai/grok-4.5`、`xai/grok-4.6`、`MiniMaxAI/MiniMax-M3`、`Qwen/Qwen3.8-*` 都被误判为纯文本;而 `deepseek/deepseek-v4-flash`、`deepseek/deepseek-v4-pro`、`zai-org/GLM-5.3` 才是纯文本——同一个厂商内部两种都有(`z-ai/glm-5.3-flash` 支持图片,`zai-org/GLM-5.3` 不支持),前缀判断无法区分。
50
+ - 思考深度同样改为查表:此前用 `['low','high','max']` / `['minimal','low','medium','high']` 等族级猜测覆盖所有模型,现在逐模型取注册表声明的集合(例如 `claude-*` 是 `low,medium,high,xhigh,max`,`gpt-5.4-mini` 是 `low,medium,high`,`deepseek/deepseek-v4-pro` 是 `high,max`,`claude-haiku-4-5` 与多数 Kimi/Qwen 模型没有思考档位)。
51
+ - 因此新增 `xhigh` 与 `minimal` 两个思考档位:`CommandCodeReasoningEffort` 联合类型、设置卡下拉、路由校验与偏好 schema 一并放开;Anthropic 线路的 `xhigh` 映射为 24576 thinking 预算(介于 `high` 16384 与 `max` 32768 之间),`minimal` 为 1024。
52
+ - 修复输出上限被误降到族级默认值的问题:注册表只为 5 个条目声明了 `maxTokens`,此前其余模型一律落到 32768。现在未声明的模型按多 provider 一致的 `limit.output` 补齐(Claude/GPT 系列 64K–128K、DeepSeek 384K、Kimi K3 131072、Grok 500K 等),注册表声明值优先。
53
+ - 新增 12 条用例锁定上述行为:逐模型模态(含 `deepseek-v4.1-flash` 支持图片、`deepseek-v4-flash` 不支持、GLM 同厂商正反例、Kimi/Grok/MiniMax/Qwen 视觉模型)、未知模型回落纯文本、逐模型思考档位(含空档位与 `xhigh`)、输出上限三级优先级,以及适配器对视觉模型发送内联图片的端到端路径。
54
+ - 新增 Command Code Provider(`command-code`),把 Command Code 的 Provider API 作为本插件的第三条线路接入 DSH:Anthropic 格式模型走 `https://api.commandcode.ai/provider/v1/messages`,其余(开源模型与 GPT 系列)走 `.../chat/completions`,两条线路各自把 DSH 的消息 / 工具 / 图片 / 流式协议映射到对应线上格式。模型 id 决定线路(`claude-*` 为 Anthropic),因为该 API 会拒绝把模型发到格式不符的端点。
55
+ - 浏览器登录复刻官方 CLI 的回环回调契约:本机 `127.0.0.1:5959` 起一次性回调服务器(端口占用时顺延,最多 10 个),打开 `https://commandcode.ai/studio/auth/cli?callback=…&state=…&mode=redirect`,Studio 页面以跨域 POST 回传 `{apiKey,state,userId,userName,keyName}`。因此回调端点实现了 CORS 预检(含 Chrome 的 `Access-Control-Allow-Private-Network`)、10 KB 体积上限、`state` 校验、授权拒绝(`access_denied`)路径,以及成功后 303 跳转到 `/callback/complete` 的人工可读页面。另提供“手动填写 API Key”入口作为无浏览器环境的兜底;两条路径都先用 `/alpha/whoami` 验证再落盘。
56
+ - 新增 `/command-code/api` 设置路由(status / login / login/status / login/apikey / logout / quota / models / settings / catalog/refresh / connection/test),修改状态的操作只接受同源 JSON POST。
57
+ - 设置页新增「Command Code」卡片:账号与密钥信息、连接状态与路由归属、模型勾选(含该模型走的线路)、默认思考深度、逐模型上下文窗口覆盖、额度与用量;对话输入框新增 `command-code` 线路的额度胶囊。
58
+ - 模型目录取自公开的 `/provider/v1/models`(含每个模型的 `context_length`),30 分钟缓存、可手动刷新;离线时回落到内置目录。上下文窗口默认取目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断)。
59
+ - 额度来自 `/alpha/billing/credits`、`/alpha/billing/subscriptions`、`/alpha/usage/summary` 与 `/alpha/whoami`:各线路独立容错(一条失败不影响其余),解析器按“带 limit/used/百分比的对象”通用识别而不绑定某个具体响应 schema,识别不出时给出空态而不是伪造 0%。
60
+ - Command Code 凭据(API Key)与 Antigravity 一样只存 Host:Windows 使用 CurrentUser DPAPI(`$DSH_HOME/storages/command-code-credentials.json.dpapi`),macOS 使用登录钥匙串,Linux 使用 Secret Service;明文 JSON 仅作为迁移来源,读取后加密回写并删除。凭据不会进入浏览器、`settings.yaml` 或日志。
61
+ - `command-code` 路由可能已被其他适配器占用(例如内置 `llm-pi-ai` 用同一端点声明过同名 Provider),而 DSH 的 `registerAdapter` 对重复路由是 all-or-nothing 并抛 `DUPLICATE_ADAPTER`。插件因此把注册做成“可用即接管”:冲突时不让插件加载失败,只在设置页显示路由归属与冲突原因,并监听 `llm/adapters-updated`——原占用方释放该路由后自动接管,无需重启。
62
+ - 新增 Kimi 系列的两项「能力补齐」(`src/host/kimi-code/modalities.ts`):
63
+ - **视频输入真正可用**,不再只是提示文字。DSH 的 `ModelModalityMap` 只有 `text` / `image`,但它是**可合并扩展的接口**,因此本插件用 TypeScript 模块增强把它扩成 `text` / `image` / `video`(`ContentBlockMap` 同理新增 `video` 块)——**没有改动 DSH 任何一行代码**,增强只存在于本插件的编译单元里。此前 `k3` / `kimi-for-coding` 的视频能力只能在设置卡里显示为说明文字;现在它是真实模态:`resolveModel` 会声明 video,适配器会把 `{ type: 'video', attachment }` 映射成服务文档的 `{ type: 'video_url', video_url: { url: 'data:video/mp4;base64,…' } }`(`api.kimi.com/coding` 的 OpenAI 线路)。
64
+ - 视频与图片**各有独立预算**:图片仍是文档的 2 MB 上限,视频按自己的 48 MiB base64 预算按「最旧优先」省略(一个视频片段就远超整段对话的图片额度,共用一个预算会让图片永远发不出去);请求体校验也据此只在**确实携带视频**时才放宽到 64 MiB,纯文本/图片请求仍按 2 MB 本地拦截。
65
+ - **不臆造未记录的字段**:`k3-256k` 只接受图片,选中它时视频会降级为明确的文字说明(提示改用 k3/kimi-for-coding);不在文档容器白名单内的格式(白名单来自官方 vision guide:mp4/mpeg/mov/avi/x-flv/mpg/webm/wmv/3gpp)同样降级并说明;而 **Anthropic Messages 线路没有文档化的视频内容块**,因此走该线路时视频一律降级为文字而不是猜一个字段名发出去。
66
+ - `dynamically_loaded_tools` 按官方线格式实现:K3 接受**消息级工具声明**(`messages[].tools`),即可在会话中途以「无 `content` 字段的 `system` 消息」注入完整工具定义(`{ name, description, parameters }` 三元组,服务拒绝只给工具名)。这正是**保护前缀缓存**的手段——官方文档明确把「保持顶层 `tools` 字节稳定」列为该特性目的之一(顶层工具变化、或中途修改/删除已发出的声明都会使缓存从该点起失效,而在末尾追加不影响缓存前缀)。本插件提供 `withMessageTools()` 在 system 消息上挂声明,映射器按历史顺序输出;声明按请求重发(服务端不保留),且仅在模型声明该能力时发送,否则降级为一条说明消息而不是发出必然 400 的请求。
67
+ - 能力判定统一走「实时 `/v1/models` > 内置注册表」:listing 的 `supports_video_in` / `supports_dynamic_tools` 直接采信,离线回落内置表(`k3` / `k3-256k` 具备动态工具加载,`kimi-for-coding` 系列不具备)。设置卡把两项能力显示在模型旁。
68
+ - 修复动态工具声明**位置被提升**的问题:首版把历史里所有 `messages[].tools` 声明收集后统一发在请求最前面,但 Kimi 的缓存是**前缀匹配**——把声明放到它首次发出位置之前会重写缓存前缀并使已缓存对话失效,恰好破坏该特性存在的唯一理由。现在每条声明按其在历史中的真实位置插入(`flushSlots` 按「非 system 消息数」定位并交错输出),因此**末尾追加**仍是缓存安全的追加,而中途新增的声明不会前移。
69
+ - 修复 `isAbort` 用 `instanceof Error` 判定取消的缺陷:DSH 的 `LlmError` **不是 Error 子类**,所以在真实调用链上取消会被误判为「读取失败」并降级成模型可见的占位文本——把用户主动取消变成了一个错误答案。改为按 `name === 'AbortError'` 结构化判定,并保留 `signal.aborted` 短路。
70
+ - 声明所在 system 消息**同时带有文本**时不再静默丢弃:服务的动态工具 schema 没有 `content` 字段,两者无法合成一条消息,因此现在保留文本(另发一条),并把声明替换为明确的说明消息,而不是让工具无声消失。
71
+ - **按官方 CLI 的能力表逐模型修正两项能力**(依据 `managed:kimi-code` 托管模型表里每个模型的 `capabilities` 列表):`k3` = image_in + video_in + dynamically_loaded_tools;`k3-256k` = image_in + **dynamically_loaded_tools**(无 video);`kimi-for-coding` = image_in + video_in + **dynamically_loaded_tools**;`kimi-for-coding-highspeed` = image_in + video_in(**无** dynamically_loaded_tools)。修正了先前把 `dynamically_loaded_tools` 当成「K3 独有」的推导错误——官方线文档只提 K3 是因为它描述的是 K3 的请求 schema,而 CLI 自己的能力表把它也标给了 K2.8 Preview。
72
+ - 修正能力判定与官方表格的一致性(已对照 https://www.kimi.com/code/docs/en/kimi-code/models.html 逐项核对):`k3` 与 `kimi-for-coding` 为「Image, video」、`k3-256k` 为「Image only」,与内置表一致;`kimi-for-coding-highspeed` 官方标为 K2.7 Code HighSpeed,「Thinking: ON」且无可选档位,故其固有档位仍按官方标注为 `high`。
73
+ - **重排模型能力展示**:此前把能力说明当成长句塞在模型名那一列,把名称列撑开、右侧描述错位。现改为独立的四列表格(模型 / 多模态 / 动态工具 / 说明):能力只显示短标签(视频 / 仅图片 / 动态工具 / —),逐模型的协议、默认思考档位与所需套餐移入悬停提示;表格自身不再附带任何解释段落。表格抽成可测组件 `KimiModelCapabilities`(`src/client/kimi-code/KimiModelCapabilities.tsx`),新增 `test/kimi-code-capability-ui.test.tsx`(5 条)钉住列数、每模型一行、长句不得进入单元格、悬停内容,以及说明为空时不渲染 `null`。该表也**不再依赖 `description` 是否存在**——实时目录条目缺描述时整个表格(含能力)仍渲染。
74
+ - 澄清并测试这两项能力的**跨模型隔离**:机制本身有三重隔离——符号载体**不可枚举**(其他线路的序列化器看不到它)、映射器只在 `messageTools === true` 时输出、且声明只存在于 Kimi 的 OpenAI 线路映射中。新增 `test/kimi-code-capability-isolation.test.ts`(6 条):Command Code 各模型仍不含 video(证明模块增强是**纯类型、不产生运行时值**)、Kimi 四个模型 id 的 video 与 dynamically_loaded_tools 与官方能力表**逐项**一致(并断言两者并非同一集合:HighSpeed 有 video 却无动态工具)、视频块不会出现在兄弟线路的请求体里、同一段历史里的声明也不会被兄弟线路带出去。
75
+ - 另记录一个**证据取舍**:公共 `models.dev` 目录虽声明了 `dynamically_loaded_tools` 字段,但 Moonshot 自家四个条目均未标注,故本插件**不采信该目录**,改以官方 CLI 托管模型表的 `capabilities` 为准;运行时仍以实时 `/v1/models` 的 `supports_dynamic_tools` / `supports_video_in` 覆盖内置表。
76
+ - 新增 `test/kimi-code-declaration-position.test.ts`(7 条回归用例):声明按历史位置交错(含前后两条声明之间有对话的情形)、末尾追加落在队尾且前缀不变、首条声明仍在队首、文本与声明同处一条消息时保留文本并给出说明、以及取消检测在「非 Error 的 AbortError 对象」与「signal 已 abort」两条真实路径上都向上抛出、而真正的读取失败仍降级。这 7 条在把两个缺陷临时改回后**确有 3 条失败**(位置 2 条 + 取消 1 条),确认它们是真的回归用例而非同义反复。
77
+ - 新增 `test/kimi-code-capabilities.test.ts`(24 条):模态词表与容器白名单、视频解析与缺字节/无 reader 的降级、最旧优先省略、两种模型能力下的线级视频形状、Anthropic 线路绝不发未记录字段、消息级工具声明的符号载体(不污染 `Object.keys`)、`content` 字段不得出现、能力缺失时的降级、历史顺序保持、以及请求体预算(纯文本仍按 2 MB 拒绝、带视频才放宽)。另有 3 条既有断言随行为变更更新(`inputModalities` 现含 `video`)。
78
+ - 新增 80 条单测:`test/command-code-mapper.test.ts`(两条线路的请求映射、图片内联与超限省略、OpenAI/Anthropic 流式解码、工具调用增量拼接、usage 与 finish reason、截断流拒绝)、`test/command-code-oauth.test.ts`(回环回调服务器:CORS 预检、表单/JSON 回调、state 校验、拒绝路径、303 跳转、宽限期发布)、`test/command-code-routes.test.ts`(账户/额度/目录解析、模型选项与启用集合、设置路由与同源校验)、`test/command-code-adapter.test.ts`(目录、上下文覆盖、两条线路的端到端流式与工具往返、缺凭据/401/429/截断的错误分类)、`test/command-code-store.test.ts`(凭据校验、模型设置文件、设置卡与胶囊的纯函数)、`test/command-code-plugin.test.ts`(插件装配、路由接管与释放后自动接管)。
5
79
  - 修复开启系统代理的机器上 `web_fetch` 必然失败的问题:DSH 内置抓取 provider 在连接前解析、校验并固定目标地址,而代理工具(Clash/Mihomo 等)的 fake-ip DNS 会把域名解析成 `198.18.0.0/15` 里的保留地址(实测 `api.github.com` → `198.18.0.17`),于是每次调用都以 `WEB_BLOCKED_URL`(`resolves to a non-public IP address`)结束——代理根本没被用上。DSH 只在进程环境变量里读到代理时才走代理,看不到系统代理。现在只要插件配置了可用代理(系统代理自动检测或自定义代理),`web_fetch` 就改用本插件的抓取 provider:由代理解析源站,与 DSH 对“走代理的请求”采用的语义一致;未配置代理时仍由内置 provider 抓取,其解析与固定策略不变。
6
80
  - 抓取 provider 新增地址策略 `src/host/fetch-address-policy.ts`,保留内置 provider 安全边界中不需要 DNS 的那一半:URL 里写明的 IP 字面量只有全球可路由单播才放行(loopback、私网、链路本地、CGNAT、多播、保留地址、IPv6 转换与隧道前缀一律拒绝);域名用本机解析器检查一次,落在私网(含 `localhost`、`127.0.0.1.nip.io` 这类)一律拒绝;只有代理的 fake-ip 答案被接受,本机解析不出的域名交给代理处理。与内置 provider 的差别是不再固定(pin)连接地址——fake-ip 环境下这一步无法成立,已在 README 的安全边界中写明。
7
81
  - 代理偏好在运行时变化(例如系统代理 ↔ 直连)会重新选择抓取后端;选择 ChatGPT 搜索来源时同时切换搜索与抓取的行为保持不变。
package/README.md CHANGED
@@ -11,6 +11,8 @@
11
11
  - [环境要求](#环境要求)
12
12
  - [安装](#安装)
13
13
  - [使用](#使用)
14
+ - [Kimi Code 线路](#kimi-code-线路)
15
+ - [Command Code 线路](#command-code-线路)
14
16
  - [子代理模型授权](#子代理模型授权0215-起)
15
17
  - [升级、降级与卸载](#升级降级与卸载)
16
18
  - [安全边界](#安全边界)
@@ -38,6 +40,32 @@
38
40
  - 新增 `codex_image_generate` 工具,生成图片后通过 DSH 附件系统保存并在会话中渲染;
39
41
  - 可选 composer 快捷用量徽标,按当前 `codex-chatgpt` 模型显示最紧张窗口的剩余额度。
40
42
 
43
+
44
+ **Command Code 线路**
45
+
46
+ - 注册 `command-code` Provider,使用 Command Code 的 Provider API 与账户 API;模型 id 决定线路:`claude-*` 走 Anthropic Messages(`/provider/v1/messages`),其余模型走 OpenAI Chat Completions(`/provider/v1/chat/completions`),因为该 API 会拒绝把模型发到格式不符的端点;
47
+ - 浏览器登录复刻官方 CLI 的回环回调契约(`127.0.0.1:5959` 起顺延,`/callback` 接受 Studio 页面的跨域 POST),也可在设置页手动粘贴 API Key;两条路径都先用 `/alpha/whoami` 验证再加密保存;
48
+ - 模型目录取自公开的 `/provider/v1/models`,每个模型的 `context_length` 作为默认上下文窗口,可逐模型覆盖;
49
+ - **模型能力逐模型查表**(`src/host/command-code/model-catalog.ts`,转录自官方 CLI 的模型注册表):是否接受图片输入、支持哪些思考档位由该表决定,未知模型回落纯文本。图片能力不能靠厂商/模型名前缀推断——`deepseek/deepseek-v4.1-flash` 与 `deepseek/deepseek-v4-flash-vision-exp` 支持图片而 `deepseek/deepseek-v4-flash`、`deepseek/deepseek-v4-pro` 不支持,`z-ai/glm-5.3-flash` 支持而 `zai-org/GLM-5.3` 不支持;
50
+ - 额度与用量来自账户 API 的账单/用量线路,任一条失败不影响其余;
51
+ - **瞬时失败按 DSH retry policy 有界重试**:`command-code` 路由显式声明 `normal` 策略(最多 3 次,1.5s 起指数退避、15s 上限、0.2 抖动),覆盖 `RATE_LIMIT`、`SERVER`、`TIMEOUT`、`TRANSPORT`。上游模型供应商临时不可用(502/503/504/500,典型响应体是 `{"error":{"type":"server_error"}}`)被归类为 `SERVER` 并自动重试,429 会带上上游的 `Retry-After` 让退避按对方的节奏走;401/403 与 `ABORTED` 明确不重试;
52
+ - 模型勾选(含线路标签)、思考深度、上下文窗口覆盖与额度在「设置 → 订阅服务 → Command Code」标签页中配置,输入框右侧另有额度胶囊。
53
+
54
+ **Kimi Code 线路**
55
+
56
+ - 注册 `kimi-code` Provider,接入 Moonshot 的 **Kimi Code 订阅**(`https://www.kimi.com/code`)。它与 Moonshot 开放平台(pay-as-you-go)是两套互不通用的系统:订阅的模型接口是 `https://api.kimi.com/coding/v1`,凭据只来自订阅 OAuth;把开放平台的 key 或 base URL 用在这里会被判为 `401 Invalid Authentication`;
57
+ - 登录用 **RFC 8628 设备码流程**(`auth.kimi.com`):设置页点「设备码登录」后直接展示用户码与一次性链接(浏览器会自动打开),装好后无需回调端口、无浏览器环境也能手工完成;`slow_down` 会按 RFC 调宽轮询间隔,设备码过期会自动重新申请而不是直接失败;
58
+ - 访问令牌到期前按 `max(300s, expires_in×0.5)` 自动续期,同进程并发调用共用一次刷新;被拒的 refresh token 进入冷却并提示重新登录;
59
+ - **瞬时失败按错误类别重试**(`src/host/kimi-code/adapter.ts`)。上游模型供应商临时不可用(典型是 502 `{"error":{"message":"Upstream model provider is temporarily unavailable. Please try again in a moment.","type":"server_error"}}`)、真正的 429 背压(`too many requests` / `engine is currently overloaded`)、连接失败与流停滞都会走有界退避(最多 3 次,1.5s 起步、15s 上限、0.2 抖动),并遵守上游的 `Retry-After`;而**配额耗尽型的 429、403 的账号额度上限、401 里的套餐权限不足、400 请求格式错误都不重试**——服务把这些含义压进同一个状态码,因此分类读响应正文而不只看状态码,重试无望时直接给出可操作的提示(换模型 / 降上下文 / 等窗口重置 / 重新登录);
60
+ - 模型目录为订阅侧的四款模型:`k3`(1M 上下文,需 Allegretto+;Moderato 上限 256K,故默认按 256K 计算,可用上下文覆盖升到 1M)、`k3-256k`、`kimi-for-coding`(K2.8 Preview)、`kimi-for-coding-highspeed`(约 6× 速度、3× 额度),运行时以 `GET /v1/models` 为准;
61
+ - **K3 行为按其官方文档实现**:思考档位只发 \`low\` / \`high\` / \`max\`(其余写法收敛映射,未知档位不发送),关闭思考发 \`thinking:{type:"disabled"}\`,开启时发 \`thinking:{type,effort,keep:"all"}\`;**开启思考时每条 assistant 消息都回传 \`reasoning_content\`**(无推理则回传空串——服务要求的是空值而非省略,否则 400);不发送 \`temperature\`(采样参数按模型固定,显式值会报错);工具调用 id 截断到 64 字符;\`stop\` 按上限裁剪为最多 5 条、每条 ≤32 字节,超长整条丢弃(截断的停止串会在错误位置终止生成);
62
+ - **K3 的长思考不会被截断**:输出上限跟随上下文窗口(保留 4096 余量),因为 \`reasoning_content\` 计入输出,固定 32K 会把 \`max\` 档的长推理中途截断并返回 \`length\`;调用方已知 prompt 规模时上限会被下调到放得下,未知时不做猜测;
63
+ - **请求体超 2 MB 本地即拒绝**:该端点最常见的 400 是 \`total message size N exceeds limit 2097152\`,官方文案不给建议,这里直接按真实序列化体积拦截并提示压缩会话或检查大工具结果;
64
+ - **缓存是自动的,且无法手动干预**:Kimi 按请求内容哈希命中前缀缓存,实测 \`prompt_cache_key\` 与 Anthropic \`cache_control\` 标记**均被忽略**(设与不设、同 key 与异 key 命中的是同一缓存),设备 id 与协议切换也不影响;TTL 实测在 300–1800 秒之间,按 256 token 对齐,\`/messages\` 与 \`/chat/completions\` **共享同一缓存**。真正决定命中率的是**内容稳定性**:同一会话内 \`system\` 或工具列表一旦变化会使整个前缀缓存失效(实测归零),因此应保持工具集合稳定、把新增内容追加在末尾。卡片会显示滚动命中率,方便验证效果;
65
+ - **视频输入可用**(`k3`、`kimi-for-coding`):DSH 的模态词表只有 `text`/`image`,但它是可合并扩展的接口,本插件用 TypeScript 模块增强把它扩到 `video`(**未改动 DSH 任何代码**),因此视频走 DSH 真实的能力通道,而不是只能显示在提示里。适配器把视频映射为服务文档的 `{type:'video_url',video_url:{url:'data:…'}}`。视频与图片**各有独立预算**(图片 2 MB、视频 48 MiB base64,最旧优先省略),请求体校验只在确实带视频时才放宽到 64 MiB。`k3-256k` 只接受图片、文档白名单外的容器、以及未文档化视频内容块的 **Anthropic 线路**,都会把视频降级为明确的文字说明而不是猜字段发出去;
66
+ - **`dynamically_loaded_tools`(仅 K3)已实现**:K3 接受**消息级工具声明**(`messages[].tools`),可在会话中途用「无 `content` 字段的 system 消息」注入完整工具定义。官方把「保持顶层 `tools` 字节稳定」列为该特性的目的之一——中途修改/删除已发出的声明会使缓存从该点起失效,而在末尾追加不影响已缓存前缀,所以这是提升缓存命中的正道。声明按请求重发(服务端不保留),且仅在模型声明该能力时发送;
67
+ - 额度卡片区分 **5 小时 / 7 天 / 月度(会员共享池)/ 月度(Kimi Code 池)** 四个窗口并显示重置时间,另可显示加油包余额;设置页为「设置 → 订阅服务 → Kimi Code」标签页,对话输入框右侧有该线路的额度胶囊。
68
+
41
69
  **设置页**
42
70
 
43
71
  - 展示账号(脱敏 email、套餐、账号 ID 后四位)、连接状态、额度与订阅增强功能开关;
@@ -122,6 +150,23 @@ DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。6 Astra 与 G
122
150
 
123
151
  **设置 → Codex 订阅 → 网络代理** 同时控制 GPT 与 Antigravity(Gemini)的 Host 请求,可选择系统代理(自动检测)、自定义代理或直连。Gemini 模型生成、网页登录后的令牌交换、令牌刷新、账号信息、项目发现、配额与模型目录查询均使用此设置;修改后对后续请求生效,无需重启 DSH。浏览器中的 Google 授权页面使用浏览器自己的网络设置。
124
152
 
153
+ ### Command Code
154
+
155
+ 1. 重启 `dsh web`;
156
+ 2. 打开 **设置 → Command Code**;
157
+ 3. 点击 **浏览器登录**(或把 Command Code Studio 里创建的 API Key 粘到「手动填写 API Key」里保存);
158
+ 4. 登录完成后按需勾选模型、设置上下文窗口与默认思考深度。
159
+
160
+ `command-code` 会像其他 Provider 一样出现在 DSH 模型选择器中。线路按模型 id 自动选择:`claude-*` 走 Anthropic Messages,其余走 OpenAI Chat Completions;设置卡片的模型标签会显示每个模型对应的线路。
161
+
162
+ **路由归属**:DSH 的 `registerAdapter` 对重复 Provider 是 all-or-nothing 并抛 `DUPLICATE_ADAPTER`,因此若 `command-code` 已被别的适配器占用(典型情况是内置 `llm-pi-ai` 用同一端点声明过同名 Provider),本插件不会加载失败,而是在卡片上显示“模型路由已被其他 Provider 占用”;从占用方的配置里移除该 Provider 后,插件会在下一次路由变更事件时自动接管,无需重启 DSH。
163
+
164
+ **上下文窗口**默认取 Command Code 模型目录的 `context_length`,可在卡片中逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `512K` / `200000` 等写法)。**默认思考深度**逐模型生效:下拉里列出的档位可按模型能力选用(`minimal` / `low` / `medium` / `high` / `xhigh` / `max`),实际发给上游前会按当前模型声明的档位取值——模型不声明该档位时不发送。对 Anthropic 线路映射为 `thinking` 预算(`minimal` 1K / `low` 2K / `medium` 8K / `high` 16K / `xhigh` 24K / `max` 32K),预算放不下时该请求不启用 thinking;对 OpenAI 线路映射为 `reasoning_effort`。
165
+
166
+ **额度**来自 `/alpha/billing/credits`、`/alpha/billing/subscriptions` 与 `/alpha/usage/summary`,三条线路相互独立容错,页面可见时最多每 60 秒刷新一次;解析不出有界额度时显示空态而不是 0%。
167
+
168
+ 额度卡片展示:**套餐名**(由订阅返回的机器 id 查表得出,表在 `src/host/command-code/plans.ts`,按最长前缀匹配)、**订阅状态与续费日期**、**滚动窗口用量**(`windowLimits` 的 `fiveHour` / `weekly`,按官方 CLI 同款标签 `5-hour` / `Weekly` 显示,并各自带重置倒计时),以及**余额明细**(月度额度 / 已购额度 / 赠送额度,另附合计)。服务只回报数字不回报名称的字段一律补上可读标签——窗口按 key 命名,余额按池命名,实在没有名字的兜底为 `Extra allowance` 并注明来源,不会渲染成 `meter-1` 这类无意义编号。
169
+
125
170
  **搜索与抓取来源** 切换 DSH 的搜索后端;网页抓取后端在有可用代理时自动改用本插件。选择 ChatGPT 来源后,网页由本插件在 Host 抓取,并使用上述网络代理设置;纯 TUN 模式可使用直连,流量由虚拟网卡接管。来源切换即时生效,DSH web 服务重载后会重新注册插件后端,并保留切回 DSH 默认来源所需的配置。
126
171
 
127
172
  **网页抓取后端(web_fetch)** DSH 内置抓取 provider 会先解析域名、校验并固定解析结果,而且只在进程环境变量里读到代理时才走代理——系统代理对它不可见。代理工具(Clash/Mihomo 等)常把域名解析成自己的 fake-ip 地址(默认 `198.18.0.0/15`),于是内置 provider 直接以 `WEB_BLOCKED_URL`(resolves to a non-public IP address)拒绝,代理根本没被用上。因此只要插件配置了可用代理(**网络代理** 选系统代理且检测到,或填写自定义代理),`web_fetch` 就改用本插件的 provider:由代理解析源站,与 DSH 对“走代理的请求”采用的语义一致;未配置代理时仍由 DSH 内置 provider 抓取,保留其解析与固定策略。若在纯 TUN 模式下把代理设为**直连**,内置 provider 会重新接管,此时可改回系统代理让插件接管抓取。代理如果在 DSH 启动之后才可用(代理工具后启动,或首次探测失败),插件会在下一次探测到代理时重新选择抓取后端,不必重启或改设置。
@@ -157,6 +202,61 @@ DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允
157
202
 
158
203
  改动只在设置卡片里保存过的勾选生效:设置改动只影响之后新建的会话(DSH 的会话快照语义),已运行的会话继续使用它自己记录的那份列表。
159
204
 
205
+ ### Kimi Code
206
+
207
+ 1. 重启 `dsh web`;
208
+ 2. 打开 **设置 → Kimi Code**;
209
+ 3. 点击 **设备码登录**,在弹出的浏览器页面确认授权(页面已预填用户码;也可手工复制用户码到 `verification_uri`);
210
+ 4. 登录完成后按需勾选模型、设置默认思考档位与上下文窗口。
211
+
212
+ `kimi-code` 会像其他 Provider 一样出现在 DSH 模型选择器中。**上下文窗口**默认取模型目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `256K` / `200000` 等写法)——注意 `k3` 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算,升级后再在此覆盖为 1M。**默认思考档位**只提供 `low` / `high` / `max` 三档与「关闭思考」(服务对这三档以外的取值直接报 400);切换模型或切换档位都会使上下文缓存失效,建议在同一会话内保持一致。
213
+
214
+ **区域**:默认使用中国大陆主机(`auth.kimi.com` / `api.kimi.com`)。国际账号可设置 `DSH_KIMI_CODE_OAUTH_HOST=https://auth.kimi.ai` 与 `DSH_KIMI_CODE_BASE_URL=https://api.kimi.ai/coding` 后重新登录;环境变量同时会钉住区域,设置页会显示当前解析到的主机。
215
+
216
+ ## Command Code 线路
217
+
218
+ 插件注册 `command-code` Provider,对接 Command Code 的两套接口:
219
+
220
+ | 用途 | 地址 |
221
+ | --- | --- |
222
+ | 模型生成(Anthropic 格式) | `https://api.commandcode.ai/provider/v1/messages` |
223
+ | 模型生成(OpenAI 格式) | `https://api.commandcode.ai/provider/v1/chat/completions` |
224
+ | 模型目录(公开) | `https://api.commandcode.ai/provider/v1/models` |
225
+ | 账号信息 | `https://api.commandcode.ai/alpha/whoami` |
226
+ | 额度与用量 | `/alpha/billing/credits`、`/alpha/billing/subscriptions`、`/alpha/usage/summary` |
227
+ | 浏览器登录页 | `https://commandcode.ai/studio/auth/cli` |
228
+
229
+ 模型 id 决定线路(`claude-*` 为 Anthropic),这也决定了请求体形态:Anthropic 线路的系统提示词放在顶层 `system`、工具用 `input_schema`、工具结果用 `tool_result` 内容块;OpenAI 线路的系统提示词是 `messages[0]`、工具用 `function.parameters`、工具结果用 `role: "tool"`。两条线路都只把 DSH 交付的可见文本、图片与工具调用发出去——reasoning 块不会被回放,因为这里的上游都不接受缺少签名的思考块。
230
+
231
+ **模型能力表**(`src/host/command-code/model-catalog.ts`)逐模型声明 `inputModalities`、`reasoningEfforts`、`contextWindow` 与可选的输出上限,内容转录自官方 CLI 的模型注册表——公开的 `/provider/v1/models` 只有 id、名称与 `context_length`,既不说模态也不说思考档位,而族级前缀推断在同一厂商内部就会出错(见上)。模型不在表内时按纯文本、无思考档位处理:DSH 会把图片转成一条可见的占位文本让用户改选模型,而反过来把图片发给不接受它的端点会让整个请求失败。
232
+
233
+ 图片以 base64 内联(OpenAI 线路 `image_url` 的 `data:` URL,Anthropic 线路 `image` 块的 `base64` source);单次请求的图片负载超过 12 MiB 时按最旧优先替换为本插件同款占位文案。读不出字节的图片降级为可见说明文本,不会被静默丢弃。
234
+
235
+ **失败分类与重试**:`command-code` 路由在注册时携带一份显式的 `normal` retry policy(`maxRetries: 3`、`initialDelayMs: 1500`、`maxDelayMs: 15000`、`jitterRatio: 0.2`),可重试码为 `RATE_LIMIT`、`SERVER`、`TIMEOUT`、`TRANSPORT`——与 `codex-chatgpt` 路由同源,只是未包含该路由的历史码 `SERVER_ERROR`/`NETWORK`。分类规则:HTTP 5xx(含上游 502)→ `SERVER`;连接层失败(fetch 抛错)→ `TRANSPORT`;429 → `RATE_LIMIT` 并附 `Retry-After`(上限 10 分钟);401/403 → `INVALID_CREDENTIAL`(换 Key,不重试);流式空闲超时由看门狗转成 `TIMEOUT`。策略由 DSH 的 `dsh-llm-retry` 插件在 `agent/request-error` 上执行,每次重试都会写入 `llm/retry` 会话事件。
236
+
237
+ **凭据存储**:API Key 使用与 Antigravity 相同的系统凭据存储——Windows 是 CurrentUser DPAPI(`$DSH_HOME/storages/command-code-credentials.json.dpapi`),macOS 是登录钥匙串,Linux 是 Secret Service(服务名 `dsh-command-code`,账号键按旧凭据文件绝对路径生成)。旧版明文 JSON 只作为迁移来源,读取后加密回写、校验并删除;注销会同时清理两者。凭据只存在于 Host 内存与系统凭据存储中,不会进入浏览器、`settings.yaml` 或日志。
238
+
239
+ **浏览器登录的回环服务器**只在 `127.0.0.1` 上监听 5959 起的空闲端口,只接受与该次登录 `state` 匹配的回调,10 KB 请求体上限,5 分钟超时;回调成功后浏览器标签页会跳到 `/callback/complete` 上的人工可读页面。登录成功后 Studio 页面回传的 API Key 会先经 `/alpha/whoami` 验证,验证失败的 Key 不会被保存。
240
+
241
+ ### 插件路由(Command Code)
242
+
243
+ 所有路由都以 `/command-code/api` 为前缀:
244
+
245
+ | 方法 | 路径 | 说明 |
246
+ | --- | --- | --- |
247
+ | GET | `/status` | 账号(脱敏)、额度、模型目录与路由归属 |
248
+ | POST | `/login` | 开始浏览器登录,返回登录页地址 |
249
+ | GET | `/login/status` | 查询登录进度 |
250
+ | POST | `/login/apikey` | 校验并保存手动填写的 API Key |
251
+ | POST | `/logout` | 注销并清理凭据与缓存 |
252
+ | GET / POST | `/quota` | 强制刷新额度(POST)或读取当前状态(GET) |
253
+ | GET / POST | `/models` | 读取或更新勾选的模型与上下文窗口 |
254
+ | POST | `/settings` | 更新默认思考深度与上下文窗口覆盖 |
255
+ | POST | `/catalog/refresh` | 强制刷新模型目录 |
256
+ | POST | `/connection/test` | 用已存凭据调用 `/alpha/whoami` 测试连接 |
257
+
258
+ 与 `codex-chatgpt` 线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 `Origin` 与 `Host`。
259
+
160
260
  ## 安全边界
161
261
 
162
262
  Antigravity 的 access token / refresh token 使用独立的系统凭据存储:Windows 使用 CurrentUser DPAPI(`$DSH_HOME/storages/antigravity-oauth.json.dpapi`),macOS 使用登录钥匙串,Linux 使用 Secret Service。macOS / Linux 的服务名为 `dsh-antigravity`,账号键按旧凭据文件的绝对路径生成,隔离不同的 `DSH_HOME`。
@@ -219,4 +319,18 @@ npm pack --dry-run
219
319
  | `web_fetch` 报 `resolves to a non-public IP address` | 机器启用了系统代理(fake-ip DNS),但插件没有可用代理可接管抓取:在 **设置 → Codex 订阅 → 网络代理** 选择系统代理(自动检测)或填写自定义代理 |
220
320
  | DPAPI 读取失败 | 确认 DSH 以创建凭据时的同一 Windows 用户运行;必要时清理凭据后重新登录 |
221
321
  | Linux 凭据存储不可用 | 确认凭据属于当前用户且权限为 `0600`,父目录权限为 `0700`;修复权限或注销后重新登录 |
222
- | Linux 上工具调用语法错误 | 确认 DSH 暴露的是 `bash`、`sh` 或 `shell`,并使用相应的 Bash/POSIX 语法与 `/` 路径 |
322
+ | Linux 上工具调用语法错误 | 确认 DSH 暴露的是 `bash`、`sh` 或 `shell`,并使用相应的 Bash/POSIX 语法与 `/` 路径 |
323
+ | `command-code` 模型不出现在选择器里 | 卡片上若显示“模型路由已被其他 Provider 占用”,从占用方(常见是 `llm-pi-ai` 的 `command-code` 条目)移除该 Provider,插件会在下一次路由变更时自动接管;否则检查是否勾选了模型 |
324
+ | Command Code 登录失败 | 确认 5959–5968 端口未被占用;无浏览器环境改用手动填写 API Key;`state` 校验失败时重开一次登录 |
325
+ | Command Code 返回 401 | 设置页重新登录或重新粘贴 API Key;插件不会保存无法通过 `/alpha/whoami` 的 Key |
326
+ | Claude 模型报格式错误 | 该 API 只接受把 `claude-*` 发到 `/messages`;请使用插件自动选择的线路,不要手工把 Claude 模型指向 OpenAI 端点 |
327
+ | Command Code 额度显示为空 | 账户 API 的账单/用量线路可能只对部分套餐开放;空态是解析不出有界额度时的正常表现,可点「刷新用量」重试 |
328
+ | Command Code 报 502 `Upstream model provider is temporarily unavailable` | 这是上游模型供应商的瞬时故障,不是账号或 API Key 的问题:插件会按 DSH retry policy 自动重试(最多 3 次);连续失败即换用同一账号下的其他模型,或稍后再试 |
329
+ | Kimi Code 登录后立即失效 | 设备码只有几分钟有效期;重新点「设备码登录」即可。若刷新令牌被拒,卡片会明确提示重新登录(插件不会反复重试被拒的令牌) |
330
+ | Kimi Code 返回 401 `does not have access to k3` / `supports only … up to … context` | 这是**套餐权限**而非凭据问题:`k3` 需 Moderato 及以上、其 1M 上下文需 Allegretto 及以上。换用 `kimi-for-coding` 或 `k3-256k`,或把该模型的上下文覆盖降到 256K |
331
+ | Kimi Code 返回 403 `reached your … usage limit` | 账号额度用尽(5 小时 / 7 天 / 月度共享池)。卡片会显示各窗口的重置时间;共享池耗尽时即使 Kimi Code 池还有余额也会被拒 |
332
+ | Kimi Code 报 502 `Upstream model provider is temporarily unavailable` | 上游模型供应商的瞬时故障,与账号、模型、凭据都无关:插件会按 DSH retry policy 自动重试(最多 3 次,并遵守上游 `Retry-After`);连续失败可稍后再试或换用同账号下其他模型 |
333
+ | Kimi Code 报 429 `engine is currently overloaded` | 服务容量问题(工作日 14:00–17:00 高峰更常见),会自动退避重试;若响应里带 `error.type = exceeded_current_quota_error` 则属于配额耗尽,插件不会重试而是提示补充额度 |
334
+ | Kimi Code 额度显示为空 | 卡片会同时给出失败原因(`/v1/usages` 的 401/403/5xx 文案),按提示处理后点「刷新用量」重试;确认用的是订阅账号——开放平台的 key 在这里不会被接受 |
335
+ | Kimi Code 账号一栏为空 | 账号身份取自 OAuth token 自身的 JWT 声明,套餐名取自 `/me`(`/usages` 自 2026-09 起不再返回 `user_level_name`)。重新登录或点「刷新用量」即可写入;若仍为空但显示「已登录」,点「测试连接」可确认凭据是否仍被接受 |
336
+ | Kimi Code 发送视频却没有画面 | `k3-256k` 不支持视频,切到 `k3` 或 `kimi-for-coding`;容器须在白名单内(mp4/mpeg/mov/avi/x-flv/mpg/webm/wmv/3gpp);若该模型走的是 Anthropic 线路,视频会降级为文字(该协议没有文档化的视频块)。以上情况模型都会收到明确的文字说明,据此向你说明而不是凭空回答 |