@eddyskywalker/dsh-chatgpt-subscription 0.7.0 → 0.8.0-alpha.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 (83) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +20 -7
  3. package/lib/client.js +43 -11
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +3963 -2754
  6. package/lib/types/client/antigravity/locales.d.ts +2 -2
  7. package/lib/types/client/command-code/locales.d.ts +2 -2
  8. package/lib/types/client/index.d.ts.map +1 -1
  9. package/lib/types/client/kimi-code/locales.d.ts +2 -2
  10. package/lib/types/client/locales.d.ts +5 -5
  11. package/lib/types/host/agent-preset.d.ts +113 -0
  12. package/lib/types/host/agent-preset.d.ts.map +1 -0
  13. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  14. package/lib/types/host/antigravity/mapper.d.ts +2 -2
  15. package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
  16. package/lib/types/host/antigravity/token-store.d.ts +1 -2
  17. package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
  18. package/lib/types/host/codex-images.d.ts.map +1 -1
  19. package/lib/types/host/command-code/adapter.d.ts.map +1 -1
  20. package/lib/types/host/command-code/mapper.d.ts +2 -2
  21. package/lib/types/host/command-code/mapper.d.ts.map +1 -1
  22. package/lib/types/host/command-code/token-store.d.ts +4 -5
  23. package/lib/types/host/command-code/token-store.d.ts.map +1 -1
  24. package/lib/types/host/common/account-pool.d.ts +24 -0
  25. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  26. package/lib/types/host/common/file-preferences.d.ts +49 -0
  27. package/lib/types/host/common/file-preferences.d.ts.map +1 -0
  28. package/lib/types/host/common/legacy-preferences.d.ts +29 -0
  29. package/lib/types/host/common/legacy-preferences.d.ts.map +1 -0
  30. package/lib/types/host/common/llm-compat.d.ts +92 -0
  31. package/lib/types/host/common/llm-compat.d.ts.map +1 -0
  32. package/lib/types/host/common/settings-compat.d.ts +55 -0
  33. package/lib/types/host/common/settings-compat.d.ts.map +1 -0
  34. package/lib/types/host/compaction-patch.d.ts +17 -0
  35. package/lib/types/host/compaction-patch.d.ts.map +1 -0
  36. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  37. package/lib/types/host/kimi-code/client.d.ts +9 -0
  38. package/lib/types/host/kimi-code/client.d.ts.map +1 -1
  39. package/lib/types/host/kimi-code/mapper.d.ts +2 -2
  40. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  41. package/lib/types/host/kimi-code/token-store.d.ts +4 -5
  42. package/lib/types/host/kimi-code/token-store.d.ts.map +1 -1
  43. package/lib/types/host/kimi-code/video-tool.d.ts.map +1 -1
  44. package/lib/types/host/oauth-service.d.ts +24 -0
  45. package/lib/types/host/oauth-service.d.ts.map +1 -1
  46. package/lib/types/host/preferences.d.ts +16 -2
  47. package/lib/types/host/preferences.d.ts.map +1 -1
  48. package/lib/types/host/preset-sync.d.ts +24 -1
  49. package/lib/types/host/preset-sync.d.ts.map +1 -1
  50. package/lib/types/host/responses-client.d.ts +1 -1
  51. package/lib/types/host/responses-client.d.ts.map +1 -1
  52. package/lib/types/host/responses-mapper.d.ts +1 -1
  53. package/lib/types/host/responses-mapper.d.ts.map +1 -1
  54. package/lib/types/host/search-provider-switcher.d.ts.map +1 -1
  55. package/lib/types/host/subagent-model-authorization.d.ts +5 -4
  56. package/lib/types/host/subagent-model-authorization.d.ts.map +1 -1
  57. package/lib/types/host/token-store-macos.d.ts +7 -0
  58. package/lib/types/host/token-store-macos.d.ts.map +1 -1
  59. package/lib/types/host/usage-service.d.ts +8 -0
  60. package/lib/types/host/usage-service.d.ts.map +1 -1
  61. package/lib/types/host/workbuddy/account-pool.d.ts +30 -0
  62. package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -1
  63. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
  64. package/lib/types/host/workbuddy/client.d.ts +17 -0
  65. package/lib/types/host/workbuddy/client.d.ts.map +1 -1
  66. package/lib/types/host/workbuddy/identity.d.ts +71 -0
  67. package/lib/types/host/workbuddy/identity.d.ts.map +1 -0
  68. package/lib/types/host/workbuddy/mapper.d.ts +2 -2
  69. package/lib/types/host/workbuddy/mapper.d.ts.map +1 -1
  70. package/lib/types/host/workbuddy/oauth.d.ts +9 -0
  71. package/lib/types/host/workbuddy/oauth.d.ts.map +1 -1
  72. package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
  73. package/lib/types/host/workbuddy/token-store.d.ts +30 -5
  74. package/lib/types/host/workbuddy/token-store.d.ts.map +1 -1
  75. package/lib/types/host/workbuddy/types.d.ts +9 -0
  76. package/lib/types/host/workbuddy/types.d.ts.map +1 -1
  77. package/lib/types/index.d.ts.map +1 -1
  78. package/lib/types/shared/contracts.d.ts +2 -0
  79. package/lib/types/shared/contracts.d.ts.map +1 -1
  80. package/lib/types/shared/model-catalog.d.ts +43 -7
  81. package/lib/types/shared/model-catalog.d.ts.map +1 -1
  82. package/lib/types/shared/preferences.d.ts.map +1 -1
  83. package/package.json +32 -30
