@inventec/dsh-copilot-auth 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![npm](https://img.shields.io/npm/v/%40inventec%2Fdsh-copilot-auth?label=npm)](https://www.npmjs.com/package/@inventec/dsh-copilot-auth)
5
5
  [![CI](https://img.shields.io/github/actions/workflow/status/iasiv5/dsh-copilot-auth/ci.yml?branch=main&label=CI)](https://github.com/iasiv5/dsh-copilot-auth/actions/workflows/ci.yml)
6
6
  [![License](https://img.shields.io/github/license/iasiv5/dsh-copilot-auth?label=License)](https://github.com/iasiv5/dsh-copilot-auth/blob/main/LICENSE)
7
- [![DSH Web](https://img.shields.io/badge/DSH%20Web-0.1.2--rc.1%20verified-2563eb)](#前置要求)
7
+ [![DSH Web](https://img.shields.io/badge/DSH%20Web-0.1.7--rc.2%20verified-2563eb)](#前置要求)
8
8
 
9
9
  为 DSH(DeepSeek Harness)内置的 GitHub Copilot LLM provider 补上 Web 端设备码(device flow)登录/注销入口,并预置一条开箱即用的 GitHub Copilot 提供方路由。
10
10
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  用公司分配的 GitHub 账号(带 Copilot 订阅)登录 DSH 的方式,和其他 Copilot 客户端一致:**网页 + 设备码**,全程不填 API Token。
14
14
 
15
- 本插件**复用 DSH 内置通道**(pi-ai 的 github-copilot provider),不实现任何 GitHub 协议代码——token 自动轮换、模型发现、协议适配全部由内置实现负责。插件本身只做三件事:挂载 DSH 内置但默认未启用的授权服务、提供「登录/注销」设置页、预置 `GitHub Copilot` 路由。
15
+ 本插件**复用 DSH 内置通道**(pi-ai 的 github-copilot provider),不实现任何 GitHub 协议代码——token 自动轮换、模型发现、协议适配全部由内置实现负责。插件本身只做三件事:提供「登录/注销」设置页、预置 `GitHub Copilot` 路由、模型目录兜底/刷新(授权服务 0.1.7+ 由 runtime 内置;≤0.1.5 时代由本插件补丁挂载,该版本线见 v1.1.x)。
16
16
 
17
17
  ## 特性
18
18
 
@@ -22,11 +22,13 @@
22
22
  - 🔄 **手动补充新模型目录条目**:GHC 设置页一键刷新——diff 预览 + 二次确认 + 数据级目录补丁(**pi-ai 版本不动**),新模型(如 gemini-3.8-flash)即可加入、失效模型镜像移除
23
23
  - 🌐 **中/英双语界面**:跟随 DSH 语言设置自动切换
24
24
  - 🔑 **凭据安全托管**:存入 DSH 内置凭据库(文件强制 0600 权限),Copilot 临时 token 到期自动刷新
25
- - 🧪 **测试与 CI**:105 条单元测试;GitHub Actions 构建测试 + tag 触发自动发布(provenance)
25
+ - 🧪 **测试与 CI**:106 条单元测试;GitHub Actions 构建测试 + tag 触发自动发布(provenance)
26
26
 
27
27
  ## 前置要求
28
28
 
29
- - DSH `0.1.2-rc.1`(实测版本)
29
+ - DSH `0.1.7-rc.2`(实测版本,v1.2.0 起的适配目标)
30
+ - 版本矩阵:`0.1.2-rc.1` ~ `0.1.5-rc.2` 请用 **v1.1.x**(v1.2.0 移除了旧版必需的 authorization 挂载补丁,在旧版上无法激活)
31
+ - v1.2.0 适配了 0.1.7 的 settings API 重塑(`settings.get` 移除),目录保护逻辑改走 `describe()`,对旧版 API 向后兼容
30
32
  - 有效的 GitHub Copilot 订阅(公司分配的 github.com 组织账号,SSO 登录)
31
33
  - `pnpm` 可用(`dsh plugin` 是 pnpm 转发器)
32
34
 
@@ -113,7 +115,7 @@ npm pack --dry-run
113
115
  - 自行在 `cordis.patch.yml` patch `llm-pi-ai` 整段 config 会覆盖预置路由
114
116
  - `settings.yaml` 的 `llm-pi-ai:` 节只能稀疏覆盖字段,无法删除预置路由本身(移除须卸载本插件)
115
117
  - 路由前缀 `/copilot-auth` 两侧硬编码,不可配置
116
- - DSH rc 版本耦合:实测 `0.1.2-rc.1`,peer 仅 `@deepseek-ai/cordis@^4.0.2`
118
+ - DSH rc 版本耦合:实测 `0.1.7-rc.2`(v1.2.0;`0.1.2-rc.1` 由 v1.1.x 实测),peer 仅 `@deepseek-ai/cordis@^4.0.2`
117
119
  - 模型目录只在「尚不存在」时由登录成功兜底填充一次,填充后归用户所有:账号新增的模型不会自动出现——用 GHC 设置页的「**刷新可用模型目录**」同步(见上节),或在 Models 页手动添加
118
120
  - 模型目录只写入 pi-ai 内置目录已描述的模型:目录快照外的新模型需先经「刷新可用模型目录」补入目录条目(数据级补丁,pi-ai 版本不变)才会出现在可选列表
119
121
  - DSH 升级后自愈仅在 pi-ai 基线版本不变(0.84.4)时重放;跨版本且条目未原生存在时上报 `self-heal-incompatible`,不修改安装树(重新执行一次手动刷新即可在新基线上激活)
package/cordis.patch.yml CHANGED
@@ -1,11 +1,11 @@
1
- # 1) 前置:0.1.2-rc.1 的全部 6 个内置 bundle 均未挂载 authorization 服务;
2
- # dsh-llm-pi-ai 的登录流注册是被动 ctx.inject(lib/index.js L2501),不挂此行则 flow 不存在。
1
+ # 0.1.2-rc.1 时代内置 bundle 不挂 authorization 服务,需在此 insert
2
+ # @deepseek-ai/dsh-authorization;0.1.7 起 runtime 已内置该服务,重复 provide
3
+ # 报 `service "authorization" has been registered`(入口不激活,journal 噪声)。
4
+ # v1.2.0 起仅适配 0.1.7+,不再 insert;旧版 DSH(≤0.1.5)请使用 1.1.x。
3
5
  - insert:
4
- - id: copilot-authorization
5
- name: '@deepseek-ai/dsh-authorization'
6
- # 2) 本插件 host 半区(web 树有 webServer 服务才会激活)
7
- # 路由前缀固定 /copilot-auth、不做配置项:client 侧 fetch 硬编码同一路径,
8
- # 配置一旦漂移 client 即 404(见附录 B)
6
+ # 本插件 host 半区(web 树有 webServer 服务才会激活)
7
+ # 路由前缀固定 /copilot-auth、不做配置项:client 侧 fetch 硬编码同一路径,
8
+ # 配置一旦漂移 client 即 404(见附录 B)
9
9
  - id: copilot-auth
10
10
  name: '@inventec/dsh-copilot-auth'
11
11
  # 3) 预置 GitHub Copilot 路由:entry config 作为 settings base 层,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inventec/dsh-copilot-auth",
3
- "version": "1.1.1",
4
- "description": "为内置 Copilot 提供方补设备码登录/注销设置页,预置开箱路由;凭据入内置凭据库,模型目录兜底不覆盖定制。",
3
+ "version": "1.2.1",
4
+ "description": "为内置 Copilot 提供方补设备码登录/注销设置页,预置开箱路由;凭据入内置凭据库,模型目录兜底不覆盖定制。适配 DSH 0.1.7+(settings API 重塑后;≤0.1.5 请用 1.1.x)。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "iasi",
package/src/host.mjs CHANGED
@@ -63,11 +63,15 @@ function readCatalogModelIds() {
63
63
  // 里该路由的 models 列表后重新登录即可。
64
64
 
65
65
  // 读取解析后的 github-copilot 路由配置(base 层 + 用户层的最终值)。
66
+ // 0.1.7 起 settings.get(ns) 被移除(settings API 重塑,见 know-how 013 §3),
67
+ // 改经 describe():value 层(base+user 合成)语义等价旧 get;旧版 DSH 的
68
+ // describe 行无 value 时回退 user 层(用户定制目录恰在 user 层)。
66
69
  // settings 未注入 / 未注册 / 读取失败一律按空处理——回退到可写入分支,
67
70
  // 保持既有 turnkey 行为不变。
68
71
  function readConfiguredRoute(ctx) {
69
72
  try {
70
- const section = ctx.settings?.get?.("llm-pi-ai");
73
+ const desc = ctx.settings?.describe?.()?.find?.((x) => x?.ns === "llm-pi-ai");
74
+ const section = desc?.value ?? desc?.user;
71
75
  return section?.providers?.["github-copilot"] ?? {};
72
76
  } catch {
73
77
  return {};
@@ -95,9 +99,13 @@ async function syncAvailableModels(ctx) {
95
99
  ids = available.filter((id) => served.has(id));
96
100
  }
97
101
  if (ids.length === 0) return;
102
+ // 真 CAS(与 boot 2a 同款,2026-09-28 审计补充):携带 expectedRevision 提交,
103
+ // 与用户在 Models 页的并发编辑互斥——冲突时 settings 抛 SETTINGS_CONFLICT,
104
+ // 由 sync() 的 catch 记入 syncError(失败不静默),不再有静默覆盖窗口。
105
+ const desc = ctx.settings?.describe?.()?.find?.((x) => x?.ns === "llm-pi-ai");
98
106
  await ctx.settings.mutate("llm-pi-ai", [
99
107
  { op: "set", path: ["providers", "github-copilot", "models"], value: ids.map((id) => ({ id })) },
100
- ]);
108
+ ], desc?.revision);
101
109
  }
102
110
 
103
111
  function sameOrigin(req) {
@@ -569,8 +577,14 @@ export function apply(ctx, opts = {}) {
569
577
  handler: async (req, res) => {
570
578
  if (!guard(req, res, "POST")) return;
571
579
  // 幂等契约:deleteRecord 对不存在记录是 no-op 且正常 resolve,
572
- // 真实删除与否由随后的 /status 反映。
573
- await ctx.credentials.deleteRecord(CREDENTIAL_KEY);
580
+ // 真实删除与否由随后的 /status 反映。异常兜底与其余路由对齐
581
+ // (2026-09-28 审计:无 try/catch 的 reject 会造成连接悬挂/未处理拒绝)。
582
+ try {
583
+ await ctx.credentials.deleteRecord(CREDENTIAL_KEY);
584
+ } catch (err) {
585
+ json(res, 500, { ok: false, error: String(err?.message ?? err) });
586
+ return;
587
+ }
574
588
  json(res, 200, { ok: true });
575
589
  },
576
590
  });