package/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.8.0-alpha.0 - 2026-09-23
6
+
7
+ - **本次先发 alpha 预发布版**:0.8.0 的正式版尚未定稿,因此只发到 `alpha` 标签(`npm i @eddyskywalker/dsh-chatgpt-subscription@alpha`),`latest` 仍指向 0.7.0——不主动指定 `@alpha` 的安装与升级行为不变。以下改动就是这一版 alpha 的内容。
8
+
9
+ - **新增 GPT-6 Sol / Luna(`gpt-6-sol`、`gpt-6-luna`)**:这两个模型随 [2026-09-22 的 GPT-6 Sol / Luna 发布](https://community.openai.com/t/announcing-gpt-6-sol-and-gpt-6-luna/1399925) 进入 Codex 模型目录,与 `gpt-6-astra` 同属 GPT-6 系列。
10
+ - **能力按本机真实目录核对,不按族名猜**:三条 GPT-6 条目都支持文本 + 图片输入、默认思考档位 `medium`、订阅侧上下文上限 872K(`~/.codex/models_cache.json`,`client_version` 0.155.0,`fetched_at` 2026-09-23;`gpt-6-sol` 的 `supported_reasoning_levels` 多一个 `ultra`,与 Astra 一样属于客户端的子代理编排,仍不作为 Responses 思考参数暴露)。`gpt-6-luna` 没有 `ultra`。
11
+ - **把「Astra 专属」的硬编码改成「GPT-6 系列」**:目录条目的 `reasoningProfile` 由 `'gpt-6-astra'` 改为 `'gpt-6'`,`GPT_6_ASTRA_MAX_CONTEXT_WINDOW` → `GPT_6_MAX_CONTEXT_WINDOW`、`GPT_6_ASTRA_REASONING_EFFORTS` → `GPT_6_REASONING_EFFORTS`,`contextWindowLimitForModel` 与 `reasoningEffortsForModel` 改为按 profile 判定而不是按模型 id 比较。上一版为新模型加能力时要逐处补 `|| model === 'gpt-6-xxx'`,这次三个模型共用一条规则。
12
+ - **`none` / `minimal` 的收敛也随族生效**:该规则此前只对 `gpt-6-astra` 生效(`responses-mapper` 里的 `options.model === 'gpt-6-astra'` 判断),新增的 Sol / Luna 会漏掉;现在提取为 `codexWireReasoningEffort()` 放在目录旁,按 profile 判定,GPT-6 三个模型行为一致,GPT-5.6 / 5.5 等仍原样透传 `none`。
13
+ - **两个模型默认可见、上下文可配置**:加入 `DEFAULT_VISIBLE_CODEX_MODEL_IDS` 与 `CONFIGURABLE_CONTEXT_MODEL_IDS`,偏好 DTO / 默认值 / host schema / 路由校验同步,因此设置卡里多出两行上下文窗口输入框,新装即勾选;**已有配置的模型勾选与上下文值一律不动**(schema 只是为新键补默认值)。
14
+ - **GPT-6 默认有效上下文提到 384K**:目录条目与 `DEFAULT_PREFERENCES` 一并从 272K 改为 `GPT_6_DEFAULT_CONTEXT_WINDOW = 384_000`(上限仍是 872K,未触及 Codex 目录里 `effective_context_window_percent: 95` 的折算问题);仅 GPT-6 三条变动,GPT-5.6 系列保持 272K。**已有配置里存过的值不会被改写**——schema 只在新键缺失时补默认值。
15
+ - **输出上限改为按模型区分**:`src/host/model-catalog.ts` 原先对所有模型写死 `defaultMaxTokens: 32_768`,现改为 `codexModelMaxTokens()` 读取目录条目的 `maxTokens`;**仅 GPT-6 系列(6 Astra / 6 Sol / 6 Luna)提到 128,000**,更早的模型(5.6 系列、5.5、5.4、5.4 Mini、5.3 Codex Spark)维持 32,768,因此这次改动不会放宽老模型的单次输出。128K 取自官方对 GPT-6 三个模型的 `128,000 max output tokens` 标注。该字段的语义已在 harness `dsh-llm` 里核实(`lib/types/types.d.ts`:「Adapter-configured per-request output cap materialized when callers omit one」,`resolveCallWithInfo` 在 `config.maxTokens === void 0` 时补入);Responses 报文自身不发输出长度参数(`responses-mapper` / `responses-client` 内 `max_output_tokens` 命中数为 0,全仓库只有 `codex-search.ts` 给搜索请求写死 4096)。
16
+ - **验证**:`npm run typecheck` 与 `npm run build` 通过(typecheck 需按 lockfile 安装——本机 `node_modules` 里 schemastery 3.18.2 与 lockfile 的 3.18.3 不一致时,`src/host/preferences.ts`、`src/index.ts` 会报两处与本改动无关的 `Volatile` 默认值错误,`npm ci` 后即消失),`npx vitest run` **85 个文件通过 / 1 跳过,1105 条通过 / 7 跳过、0 失败**。新增 6 条断言:适配器对三个 GPT-6 模型逐一校验能力、384K 默认上下文、128K 输出上限与 872K 覆盖,并同时锁定 GPT-5.6 系列与 `gpt-5.3-codex-spark` 仍为 32,768;`gpt-6-sol` / `gpt-6-luna` 的思考档位表与「无降级模型」;映射器对三个 GPT-6 模型统一收敛 `none`/`minimal`,以及 `gpt-5.6-sol` / `gpt-5.5` 的 `none` 不被误伤。
17
+
18
+ - **支持 DSH 0.1.7-alpha.1**(本机 harness 仓库已到该版本;本机 npm 上 `@deepseek-ai/dsh` 的 `alpha` 也是它)。0.1.7 有**三处破坏性重写**,同一份代码仍要覆盖 0.1.2-alpha.5 以来的各代,因此全部按「双形态」适配,peer 范围相应加入 `^0.1.7-alpha.1`,dev 基线升到 `0.1.7-alpha.1`。
19
+ - **会话消息模型**:0.1.7 把工具结果从「`role:"user"` 消息里的 `tool-result` 内容块」改成**一等 `role:"tool"` 消息**(`toolCallId`/`isError` 直接挂在消息上),`ToolResultBlock` 从 `ContentBlockMap` 删除,`GenerateOptions.messages` 由 `Message[]` 放宽为 `RequestMessage[]`,`MessageSourceMap` 的兜底 `plugin` 种类也被移除。新增 `src/host/common/llm-compat.ts` 作为唯一边界:它给出 mapper 读的规范词汇(`Message`/`ContentBlock` 由 harness 自己的块类型加回本包的 `tool-result` 块推出;`OutboundContentBlock` 是本包回传的那部分),并把 `role:"tool"` 消息重新包成 mapper 认得的「带一个 `tool-result` 块的用户消息」,连 `source.kind === 'tool'` 的出处一并保留。**5 条线路只在各自的请求边界调一次** `normalizeGenerateOptions()`(`responses-client` 的 `stream()` 与四个 provider adapter 的 `offloadOldestRequest*` 之前),5 个 mapper 的逻辑一行未改——这正是旧版仍然逐字可用的原因。
20
+ - **设置 API**:0.1.7 删除了 `settings.register`/`SettingsProvider`/`SettingsScope`,改成从插件 `Config` 的 `.volatile()` 字段投影出表单、写 profile patch(`packages/settings/settings` 在 0.1.7 只剩 `SettingsForms`)。新增 `src/host/common/settings-compat.ts`(本地结构化类型 + `hasRegister` 守卫 + `settingsNamespace` 探测)与 `src/host/common/file-preferences.ts`(`<DSH_HOME>/storages/dsh-chatgpt-subscription-preferences.json`:同步快照、一次性水合、schemastery 校验、临时文件 + rename 原子写、`watch` 通知)。**有 `register` 的一代走原路(行为未变),没有的一代把偏好落到插件自有文件而不是内存**,因此 0.1.7 上设置不会随重启丢失。**并为老用户做一次性迁移**(`src/host/common/legacy-preferences.ts`):新文件缺失、或只有默认值时,读 `$DSH_HOME/settings.yaml` 以及 harness 迁移后留下的 `settings.yaml.imported` 里本插件的段,用同一份 schema 校验后写进新文件;已存在且带真实值的文件绝不被覆盖。旧文档只按文本解析(本包不引入 YAML 依赖),只认自己那一段的四种形状——标量、一层嵌套 map(`contextWindowOverrides`)、块序列(`visibleModelIds`)、行内数组——读不懂的字段直接忽略。已用本机真实 `settings.yaml` 实测:8 个字段(含嵌套 map、块序列、带副密码的引号代理 URL)全部读全。
21
+ - **agent preset**:0.1.7 不再读取 `~/.dsh/.agent-presets`(改为 bundle 里的 `@deepseek-ai/dsh-agent-preset` 声明行)。**不能把声明行静态写进本包的 bundle patch**:`assertEntriesLoaded` 会让「无 fiber 且未 disabled」的条目直接把 DSH 启动判为失败,而 `@deepseek-ai/dsh-agent-preset` 在 ≤0.1.6 上不存在——那会让多数用户开不了机。因此改为运行时注册:新增 `src/host/agent-preset.ts`,在 `@deepseek-ai/dsh-agent-preset` 可解析且 `agentPresets` 服务在场时按 `preset.yml` + `agent.cordis.yml` 注册 `dispatch`(19 行逐字转录,`!!js` 平台判断落成真布尔值;已用解析后的 YAML 做过 deepEqual,并按 `entryListProblem` 校验),注册失败只记日志、绝不外抛;旧代仍走原有的 harness-home 拷贝。
22
+ - **消息出处**:`MessageSourceMap` 没有兜底 `plugin` 种类了,插件改为声明自己的种类(`declare module '@deepseek-ai/dsh-llm'` 里的 `dsh-chatgpt-subscription`),图片工具与视频工具注入的 notice 消息同步改用该 kind。
23
+ - **另修的连带问题**:`@deepseek-ai/dsh-code-runtime` 在 0.1.7 改名为 `dsh-ptc-runtime`(测试随之改名与改用 `ctx.ptcRuntime`);客户端工具视图对 `tool-result` 块的判比在 0.1.7 类型里已不成立,改为本地联合类型(运行时两种形态都能认);`refreshSearchProviderSelection` 一侧补上 `await entry.fiber?.await()`——cordis 4.0.3 的 `Fiber.update()` 不再返回 promise,原来的 `await` 变成空操作,选完搜索提供方后 `ctx.web` 会有一小段空窗。
24
+ - **验证**:`0.1.7-alpha.1` 基线上 `npm run typecheck` 与 `npm run build` 通过,`npx vitest run` 86 个文件 1099 条通过(1 个文件 7 条为既有的平台跳过)。旧代回测在**独立干净目录**里按 `^0.1.5-rc.1` 装出完整依赖闭包(实得 0.1.5-rc.3):`tsc -b`——即用户实际安装的 host + client 运行时代码——**0 错误**,`npx vitest run` 1096 条通过、**0 条失败**;唯一无法加载的文件是 `test/subagent-model-authorization-ptc.test.ts`,它静态导入 0.1.7 才有的 `@deepseek-ai/dsh-ptc-runtime`,属测试夹具绑定最新一代,运行时代码不受影响。
25
+ - **合并社区 PR #15、#12、#14,并修掉评审发现的问题**:
26
+ - **#12(macOS 钥匙串十六进制载荷)**:与版本无关的独立修复,`security find-generic-password -w` 在载荷含本地化字符时输出十六进制字节,解码后仍走原有 JSON 路径;断言与 macOS 回环测试保留。
27
+ - **#14(settings 缺 `register` 时优雅回退)**:四个线路的 provider store 守卫保留(它们的回退本就落到各自的 `FileModelSettingsStore`);但**主偏好 store 的「内存回退」被替换为文件落盘**(见上),并让 provider store 的回退**从文件水合**——此前回退的 `status()` 恒返回默认值,0.1.7 上「保存过的模型开关每次启动都像被重置」。
28
+ - **#15(客户端 inject 补 `sessions`/`remote`/`remote.session`)**:**报告的根因不成立**。用真实 cordis 4.0.3 在「兄弟 fiber」布局下实测(两种调用方式各两次):`ModelDirectoryResolver` 的方法调用会被影子上下文指回**服务自己的** fiber,`this.ctx.remote.session` 因此从不由调用方的 inject 决定,调用方只声明 `modelDirectories` 也能通过;0.1.5-rc.2 与 0.1.7 的 `service.ts`/`reflect.ts` 在这点上逐字相同(一方插件 `ui-model-selection` 自己也是只声明 `['commandUi','modelDirectories']` 就叫它)。保留下来的这三项声明不产生副作用(都是客户端本就存在的服务),与 `ui-plan`/`ui-open-in-app` 等一方插件的写法一致,但**它并不是那个 `cannot get property remote.session without inject` 的修复**;按报告者的复现,真正起作用的是激活时序。
29
+
30
+ - **修 WorkBuddy 的两个账号身份缺陷**(用户报告:①「workbuddy 授权登录和自动扫盘获得的账户如果都是同一个,会出现 2 个账户」;②「添加账号出现的账号会显示账号 1,没正确获取信息」)。两个症状同一根因:**账号 id 曾经把「显示名」当成身份**。
31
+ - **根因(实测)**:浏览器授权的 token 响应只给 `auth` 块(accessToken / refreshToken / domain),**不含账号身份**;`workBuddyAccountId` 的取值链是 `uid → uin → nickname → domain`,于是同一次登录里 uid 缺失就退化成昵称,产出的 id 是 `intl:<邮箱>`。而 CodeBuddy 桌面端自己写的 `*.info` 文件在 `account.uid` 里带着 uuid,同一账号扫盘得到 `intl:<uuid>`。**两条路径为同一个账号算出两个 id**,号池按 id 去重,就落成两行、`/accounts` 两个条目、设置卡片两张卡——这正是「会出现 2 个账户」。同理,响应里连昵称都没有时(实测签名/类型字段在部分账号下为空)只剩昵称兜底,于是落成位置标签 `账号 1`。
32
+ - **identity 从凭据自己解析**(新增 `src/host/workbuddy/identity.ts`):access token 是 Keycloak JWT,两个区的 `sub` 都是账号稳定 uid(已用本机真实国区/国际区 token 解码确认),`nickname`/`preferred_username`/`name` 提供显示名,`uin` 提供腾讯 UIN。解析在**唯一入口**统一做:`parseCredentialFile`(扫盘与桌面文件重读)、`parseManagedCredentials`、`ManagedCredentialStore.list/add/delete`、号池 `addAccount` 与 `parseWorkBuddyPoolData`。**不校验签名**是有意的:claims 只用来区分账号,token 仍由网关逐次校验,读不出 claim 的 opaque token 原样保留(新增单测锁定)。
33
+ - **昵称不再是取值链的第一级**:改为 `uid → uin → nickname → domain`,且关键是**顺序 + 先定 uid**——`withResolvedIdentity` 在派生任何 id 之前先由 token 的 sub把关:真实登录与桌面文件因此都走 uid 分支、结果一致(原来昵称排在 uid 之前,正是两条路径算出两个 id 的原因)。昵称保留在 domain 之前而不是删掉,是为了让「token 完全读不出 claim」的两个同区账号不会一起塌到共享的 deployment key 上;旧记录不会失去地址——被误存为 uid 的显示名会被换成真 uid(旧值保留为 nickname),无法识别的行则维持原 id 不变(`hasStableIdentity` 守卫)。
34
+ - **登录完成前先定身份**:`beginWebLogin` 在写盘**之前**调 `fetchAccountIdentity`(新增端点 `/v2/plugin/account`,即官方客户端读账号的同一个口,实测两区均返回 uid / nickname / uin / enterpriseId),并用 token claims 兜底;账号接口读不到**不阻塞登录**(新增单测锁定)。这样卡片回填的 `accountId` 与凭据库、号池算出的 id 是同一条,不再出现「先按名字存、事后才发现要按 uuid 存」。
35
+ - **存量数据一次性收敛**:号池解析把 re-key 后指向同一账号的两行合并(插件托管行优先,`isPrimary`、`addedAt`、`lastUsedAt`、冷却与失效状态、以及只存在于被丢弃行的 `uin`/`sourceFile` 展示字段都并入胜者),并把 `activeAccountId` 指向新 id。设置里的 `selectedAccountId`/`hiddenAccountIds` 若写于修复前(旧取值链的 `region:<nickname>`),通过 `workBuddyAccountIdAliases`(枚举旧链可能产出的全部 key)继续匹配,因此**已固定的账号不会退回自动选号、已隐藏的账号也不会重新进入轮换**。
36
+ - **别名优先于 uuid**:默认别名为 `nickname → uin → uid → 账号 N`。uuid 放在 UIN 之后,因为 UIN 是用户能在自己账号页核对的数字;位置标签只剩「凭据完全没有任何身份信息」时才可能出现(即症状②最后一次兜底)。
37
+ - 新增 18 条回归测试:identity 模块 8 条(两区 claim 形状、opaque/畸形 token 不抛错、空字符串不算身份、token 纠正被误存为 uid 的显示名、无改动时返回原对象)、store 2 条(登录凭据与桌面文件归并为同一 id、按显示名存下的托管行能恢复真 uid)、号池 4 条(登录 + 扫盘不产生第二个账号、默认别名取可识别身份而非 `账号 1`、两行 re-key 后合并且保留 UIN、旧 key 的 pin/hide 仍生效)、登录流程 2 条 + 改写 1 条(用 token 而非显示名定身份、账号接口不可达仍能完成登录、原有用例补断言持久化的凭据 id 与扫盘一致)、路由 2 条(登录保存的 id 与扫盘一致、旧 key 隐藏的账号仍报 `hidden`)。**其中 11 条已在修复前的 HEAD(`77491c7`)上实测必失败**:`expected '账号 1' to be '330101607075'`(症状②)、两处 `expected [ 2 rows ] to have a length of 1`(症状①)、`expected 'cn:copilot.tencent.com' to be 'cn:d5721ab0-…'`,另有一条把「忽略旧 key 的 pin/hide」变异回去也立即失败(变异测试确认断言有效)。identity 模块的 8 条在基线无法运行(该文件为新增),故未计入这 11 条。修复后 1036 条全绿(82 个文件通过 / 1 跳过),`npm run typecheck` 与 `npm run build` 均通过。
38
+ - **修「模型选择器打开要等好几秒,且第二次打开一样慢」**:`kimi-code` 的 `loadProviderModels()` 把 `ensureAccessToken()` 放在 30 分钟目录缓存的判断**之前**,而取 token 要读凭据存储——Windows 上那是一次经由 `spawn("powershell.exe")` 的 DPAPI 解密。DSH 在构建模型选择器的目录时会对**每个 Provider 的每个模型**调一次 `resolveModel`,本线路的 `resolveModel` 每次都会调 `catalog()`,于是**一个模型一次进程启动**。实测(Windows / Node 24):裸启动 `powershell.exe` 约 190–200 ms,4 个模型的目录解析 808 ms,第二次构建仍是 835 ms——缓存从未生效。修复后同一测量为 3 ms、0 次启动。
39
+ - **`loadProviderModels()` 的缓存检查提前到取 token 之前**,token-free 的调用按 `region` 匹配(`region` 因此单独记进缓存条目,不再只存在于 `${region}:${token尾8位}` 这个合成 key 里)。不同区域不会互相命中;显式传了 `accessToken` 的调用方仍按 token 精确匹配,因为换账号可能看到不同清单。
40
+ - **`UsageService.status()` 同样把 60 秒快照的判断提前到 `oauth.credentials()` 之前**:设置卡片每 60 秒轮询 `/status`(外加 `visibilitychange`),此前每次轮询都要先读一次凭据,因此**每次轮询一次进程启动**,与快照是否新鲜无关。快照本就按账号分键,且账号切换会 `clear()`,所以提前返回不会报出别的账号的用量;取到凭据后发现账号变了的那条判断保留。
41
+ - **修正上述配额缓存提前返回引入的一次账号串号**:那条早退发生在「取到凭据后比对账号」这道守卫**之前**,于是 60 秒窗口内切换账号时,卡片会把**上一个账号**的用量当成当前账号的用量报出来(实测:切换后仍返回旧账号的 10%,真实值应是 99%)。根因是守护这份缓存所需的账号身份**只能从凭据里得到**,而要省掉的正是这次凭据读取——「零凭据读取」与「账号正确」在带号池时天然冲突。现在改为比较一个**零成本的内存身份修订号**:号池把它作为公开方法暴露(与本进程的凭据写入计数相加),任何可能改变「由哪个账号作答」的写入——登录、删除、设为主账号、轮换、刷新——都会推进它;缓存只在修订号与写入快照时一致时才命中,因此不命中就回落到原有的账号比对(那是唯一能确认真实账号身份的地方)。登出的 `usage.clear()` 保留;ChatGPT 的 `/accounts` 账号动作本就没有清缓存(这正是本缺陷的成因),现在的正确性不再依赖它。修订号取不到网络与磁盘,Windows 上 DPAPI 读取的优化因此完整保留(空闲轮询仍是 0 次进程启动)。
42
+ - 新增 2 条回归测试:号池端到端 1 条(切换主账号后卡片立即报新账号的 99%,按请求实际携带的 `chatgpt-account-id` 判定归属,因此断言的是「哪个账号的配额」而非请求次数)、配额服务 1 条(登出后 60 秒窗口内不再返回登出前的快照)。两条都在修复前必失败(已实测:`expected 10 to be 99` / `expected 1 to be greater than 1`)。
43
+ - 新增 9 条回归测试:目录 6 条(热缓存零凭据读取、多模型解析只读一次、`force` 仍重新拉取、跨区域不互相命中、带 token 的调用方仍能命中、无 store 返回空)、配额 3 条(热快照零凭据读取、过期后仍重新读取、未登录不返回缓存快照)。用例断言的是**凭据读取次数**而非墙钟时间,因此锁定的是调用顺序本身。
44
+
5
45
  - **修「0.1.6 上 dispatch 预设挂载失败」**:harness 0.1.6 把 workflow 引擎的包名从 `@deepseek-ai/dsh-workflow-worker-thread` 改成 `@deepseek-ai/dsh-workflow-ptc`,preset-sync 靠探测当前安装能解析哪个拼写来改写预设行;但探测根只看 profile 目录、cwd 与插件自身目录,而标准装法下 harness 是全局 npm 安装、插件在 profile 的 pnpm 树里,Node 从插件位置解析不到 harness 嵌套的 `node_modules`——两个拼写都"解析不到"时按设计不改写,旧名字原样同步进 `~/.dsh/.agent-presets`,预设挂载即报 `names a plugin that cannot be resolved`。0.1.5 上无需改写,故障完全隐形。`candidatePackageRoots` 新增 harness CLI 入口脚本(`process.argv[1]`,经 realpath 解 bin shim 与相对路径)所在目录作为候选根:它必然位于 harness 安装树内,向上走即达 harness 自带包。改写仍是双向的,0.1.5 行为不变(旧名可解析故保留)。新增 2 条用例:入口脚本旁的 harness 包可达、入口缺失或悬空不抛错。
6
46
  - **修复 ChatGPT 线路的网页搜索不可用**(实机 sighting:对话里执行「网页搜索」直接报 `Error: ChatGPT subscription credentials are required for Codex search.`,连本仓库自己的检索也一起失败):
7
47
  - **根因是「取号」与「取凭据」两件事被合并成了一条路径**。ChatGPT 号池为了在 429 之前就跳过已用尽的账号,会在按账号缓存到「Codex 窗口已用尽」时把该账号移出轮换(`account-pool-core.getEffectiveAccount` → `isEligible`)。而 OAuth 服务的 `credentials()` 过去**只有这一条路径**,于是 `codex-search` / `codex-fetch` / `codex-images` 和配额卡片全都拿不到凭据。实测确认:窗口打满时 `oauth.credentials()` 抛 `LlmError(RATE_LIMIT)`,而**同一个 token 直接打 `/alpha/search` 却能正常返回结果**——搜索并不计入 Codex 限流窗口,被挡住的只是调度,不是凭据。
package/README.md CHANGED
@@ -85,17 +85,21 @@
85
85
 
86
86
  **设置页**
87
87
  - 展示账号(脱敏 email、套餐、账号 ID 后四位)、连接状态、额度与订阅增强功能开关;
88
+ - **偏好落盘位置随 harness 生成**:有 `settings.register` 的一代(≤0.1.6)仍写进 harness 的设置文档;0.1.7 起该 API 被 `SettingsForms` 取代,偏好改由插件自己持久化到 `<dshHome>/storages/dsh-chatgpt-subscription-preferences.json`(0600、原子写;读取失败或校验不过就回落默认值;**首次运行会从旧设置文档里本插件的段一次性迁移**),五条线路的模型开关同样从各自既有的 `storages/*-models.json` 水合,因此重启后不会像被重置;
88
89
  - 子代理的模型与思考深度沿用 DSH 自身设置:**设置 → Subagent** 卡片授权 Agent 可以为子代理挑选的模型(来自 DSH 已接入的全部 Provider,包含本插件的 Codex / Antigravity),新 Agent 的默认路由由 DSH 的 `agent-default-model` 设置提供;
89
90
  - 最大嵌套深度不在本插件设置内,由 DSH 侧决定:0.1.5 及以前是 preset 中 `tool-subagent` 行的 `maxDepth`(默认 3),0.1.6 起改由 `subagent` 服务的设置项提供(默认 1);`provider-managed` 表示把预算交给进程外提供方;
90
- - 6 Astra 与 5.6 Sol / Terra / Luna 默认使用 272K 有效上下文;订阅侧 6 Astra 可配置最高 872K,5.6 系列最高 1M,用于 DSH 压缩与溢出判断;其他模型保持目录声明值;
91
+ - GPT-6 系列(6 Astra / 6 Sol / 6 Luna)默认使用 384K 有效上下文,可配置最高 872K;5.6 Sol / Terra / Luna 保持 272K,最高 1M,用于 DSH 压缩与溢出判断;其他模型保持目录声明值;
92
+ - 单次输出上限按模型区分:GPT-6 系列为 128K(官方对 6 Astra / 6 Sol / 6 Luna 均标 128K),更早的模型保持 32768;调用方未显式指定时生效,Responses 报文本身不发送输出长度参数。
91
93
  - 可访问的进度条、窄窗口/200% 缩放布局、深浅主题与 reduced-motion。
92
94
 
93
95
  ## 模型目录
94
96
 
95
97
  | 显示名 | 模型 slug |
96
98
  | --- | --- |
97
- | 5.6 Sol | `gpt-5.6-sol` |
98
99
  | 6 Astra | `gpt-6-astra` |
100
+ | 6 Sol | `gpt-6-sol` |
101
+ | 6 Luna | `gpt-6-luna` |
102
+ | 5.6 Sol | `gpt-5.6-sol` |
99
103
  | 5.6 Terra | `gpt-5.6-terra` |
100
104
  | 5.6 Luna | `gpt-5.6-luna` |
101
105
  | 5.5 | `gpt-5.5` |
@@ -105,16 +109,16 @@
105
109
 
106
110
  > 目录只用于展示;账号实际可用的模型由 ChatGPT 套餐、workspace 策略与上游兼容状态决定。
107
111
 
108
- 6 Astra 支持文本、图片输入和工具调用,默认思考档位为 `medium`,可选 `low`、`medium`、`high`、`xhigh`、`max`。从旧会话带入的 `none` / `minimal` 会按 [OpenAI 官方迁移说明](https://developers.openai.com/api/docs/guides/latest-model) 转为 `low`。订阅侧 872K 上下文上限依据 2026-09-05 的 Codex 模型目录;[Codex Ultra](https://learn.chatgpt.com/zh-Hans/docs/models) 涉及客户端的子代理编排,本插件不将它作为 Responses 思考参数暴露。
112
+ GPT-6 系列(6 Astra / 6 Sol / 6 Luna)支持文本、图片输入和工具调用,默认思考档位为 `medium`,可选 `low`、`medium`、`high`、`xhigh`、`max`。从旧会话带入的 `none` / `minimal` 会按 [OpenAI 官方迁移说明](https://developers.openai.com/api/docs/guides/latest-model) 转为 `low`。三个模型的默认 384K 与上限 872K 均取自 2026-09-23 的 Codex 模型目录(`gpt-6-sol` / `gpt-6-luna` 于 2026-09-22 发布,能力与 `gpt-6-astra` 一致;目录里的 `context_window` 是 272K,本插件把默认有效上下文提高到 384K,仍低于 872K 上限);[Codex Ultra](https://learn.chatgpt.com/zh-Hans/docs/models) 涉及客户端的子代理编排,本插件不将它作为 Responses 思考参数暴露。
109
113
 
110
- 新配置默认显示 6 Astra;已有配置保留原来的模型勾选,可在 **设置 → Codex 订阅 → 可用模型** 中勾选 **6 Astra**。
114
+ 新配置默认显示 GPT-6 系列与 GPT-5.6 系列;已有配置保留原来的模型勾选,可在 **设置 → Codex 订阅 → 可用模型** 中勾选 **6 Sol** / **6 Luna**。
111
115
 
112
116
  ## 环境要求
113
117
 
114
118
  - Windows 或 Linux;
115
119
  - Windows:系统需提供 Windows PowerShell,以使用 CurrentUser DPAPI;
116
120
  - Linux:Host 用户必须拥有可写的 `~/.dsh`(或 `$DSH_HOME`),凭据文件会强制使用 `0600`、目录使用 `0700`;
117
- - 已安装 DSH:peer 范围覆盖 0.1.2-alpha.5 及以后的 0.1.x(含 0.1.5-rc.2 与 0.1.6-alpha)。构建与测试以 **0.1.5-rc.2** 为基线(npm 上 `@deepseek-ai/dsh` 的 `latest`,也就是用户实际在跑的版本)。0.1.1-rc.2 不再声明支持——它既没有 preset 用到的 `present` 工具,`mode` 枚举那时也还写作 `code`;0.1.6 把 workflow 引擎改了包名,插件在 preset 同步时按当前安装自动适配(见下);
121
+ - 已安装 DSH:peer 范围覆盖 0.1.2-alpha.5 及以后的 0.1.x(含 0.1.5-rc.2、0.1.6-alpha 与 0.1.7-alpha.1)。构建与测试以 **0.1.7-alpha.1**(npm 上 `@deepseek-ai/dsh` 的 `alpha`)为基线,旧版行为由版本兼容层保留:0.1.7 重写了会话消息模型(工具结果由 `tool-result` 内容块改为 `role: "tool"` 消息)、删除了 `settings.register`(偏好改由插件自有存储落盘)、并让 agent preset 不再从 `~/.dsh/.agent-presets` 读取,插件在请求边界、设置服务与 preset 注册三处同时适配,因此同一份代码可装在 0.1.2-alpha.5 以来的各代上。0.1.1-rc.2 不再声明支持——它既没有 preset 用到的 `present` 工具,`mode` 枚举那时也还写作 `code`;0.1.6 把 workflow 引擎改了包名,插件在 preset 同步时按当前安装自动适配(见下);
118
122
  - Node.js 与 npm。
119
123
 
120
124
  ## 安装
@@ -132,6 +136,13 @@ dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription
132
136
  npx @deepseek-ai/dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription
133
137
  ```
134
138
 
139
+ **版本阶段**:`latest` 目前是 0.7.0;0.8.0 的正式版尚未定稿,先以 `0.8.0-alpha.0` 发到 `alpha` 标签,因此上面两条命令装到的仍是 0.7.0。要试用 alpha,需显式带上标签或版本号:
140
+
141
+ ```sh
142
+ dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription@alpha
143
+ npm install @eddyskywalker/dsh-chatgpt-subscription@0.8.0-alpha.0
144
+ ```
145
+
135
146
  ### 方式 2:在 DSH 界面里安装
136
147
 
137
148
  DSH 没有插件市场;Web 界面的 **Plugins** 页提供按包名安装的入口(底层与 `dsh plugin add` 相同):
@@ -164,7 +175,7 @@ npx @deepseek-ai/dsh plugin --profile web add "link:C:\absolute\path\to\dsh-chat
164
175
  3. 完成 ChatGPT 登录;
165
176
  4. 执行 **测试连接**。
166
177
 
167
- DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。6 Astra 与 GPT-5.6 系列的有效上下文窗口在“Codex 订阅 → 增强功能”中配置。子代理的模型与思考深度由 DSH 自身的设置决定(Subagent 卡片授权的模型清单,以及 `agent-default-model` 的默认路由;该卡片 0.1.5 及以前在「设置」页,0.1.6 起在 **Plugins** 页);最大嵌套深度由 DSH 侧决定(0.1.5 及以前取 preset 中 `tool-subagent` 的 `maxDepth`,默认 3;0.1.6 起取 `subagent` 服务的设置,默认 1)。
178
+ DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。GPT-6 系列与 GPT-5.6 系列的有效上下文窗口在“Codex 订阅 → 增强功能”中配置。子代理的模型与思考深度由 DSH 自身的设置决定(Subagent 卡片授权的模型清单,以及 `agent-default-model` 的默认路由;该卡片 0.1.5 及以前在「设置」页,0.1.6 起在 **Plugins** 页);最大嵌套深度由 DSH 侧决定(0.1.5 及以前取 preset 中 `tool-subagent` 的 `maxDepth`,默认 3;0.1.6 起取 `subagent` 服务的设置,默认 1)。
168
179
 
169
180
  **设置 → Codex 订阅 → 网络代理** 同时控制 GPT 与 Antigravity(Gemini)的 Host 请求,可选择系统代理(自动检测)、自定义代理或直连。Gemini 模型生成、网页登录后的令牌交换、令牌刷新、账号信息、项目发现、配额与模型目录查询均使用此设置;修改后对后续请求生效,无需重启 DSH。浏览器中的 Google 授权页面使用浏览器自己的网络设置。
170
181
 
@@ -201,7 +212,9 @@ DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。6 Astra 与 G
201
212
 
202
213
  ## 随包分发的 Agent Preset
203
214
 
204
- 插件自带一个 **调度模式** agent preset(id `dispatch`),随 npm 安装一起分发:启动时会把它从包内 `presets/dispatch/` 同步到 DSH 的 preset 发现根目录 `<dshHome>/.agent-presets/`,因此任何装了本插件的机器都能在新建会话时直接选到它,不需要手工拷贝文件。
215
+ 插件自带一个 **调度模式** agent preset(id `dispatch`),随 npm 安装一起分发:0.1.7 起 harness 不再从发现根目录读取 preset,插件改为**运行时注册**(`src/host/agent-preset.ts`:探测 `@deepseek-ai/dsh-agent-preset` 能否解析、`agentPresets` 服务是否在场,然后在 `presets/dispatch/preset.yml` 与 `agent.cordis.yml` 转录出的定义上调用 `register()`,注册失败只记 warn);0.1.6 及以前仍按老办法把包内 `presets/dispatch/` 同步到 `<dshHome>/.agent-presets/`。两条路都让装了本插件的机器在新建会话时直接选到它,不需要手工拷贝文件。
216
+
217
+ > 为什么不用静态声明行:0.1.7 的 preset 声明要写进 bundle patch,而 `assertEntriesLoaded` 会把「无 fiber 且未 disabled」的条目判为启动失败——`@deepseek-ai/dsh-agent-preset` 在 ≤0.1.6 上并不存在,静态声明会让那些机器直接开不了机。声明行也不能按运行环境条件化,所以选择运行时注册 + 能力探测。
205
218
 
206
219
  同步在每个 profile 启动时执行一次(幂等):
207
220
 
package/lib/client.js CHANGED
@@ -203,7 +203,11 @@ window.__ModuleLoader__.load({
203
203
  //#endregion
204
204
  //#region src/shared/model-catalog.ts
205
205
  const GPT_56_MAX_CONTEXT_WINDOW = 1e6;
206
- const GPT_6_ASTRA_MAX_CONTEXT_WINDOW = 872e3;
206
+ const GPT_6_MAX_CONTEXT_WINDOW = 872e3;
207
+ /** Effective context the GPT-6 family starts at, before any user override. */
208
+ const GPT_6_DEFAULT_CONTEXT_WINDOW = 384e3;
209
+ /** Output cap of the GPT-6 family; the vendor declares 128K for all three. */
210
+ const GPT_6_MAX_TOKENS = 128e3;
207
211
  const CODEX_MODEL_CATALOG = [
208
212
  {
209
213
  id: "gpt-5.6-sol",
@@ -218,11 +222,32 @@ window.__ModuleLoader__.load({
218
222
  {
219
223
  id: "gpt-6-astra",
220
224
  name: "6 Astra",
221
- contextWindow: 272e3,
225
+ contextWindow: GPT_6_DEFAULT_CONTEXT_WINDOW,
222
226
  inputModalities: ["text", "image"],
223
227
  defaultReasoningEffort: "medium",
224
- reasoningProfile: "gpt-6-astra",
225
- supportsReasoningSummary: true
228
+ reasoningProfile: "gpt-6",
229
+ supportsReasoningSummary: true,
230
+ maxTokens: GPT_6_MAX_TOKENS
231
+ },
232
+ {
233
+ id: "gpt-6-sol",
234
+ name: "6 Sol",
235
+ contextWindow: GPT_6_DEFAULT_CONTEXT_WINDOW,
236
+ inputModalities: ["text", "image"],
237
+ defaultReasoningEffort: "medium",
238
+ reasoningProfile: "gpt-6",
239
+ supportsReasoningSummary: true,
240
+ maxTokens: GPT_6_MAX_TOKENS
241
+ },
242
+ {
243
+ id: "gpt-6-luna",
244
+ name: "6 Luna",
245
+ contextWindow: GPT_6_DEFAULT_CONTEXT_WINDOW,
246
+ inputModalities: ["text", "image"],
247
+ defaultReasoningEffort: "medium",
248
+ reasoningProfile: "gpt-6",
249
+ supportsReasoningSummary: true,
250
+ maxTokens: GPT_6_MAX_TOKENS
226
251
  },
227
252
  {
228
253
  id: "gpt-5.6-terra",
@@ -283,20 +308,24 @@ window.__ModuleLoader__.load({
283
308
  }
284
309
  ];
285
310
  const DEFAULT_VISIBLE_CODEX_MODEL_IDS = [
286
- "gpt-5.6-sol",
287
311
  "gpt-6-astra",
312
+ "gpt-6-sol",
313
+ "gpt-6-luna",
314
+ "gpt-5.6-sol",
288
315
  "gpt-5.6-terra",
289
316
  "gpt-5.6-luna"
290
317
  ];
291
318
  const DEFAULT_CODEX_MODEL = CODEX_MODEL_CATALOG[0];
292
319
  const CONFIGURABLE_CONTEXT_MODEL_IDS = [
293
320
  "gpt-6-astra",
321
+ "gpt-6-sol",
322
+ "gpt-6-luna",
294
323
  "gpt-5.6-sol",
295
324
  "gpt-5.6-terra",
296
325
  "gpt-5.6-luna"
297
326
  ];
298
327
  function contextWindowLimitForModel(model) {
299
- return model === "gpt-6-astra" ? GPT_6_ASTRA_MAX_CONTEXT_WINDOW : GPT_56_MAX_CONTEXT_WINDOW;
328
+ return resolveCodexCatalogEntry(model).reasoningProfile === "gpt-6" ? GPT_6_MAX_CONTEXT_WINDOW : GPT_56_MAX_CONTEXT_WINDOW;
300
329
  }
301
330
  function resolveCodexCatalogEntry(model) {
302
331
  return CODEX_MODEL_CATALOG.find((entry) => entry.id === model) ?? DEFAULT_CODEX_MODEL;
@@ -5511,9 +5540,9 @@ window.__ModuleLoader__.load({
5511
5540
  searchProviderCodex: "ChatGPT(代理隧道)",
5512
5541
  providerDefault: "使用 Provider 默认值",
5513
5542
  contextWindows: "模型上下文窗口",
5514
- contextWindowsHint: "默认 272K;6 Astra 最高 872K,GPT-5.6 最高 1M。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。",
5543
+ contextWindowsHint: "GPT-6 系列默认 384K(最高 872K),GPT-5.6 系列默认 272K(最高 1M)。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。",
5515
5544
  contextWindow: "上下文窗口",
5516
- contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(6 Astra 为 872K,GPT-5.6 为 1M);可使用 K 或 M 后缀。",
5545
+ contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(GPT-6 系列为 872K,GPT-5.6 系列为 1M);可使用 K 或 M 后缀。",
5517
5546
  saveContextWindow: "保存上下文窗口",
5518
5547
  save: "保存",
5519
5548
  tokens: "tokens",
@@ -5640,9 +5669,9 @@ window.__ModuleLoader__.load({
5640
5669
  searchProviderCodex: "ChatGPT (Proxy tunnel)",
5641
5670
  providerDefault: "Use provider default",
5642
5671
  contextWindows: "Model context windows",
5643
- contextWindowsHint: "Defaults to 272K, with up to 872K for 6 Astra and 1M for GPT-5.6. DSH uses it for compaction and overflow detection; values such as 872K and 512K are accepted.",
5672
+ contextWindowsHint: "GPT-6 defaults to 384K (up to 872K); GPT-5.6 defaults to 272K (up to 1M). DSH uses it for compaction and overflow detection; values such as 872K and 512K are accepted.",
5644
5673
  contextWindow: "Context window",
5645
- contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for 6 Astra, 1M for GPT-5.6). K and M suffixes are accepted.",
5674
+ contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for the GPT-6 family, 1M for GPT-5.6). K and M suffixes are accepted.",
5646
5675
  saveContextWindow: "Save context window",
5647
5676
  save: "Save",
5648
5677
  tokens: "tokens",
@@ -6807,7 +6836,10 @@ window.__ModuleLoader__.load({
6807
6836
  "slots",
6808
6837
  "locale",
6809
6838
  "modelDirectories",
6810
- "conversation"
6839
+ "conversation",
6840
+ "sessions",
6841
+ "remote",
6842
+ "remote.session"
6811
6843
  ];
6812
6844
  function apply(ctx) {
6813
6845
  ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");