@dmh2002/dsh-connect-qoder 0.0.0-stage → 0.4.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.
- package/CHANGELOG.md +428 -0
- package/LICENSE +21 -0
- package/README.en.md +266 -0
- package/README.md +265 -2
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/cordis.patch.yml +12 -0
- package/docs/DESIGN.md +153 -0
- package/docs/PAT.md +181 -0
- package/docs/assets/dsh-connect-qoder-composer-credits.png +0 -0
- package/docs/assets/dsh-connect-qoder-model-management.png +0 -0
- package/docs/assets/dsh-connect-qoder-model-picker.png +0 -0
- package/docs/assets/dsh-connect-qoder-usage-card.png +0 -0
- package/icons/dsh-connect-qoder-128.png +0 -0
- package/icons/dsh-connect-qoder-64.png +0 -0
- package/lib/bin.d.ts +26 -0
- package/lib/bin.js +219 -0
- package/lib/client.js +4872 -0
- package/lib/host-heartbeat-BNuj6Lt_.js +1985 -0
- package/lib/index.d.ts +126 -0
- package/lib/index.js +3093 -0
- package/lib/status-paths-w2WDUPVS.js +218 -0
- package/lib/transfer-CUNaVvmi.js +172 -0
- package/package.json +135 -4
- package/screenshots.json +6 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# 第三方开源声明(Third-Party Notices)
|
|
2
|
+
|
|
3
|
+
> 本文件记录本项目在设计、实现与外观上参考或借鉴的开源项目,以及各自的许可证与合规要求。
|
|
4
|
+
>
|
|
5
|
+
> 通用平台与构建依赖(`@deepseek-ai/*`、`react`、`typescript`、`tsdown`、`vitest` 等)的许可证随各自 npm 包自动携带,不属于本文档范围。
|
|
6
|
+
>
|
|
7
|
+
> 若你对本文件的完整性有疑问或发现遗漏,请提交 issue 或 PR。
|
|
8
|
+
|
|
9
|
+
## 一、项目缘起
|
|
10
|
+
|
|
11
|
+
本项目是把 **Qoder(通义灵码国际 / 国内)模型接入 DeepSeek Harness(DSH)** 的独立实现:DSH 官方不提供 Qoder 的 OpenAI 兼容端点,官方 SDK 只是 agent 启动器,因此本项目直接实现 cosy 协议的最小客户端(自定义 Base64、MD5 签名、RSA/AES 会话、指纹派生、jobToken 交换、SSE 增量解析),并参照同作者的 workbuddy 插件工程组织 host↔client 结构。
|
|
12
|
+
|
|
13
|
+
## 二、参考项目清单
|
|
14
|
+
|
|
15
|
+
### 与 Qoder / cosy 接入直接相关
|
|
16
|
+
|
|
17
|
+
| 项目 | 仓库 | 参考内容 | 许可证 |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| `qoder2api`(Go) | <https://github.com/Zhengyuuuui/qoder2api> | cosy 协议 wire behavior 的参照实现:自定义 Base64 编码与重排、MD5 签名(`cosy&<SECRET>&<date>`)、RSA/AES 会话封装、指纹派生、jobToken 交换、SSE 信封与增量形状、错误分类。本项目**未复制其源码**,按其文档与运行行为独立实现为 TypeScript(`src/cosy.ts` / `src/upstream.ts`) | 仓库未附独立 LICENSE,README 声明其源自 `wangtufly/QCCG`(**GPL-3.0**,见下) |
|
|
20
|
+
| `QCCG`(qoder2api 的上游) | <https://github.com/wangtufly/QCCG> | qoder2api 声明的协议源头。本项目仅经 qoder2api 了解协议行为,未接触其源码 | **GPL-3.0** |
|
|
21
|
+
| `Qoder-Daily`(青龙脚本) | <https://github.com/L0NE-6/Qoder-Daily> | **每日签到**的协议参照:`sash/api/v1/me/campaigns` 拉活动 + `…/{campaignId}/claim` 领取的请求形状、`jt-` 令牌与 `cosy-clienttype` 头、幂等判定(`CLAIMED` / 409 / `replayed`),以及国际版所需设备风控三件套(`Cosy-MachineToken` / `MachineCode` / `MachineType`)由本机 UMID 组件产出的思路。本项目**未复制其源码**,按其文档与本机实测行为独立实现为 TypeScript(`src/upstream.ts` 的签到部分 / `src/device-risk.ts`),并补了它没有的两点:逐账号「先查后领」的幂等,以及取不到设备身份时**如实报错**而不是静默降级成「今天没有活动」 | **MIT** |
|
|
22
|
+
| Qoder 官方 SDK(agent 启动器) | 厂商随 IDE 分发的 TypeScript 类型定义(本地 `/tmp/sdk`) | 仅用于**类型核对**(usage 形状、cosy 头字段名),未复制其实现 | 厂商内部许可(不随本项目分发) |
|
|
23
|
+
|
|
24
|
+
> **GPL-3.0 合规说明**:本项目与 `QCCG`(GPL-3.0)之间**没有源码级衍生关系**——cosy 协议是公开的请求/响应行为(可通过抓包与文档观察),本项目按该行为**独立实现**全部加解密、签名与会话逻辑,不复制、不修改、不链接其任何源码。GPL 的传染性不适用于「仅参照协议行为、clean-room 独立实现」的作品;本项目自身以 MIT 发布,与之不存在再分发冲突。若你对这一判断有异议或发现任何源码级相似,请提交 issue。
|
|
25
|
+
|
|
26
|
+
### 与 DSH 插件结构 / 外观相关
|
|
27
|
+
|
|
28
|
+
| 项目 | 仓库 | 参考内容 | 许可证 |
|
|
29
|
+
| --- | --- | --- | --- |
|
|
30
|
+
| `dsh-connect-workbuddy` | <https://github.com/dingminhua/dsh-connect-workbuddy> | 插件工程结构的基准:host↔client 路由形态、设置卡片交互模型(区域 tab / 模型勾选 / 用量 / 探测)、loopback shim 模式、`web-status.ts` 路由、npm 发布工程(package.json / RELEASING / README 结构 / dsh-line 测试) | **MIT**(Copyright (c) 2026 LaoDing) |
|
|
31
|
+
| `dsh-connect-trae` | <https://github.com/dingminhua/dsh-connect-trae> | 经 `dsh-connect-workbuddy` 转引的 DSH 插件卡片外观与发布工程基准 | **MIT**(Copyright (c) 2026 LaoDing) |
|
|
32
|
+
| `dsh-codex-connect` | <https://github.com/franksong2702/dsh-codex-connect> | DSH 插件结构与 pi-ai provider 注册的参照(经 `dsh-connect-workbuddy` 转引) | **Apache-2.0** |
|
|
33
|
+
|
|
34
|
+
## 三、Apache-2.0 特别说明
|
|
35
|
+
|
|
36
|
+
`dsh-codex-connect` 采用 **Apache License 2.0**。本项目对它的参考是**间接的**:经由 `dsh-connect-workbuddy` 转引其 DSH 插件结构与 provider 注册思路。即便如此,本项目仍遵守 Apache-2.0 第 4 条的要求:
|
|
37
|
+
|
|
38
|
+
- **保留声明**:在该项目条目中标注其许可证为 Apache-2.0,并注明「经 `dsh-connect-workbuddy` 转引」的事实路径。
|
|
39
|
+
- **NOTICE 文件**:`dsh-codex-connect` 未随其仓库提供独立的 `NOTICE` 文本文件;若上游后续补充,本项目将同步将其内容纳入本文件。
|
|
40
|
+
- **改动声明**:本项目**未修改** `dsh-codex-connect` 的源码;适配器装配与插件注册为独立实现。
|
|
41
|
+
- **专利与商标**:本项目不主张 `dsh-codex-connect` 作者的任何专利许可或商标权利。
|
|
42
|
+
|
|
43
|
+
## 四、本项目的使用方式
|
|
44
|
+
|
|
45
|
+
- **借鉴设计思路 + 独立实现**:关键模块均为本项目独立编写(cosy 加解密、签名、会话、shim、适配器装配),并在各源文件头部注释中标注所参考的具体项目与模式。
|
|
46
|
+
- **不复制源码**:全部参考项目均只借鉴设计思路或协议行为,未复制、修改或再分发其源文件(含 GPL-3.0 的 `QCCG` 与无独立 LICENSE 的 `qoder2api`)。
|
|
47
|
+
- **版权声明保留**:所有参考项目的版权归各自作者所有。
|
|
48
|
+
- **后续引入依赖时**:引入任何新的 Qoder 相关外部依赖、或复用其他项目代码时,必须同步更新本文件,并遵守对应许可证的署名与声明要求。
|
|
49
|
+
|
|
50
|
+
## 五、图标来源与商标说明
|
|
51
|
+
|
|
52
|
+
本项目的插件图标(`icons/dsh-connect-qoder-128.png`、`icons/dsh-connect-qoder-64.png`,以及 `src/client/icon.ts` 中内联的 base64 副本)是 **LaoDing 插件家族通用的 LD 品牌标**(蓝紫渐变圆角磁贴 + 白色字标),与 `dsh-connect-trae` / `dsh-connect-workbuddy` 的图标**字节一致**——家族约定:图标标识「这是同一家族的插件」,产品区分由卡片标题、描述与配色承载。该美术作品由本作者原创,随本项目 MIT 许可分发。
|
|
53
|
+
|
|
54
|
+
- **0.2.0 曾用过 Qoder 桌面客户端的应用图标本体**(从 `/Applications/Qoder.app/…/application-icons/qoder-dark.png` 降采样),属**指示性使用**;0.3.0 起已改回家族 LD 标,**不再随包分发任何第三方美术作品**。
|
|
55
|
+
- **商标**:`Qoder`、`通义灵码` 名称与各自图标是厂商的商标,本项目仅在描述兼容关系的意义上使用其名称,不表示 Qoder 官方出品、背书或授权;相关权利归各自所有。
|
|
56
|
+
- **可替换性**:替换图标只需重新生成 `icons/` 下两个 PNG 并同步 `src/client/icon.ts` 的 data URI(见该文件头部注释),不影响任何代码逻辑。
|
|
57
|
+
|
|
58
|
+
## 六、随包分发
|
|
59
|
+
|
|
60
|
+
本文件已列入 `package.json` 的 `files` 白名单,随 npm 包一同分发,确保最终用户在安装包内即可看到完整的第三方声明。README(中英双语)中的「致谢」章节与本文件互为索引。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Register the Qoder provider without changing the profile's default model.
|
|
2
|
+
# PAT is configured in the plugin's settings card (or via environment
|
|
3
|
+
# variable); no OAuth flow is started by the plugin itself.
|
|
4
|
+
#
|
|
5
|
+
# `id` deliberately stays the unscoped `dsh-connect-qoder`: it is the entry id,
|
|
6
|
+
# the settings namespace (`settingsNamespaceOf`), and the `/plugins/<id>/…`
|
|
7
|
+
# route prefix. Renaming it would silently orphan every existing install's
|
|
8
|
+
# saved config. Only `name` — the package resolved through the profile's
|
|
9
|
+
# node_modules — carries the npm scope.
|
|
10
|
+
- insert:
|
|
11
|
+
- id: dsh-connect-qoder
|
|
12
|
+
name: '@dmh2002/dsh-connect-qoder'
|
package/docs/DESIGN.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# 设计方案:dsh-connect-qoder
|
|
2
|
+
|
|
3
|
+
> **目标**:把 Qoder(通义灵码国际 / 国内)接入 DeepSeek Harness(DSH)。
|
|
4
|
+
> **表现形式**:与插件家族一致(`dsm-*` 卡片外观),基准实现为
|
|
5
|
+
> [`dsh-connect-workbuddy`](https://github.com/dingminhua/dsh-connect-workbuddy)。
|
|
6
|
+
> **内核**:DSH 官方不提供 Qoder 的 OpenAI 兼容端点,官方 SDK 只是 agent 启动器,
|
|
7
|
+
> 因此本项目直接实现 cosy 网关协议的最小客户端。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 一、与 workbuddy 的分工
|
|
12
|
+
|
|
13
|
+
| 层 | 来源 | 取什么 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| 插件外壳 / 外观 | `dsh-connect-workbuddy` | 卡片结构、`dsm-*` CSS、`settingsScope` 配置回写、路由形态、发布工程、CI |
|
|
16
|
+
| 连接内核 | 自行实现(`src/cosy.ts` / `src/upstream.ts`) | Qoder 的 cosy 协议:自定义 Base64、MD5 签名、RSA/AES 会话、指纹派生、jobToken 交换、SSE 增量解析 |
|
|
17
|
+
| 已修缺陷的教训 | `dsh-connect-workbuddy` | 「平台标记 ≠ 模型原生能力」「声明可关闭思考不等于真的能关」等已踩过的坑(见第五节) |
|
|
18
|
+
|
|
19
|
+
关键差异(**合理**差异,非缺口):
|
|
20
|
+
|
|
21
|
+
- **凭据**:workbuddy 读桌面端本地加密凭据(`auth.ts` / `at-rest.ts` / `oauth.ts`);
|
|
22
|
+
本插件用用户自备的 PAT(`credentials.ts`)+ 本地 vault(`accounts.ts`)。
|
|
23
|
+
- **签到**:两边都有每日签到,但端点不同——WorkBuddy 有专用 checkin 端点,Qoder
|
|
24
|
+
的签到藏在 `sash/api/v1/me/campaigns`(活动/权益)+ `…/{campaignId}/claim` 里,
|
|
25
|
+
名字没有「签到」二字,照 checkin / signin / reward 猜路径一律 404(早期据此
|
|
26
|
+
误判为「没有签到」,已修正)。国际版的活动只下发给带设备风控头的请求,
|
|
27
|
+
三件套由 `device-risk.ts` 读本机 Qoder 客户端的 UMID 组件产出。
|
|
28
|
+
- **工具调用恢复**:workbuddy 需要 `dsml-recovery.ts` / `markup-diagnosis.ts`,
|
|
29
|
+
因为其上游**不**发原生 tool_calls;Qoder 上游**原生**发 `delta.tool_calls`
|
|
30
|
+
(见 `src/upstream.ts` 的解析与 `src/shim.ts` 的直写),故不需要这两个模块。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 二、模块结构
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
DSH PiAiAdapter(qoder / qoder-global 各一套)
|
|
38
|
+
-> 安全 loopback shim(每区域一个随机端口 + 进程内随机 secret)
|
|
39
|
+
-> QoderUpstreamClient(cosy 协议最小客户端)
|
|
40
|
+
-> https://gateway.qoder.com.cn/algo/api/v2/... (国内)
|
|
41
|
+
-> https://api1.qoder.sh/algo/api/v2/... (国际)
|
|
42
|
+
-> Qoder SSE(OpenAI 形状增量)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| 模块 | 职责 |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `status-paths.ts` | node-free 契约中心:路由常量、DTO、区域/动作 helper |
|
|
48
|
+
| `cosy.ts` | 协议层:自定义 Base64、`n/3` 重排、签名、RSA/AES 会话、指纹 |
|
|
49
|
+
| `upstream.ts` | `exchangeJobToken` / `fetchModels` / `chatStream` / `fetchUsage`;错误分类 |
|
|
50
|
+
| `credentials.ts` | PAT 校验、`qoderAccountId`(sha256 前 16 位)、掩码 |
|
|
51
|
+
| `accounts.ts` | 本地 vault(`$DSH_HOME/.qoder-accounts.<region>.json`,0600),三源去重合并 |
|
|
52
|
+
| `account-pool.ts` / `-store.ts` / `-run.ts` | 账号池排序(`rankPool`)、测量落盘、批量测试 |
|
|
53
|
+
| `off-thinking.ts` | 「可关闭思考」的校正表与种子(见第五节) |
|
|
54
|
+
| `native-modality.ts` | 模型原生多模态表与图片默认值(见第五节) |
|
|
55
|
+
| `shim.ts` | loopback 服务:入站校验、SSE 翻译、首字节前故障转移 |
|
|
56
|
+
| `adapter.ts` | pi-ai 装配:代际门控、思考档位映射、模型描述符 |
|
|
57
|
+
| `web-status.ts` | 浏览器路由:usage / account-credits / accounts / pool / transfer / probe / `__save` |
|
|
58
|
+
| `index.ts` | 装配中枢:双区域栈、配置 schema、目录管注册 |
|
|
59
|
+
| `bin.ts` | CLI:`doctor` / `status` / `logout` |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 三、凭据与账号池
|
|
64
|
+
|
|
65
|
+
三源按 **settings → env → vault** 优先级去重合并(同一个 PAT 只在最高优先级
|
|
66
|
+
来源里列出一次,id 由 PAT 本身派生,故重复项必然精确相同):
|
|
67
|
+
|
|
68
|
+
| 来源 | 位置 | 说明 |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| settings | `regions.<region>.pat` | 卡片填写,优先 |
|
|
71
|
+
| env | `QODERCN_PERSONAL_ACCESS_TOKEN` / `QODER_PERSONAL_ACCESS_TOKEN` | 无 UI 场景 |
|
|
72
|
+
| vault | `$DSH_HOME/.qoder-accounts.<region>.json` | 多账号池,0600 |
|
|
73
|
+
|
|
74
|
+
账号池「实测优先」:`test` 批量对每个成员发真实探测,结果落
|
|
75
|
+
`$DSH_HOME/.qoder-pool.<region>.json`;聊天流在**首字节之前**按 `rankPool`
|
|
76
|
+
(可用性 → 额度从高到低 → 到期最近 → id)自动换账号。首字节之后绝不换账号
|
|
77
|
+
(那会让用户看到两个人拼出来的回答)。
|
|
78
|
+
|
|
79
|
+
**每日签到已接通**(CN 与国际版),所以池的批量动作是 `checkin` / `test` 两个,
|
|
80
|
+
另有逐账号的 `remove`。签到**先查状态再领取**(幂等),且只在你点按钮时执行——
|
|
81
|
+
不提供自动签到。
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 四、推理与上下文
|
|
86
|
+
|
|
87
|
+
- **推理**:Qoder 的推理线上量是**布尔** `model_config.is_reasoning`,不是 effort
|
|
88
|
+
档位。所以 `qoderThinkingLevelMap` 只能表达 `off`(且仅
|
|
89
|
+
`canDisableThinking` 的模型提供),所有 effort 档位映射 `null`。
|
|
90
|
+
- **上下文档位**:从上游 `context_config` 解析模型**声明的**档位
|
|
91
|
+
(`contextTiers`),用户按档选择;预算只在该档位确实被声明时生效,否则回落
|
|
92
|
+
原生值(`applyContextBudgets`)——不发明一个上游不认的值。
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 五、从 workbuddy 继承的「已修缺陷」教训(重点)
|
|
97
|
+
|
|
98
|
+
这三条是同一个形状的问题:**上游的声明字段不可全信**。解法也相同:按**精确
|
|
99
|
+
model id** 键控的人工核对表 + 只在有依据时才给默认值,其余留 `unknown`(宁可
|
|
100
|
+
少给,也不要每次都失败/撒谎)。
|
|
101
|
+
|
|
102
|
+
### 5.1 平台标记 ≠ 模型原生能力(`native-modality.ts`)
|
|
103
|
+
|
|
104
|
+
上游目录的 `supportsImages`(Qoder 的 `is_vl`)是**平台**的图片输入声明,不是
|
|
105
|
+
**模型**的原生能力:它在内置目录里几乎对每个模型都是 `true`,连纯文本模型
|
|
106
|
+
(DeepSeek-V4-Pro、GLM-5.2、Kimi-K2.7-Code 等)也是 `true`。直接采信会在纯文本
|
|
107
|
+
模型上默认开出图片输入,用户一发图就 400。
|
|
108
|
+
|
|
109
|
+
解法:`NATIVE_MODALITY_BY_MODEL_ID` 表 + `imageDefaultFor`(只有文档确认
|
|
110
|
+
`multimodal` 才预勾选;`supportsImages:false` 仍可否决)。**与 workbuddy 的差异**:
|
|
111
|
+
对方面向已核对过的数据源,本项目**没有**同等来源,故不虚构条目,只登记少数可从
|
|
112
|
+
厂商命名确认的项,其余保持 `unknown`(= 不预勾选)——比信任平台标记严格更安全。
|
|
113
|
+
|
|
114
|
+
### 5.2 声明「可关闭思考」≠ 真的能关(`off-thinking.ts`)
|
|
115
|
+
|
|
116
|
+
workbuddy 实测:声明可关闭的模型里有一部分对 `reasoning_effort:"off"` 回 400,
|
|
117
|
+
且错误体不点名参数。由于该档位写进运行时描述符,失败会在**此后每一次请求**上
|
|
118
|
+
重演,用户读到的是「这个模型坏了」。
|
|
119
|
+
|
|
120
|
+
解法:`REFUSES_OFF_MODEL_IDS` + `offDefaultFor` + `defaultOffModelIds`(首读种子)
|
|
121
|
+
+ `withEffectiveOff`(把用户选择盖印到运行时目录)。**差异**:本项目暂无实测拒绝
|
|
122
|
+
样本,故拒绝集**留空而非虚构**——默认行为等同 0.1.0(不倒退),一旦实测到只需
|
|
123
|
+
加一行即可开始隐藏。代价不对称是这里的取舍依据:提供一个必然失败的档位,代价是
|
|
124
|
+
用户该模型的每一次请求;藏起一个本可用的档位,代价只是一个选项。
|
|
125
|
+
|
|
126
|
+
### 5.3 图片勾选必须独立持久(`imageModelKeys`)
|
|
127
|
+
|
|
128
|
+
workbuddy 用独立的 `imageModelIds`;本项目早期把图片勾选**耦合进** `lastCatalog`
|
|
129
|
+
快照,目录一被重写就可能连带改变某个模型的图像答案。现改为独立集合
|
|
130
|
+
(`regions.<region>.imageModelKeys`),运行时只从它派生图像能力。
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 六、安全
|
|
135
|
+
|
|
136
|
+
- **PAT 不出进程**:pi-ai 只与本地 shim 对话;shim 用 cosy 会话做上游请求。
|
|
137
|
+
- **shim 入站校验**:先查 Host / Origin(仅接受 `127.0.0.1`)/ Content-Type,
|
|
138
|
+
再做 `timingSafeEqual` bearer 比对;body 有大小上限。
|
|
139
|
+
- **脱敏**:任何上游文本在落盘/回传前经 `redactUpstreamText`
|
|
140
|
+
(`key=secret` 保留键名抹值;裸 `pt-` token 整段替换)。
|
|
141
|
+
- **vault 权限**:`0600`(目录 `0700`),写入走原子替换 + 文件锁。
|
|
142
|
+
- **不读桌面端登录文件**:与 workbuddy 不同,本插件不接触、不修改 Qoder 桌面端
|
|
143
|
+
的任何本地凭据。
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 七、源头与致谢
|
|
148
|
+
|
|
149
|
+
- 外观与工程骨架:[`dsh-connect-workbuddy`](https://github.com/dingminhua/dsh-connect-workbuddy)(MIT)—— 各源文件头部均带标注。
|
|
150
|
+
- cosy 协议行为参照:[`qoder2api`](https://github.com/Zhengyuuuui/qoder2api) / `QCCG`(其声明为 GPL-3.0)。
|
|
151
|
+
本项目**未复制其源码**,按其文档与运行行为独立实现为 TypeScript。
|
|
152
|
+
合规细节见 [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md)。
|
|
153
|
+
- 商标:Qoder 名称是厂商商标,此处仅用于标识本插件所连接的服务;插件图标沿用 LaoDing 插件家族通用的 LD 品牌标(与 dsh-connect-trae / dsh-connect-workbuddy 字节一致),不使用厂商商标图形。
|
package/docs/PAT.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# 获取并配置 PAT(Personal Access Token)
|
|
2
|
+
|
|
3
|
+
本插件用 **PAT** 接入 Qoder。这份文档只讲三件事:PAT 是什么、从哪拿、怎么填进插件。
|
|
4
|
+
|
|
5
|
+
## 一、PAT 是什么
|
|
6
|
+
|
|
7
|
+
PAT 是 Qoder 官方发给开发者的**个人访问令牌**,形如 `pt-` 开头的一串字符。你可以把它理解成「给外部程序用的一把钥匙」:谁持有它,谁就能以你的身份调用 Qoder 的接口。
|
|
8
|
+
|
|
9
|
+
它的两个特点决定了本插件的设计:
|
|
10
|
+
|
|
11
|
+
- **你自己签发、自己吊销**:不需要把账号密码交给任何第三方,随时能在设置页删掉。
|
|
12
|
+
- **等价于你的账号权限**:泄露它等于泄露账号,因此不要提交进代码仓库、也不要贴到聊天窗口或 issue 里。
|
|
13
|
+
|
|
14
|
+
插件拿到 PAT 之后做的事(这也是它**为什么只需要 PAT**的原因):
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
PAT ──(一次性)──> Qoder 网关 /jobToken 交换 ──> jobToken
|
|
18
|
+
│
|
|
19
|
+
↓
|
|
20
|
+
之后每次请求带签名会话头
|
|
21
|
+
(PAT 此后不再出现)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
PAT 只在**进程内**参与这次交换:DSH 的模型客户端(pi-ai)连的是本机的回环端口,真正的 PAT 一直在插件进程里,不进网络请求、不写进会话记录。
|
|
25
|
+
|
|
26
|
+
## 二、从哪里拿 PAT
|
|
27
|
+
|
|
28
|
+
两个区域各发一份,**互不通用**:
|
|
29
|
+
|
|
30
|
+
| 区域 | 服务站点 | 发证入口 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| 国内版(通义灵码) | `qoder.com.cn` | 登录 [Qoder CN 控制台](https://www.alibabacloud.com/help/zh/lingma/cloud-agents-cn/api-authentication) → **设置 → API 令牌** → 创建令牌 |
|
|
33
|
+
| 国际版 | `qoder.sh` | 登录 Qoder 控制台 → **Settings → Personal Access Tokens** → 创建(见 [Qoder 官方认证文档](https://docs.qoder.com/cloud-agents/api/conventions/authentication)) |
|
|
34
|
+
|
|
35
|
+
创建时:
|
|
36
|
+
|
|
37
|
+
1. 给令牌起一个**名字**(只是给你自己看的备注,比如「DSH 笔记本」)。
|
|
38
|
+
2. 如果页面要求选**权限范围 / 有效期**,按需选择——本插件只用模型推理能力,选默认即可;有有效期的话注意到期后要重新签发。
|
|
39
|
+
3. 点创建。**令牌通常只完整显示一次**,当场复制保存(形如 `pt-xxxxxxxx`)。
|
|
40
|
+
|
|
41
|
+
> 注意:这里说的是 Qoder **控制台网页版**里的入口,不是桌面客户端的设置页。
|
|
42
|
+
|
|
43
|
+
## 三、怎么填进插件
|
|
44
|
+
|
|
45
|
+
插件侧有两条路,二选一(同时配也没问题,会自动去重合并)。
|
|
46
|
+
|
|
47
|
+
### 方式 A:在设置卡片里粘贴(推荐,可多账号)
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
DSH → 插件 → dsh-connect-qoder → 设置卡片
|
|
51
|
+
→ 选对应的 tab(国内版 / 国际版)
|
|
52
|
+
→ 点「添加 PAT」
|
|
53
|
+
→ 在输入框贴入 pt-…(可顺便填一个显示名,会自动带出真实账号名)
|
|
54
|
+
→ 提交
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
提交时插件会**立刻拿它去 Qoder 网关做一次真实验证**:能换到 jobToken 才算通过,失败会直接拒绝并报错,不会把一个无效令牌存进去。所以「提交后没反应」以外的情况,都说明令牌本身有问题。
|
|
58
|
+
|
|
59
|
+
卡片里可以放**多个**账号(每区域一个保险库),换号、删号都在卡片内完成。
|
|
60
|
+
|
|
61
|
+
### 方式 B:环境变量
|
|
62
|
+
|
|
63
|
+
适合不想让令牌进 DSH 设置文件、或者希望由密钥管理器注入的场景:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 国际版
|
|
67
|
+
export QODER_PERSONAL_ACCESS_TOKEN=pt-xxxxxxxx
|
|
68
|
+
|
|
69
|
+
# 国内版
|
|
70
|
+
export QODERCN_PERSONAL_ACCESS_TOKEN=pt-xxxxxxxx
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
放进 shell 配置(`~/.zshrc` 等)或系统的密钥管理工具(1Password / Bitwarden 等的 shell 插件),DSH 启动时会自动读取。
|
|
74
|
+
|
|
75
|
+
### 优先级
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
设置卡片的 PAT > 环境变量 PAT > 保险库(vault)账号
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
三者按账号去重合并,不是互相覆盖。谁在生效可以用命令行看:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
dsh-connect-qoder status # 各区域当前凭据来源与上游可达性
|
|
85
|
+
dsh-connect-qoder doctor # PAT 是否就位、指纹派生、账号数(不联网)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 四、常见问题
|
|
89
|
+
|
|
90
|
+
**提交后报「验证失败」**
|
|
91
|
+
令牌与区域不匹配(国内版的令牌不能用在国际版 tab),或复制时带上了空格/换行,或已过期。
|
|
92
|
+
|
|
93
|
+
**「凭据被拒」但令牌明明是新生成的(实测记录)**
|
|
94
|
+
2026-10 实测到一个值得记下来的现象:同一个 CN 令牌,
|
|
95
|
+
|
|
96
|
+
| 请求 | 结果 |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `api.qoder.com.cn/api/v1/cloud/agents` | **200** —— 令牌有效、账号正常 |
|
|
99
|
+
| `openapi.qoder.com.cn/sash/api/v2/me/usage` | 401 `TOKEN_EXPIRE / token is not active` |
|
|
100
|
+
| `openapi.qoder.sh/sash/api/v2/me/usage` | 401 `TOKEN_EXPIRE` |
|
|
101
|
+
| `gateway.qoder.com.cn/algo/api/v2/model/list` | 403 `Signature invalid` |
|
|
102
|
+
|
|
103
|
+
两个结论:
|
|
104
|
+
|
|
105
|
+
1. **一张令牌有效与否,不能只看单一端点。** `sash` 系列接口回 `TOKEN_EXPIRE`
|
|
106
|
+
时,令牌本身可能完全正常——它只是不接受 PAT 直连(那条路径预期的是
|
|
107
|
+
浏览器会话 cookie:`qoder.com.cn/sash/...` 对缺 cookie 的请求回
|
|
108
|
+
`UNAUTHORIZED / missing cookie header`,与令牌无关)。
|
|
109
|
+
2. **`gateway.*/algo/*` 必须走 COSY 签名**,裸 `Bearer` 一律 `Signature invalid`。
|
|
110
|
+
本插件正是走「PAT → jobToken → 签名会话」这条路,所以**聊天与模型列表不受
|
|
111
|
+
上面那条 401 影响**;受影响的只有用量/积分查询。
|
|
112
|
+
|
|
113
|
+
因此:卡片上积分显示「—」而对话能正常用,属于「积分端点读不到」,不等于
|
|
114
|
+
「令牌坏了」。判断令牌真实状态应看对话能否发送,或按上表用 Cloud Agents 端点核对。
|
|
115
|
+
(本插件现在的积分查询已改用 jobToken 的 `jt-` 令牌,实测 200;PAT 直连只作兜底。)
|
|
116
|
+
|
|
117
|
+
**模型列表是空的,但令牌看着没问题**
|
|
118
|
+
未配置 PAT 的区域**不会列出任何模型**——一个请求都发不出去,列出来只会点到就失败。确认「从 Qoder 刷新」执行过。
|
|
119
|
+
|
|
120
|
+
**不想用 PAT 了**
|
|
121
|
+
把令牌在 Qoder 控制台里删掉即可;本插件侧用 `dsh-connect-qoder logout [--region cn|global]` 清除本地 vault 账号。
|
|
122
|
+
|
|
123
|
+
**能不能像 WorkBuddy 那样直接读本机登录?**
|
|
124
|
+
不能。WorkBuddy 桌面端把登录态存在固定路径的明文/可解密文件里,插件可以直接扫描复用;Qoder 桌面端把凭据加密后存进系统钥匙串相关的封装文件,且 CLI 侧的 `.auth/user` 只有登录过 Qoder CLI 才会生成(大多数用户不会)。所以 Qoder 这边只有官方 PAT 这一条稳妥路径——所有第三方 Qoder 接入工具都是这么做的。
|
|
125
|
+
|
|
126
|
+
## 五、Qoder 每日签到(实测协议,2026-10)
|
|
127
|
+
|
|
128
|
+
**参考实现**:https://github.com/L0NE-6/Qoder-Daily (青龙脚本,CN + Global)
|
|
129
|
+
**官方规则**:https://help.aliyun.com/zh/lingma/daily-check-in-100-credits-reward-program-terms
|
|
130
|
+
|
|
131
|
+
### 协议(CN 实测通过)
|
|
132
|
+
|
|
133
|
+
拉活动列表(**v1**,且叫 campaigns,不是 checkin):
|
|
134
|
+
|
|
135
|
+
GET {openapi}/sash/api/v1/me/campaigns?forceRefresh=true
|
|
136
|
+
headers:
|
|
137
|
+
authorization: Bearer {jobToken.securityOauthToken} ← jt- 令牌,与用量同一套
|
|
138
|
+
cosy-clienttype: 10
|
|
139
|
+
accept: application/json
|
|
140
|
+
accept-language: zh-CN
|
|
141
|
+
user-agent: Qoder
|
|
142
|
+
|
|
143
|
+
响应:
|
|
144
|
+
|
|
145
|
+
{"campaigns":[
|
|
146
|
+
{"campaignId":"01a12102-…","actionType":"CLAIM_BENEFIT","claimStatus":"CLAIMED",
|
|
147
|
+
"benefit":{"kind":"CREDITS","amount":100,
|
|
148
|
+
"modelScope":{"modelSeries":{"key":"ALL_MODELS"}},
|
|
149
|
+
"validity":{"mode":"RELATIVE_DAYS","days":30}}},
|
|
150
|
+
{"campaignId":"01a05bbf-…","actionType":"VIEW_DETAILS","claimStatus":"CLAIMED"}
|
|
151
|
+
]}
|
|
152
|
+
|
|
153
|
+
领取:
|
|
154
|
+
|
|
155
|
+
POST {openapi}/sash/api/v1/me/campaigns/{campaignId}/claim
|
|
156
|
+
(同 headers + content-type: application/json + origin)
|
|
157
|
+
|
|
158
|
+
已领取的判定:HTTP 409,或 body.result === "ALREADY_CLAIMED",或 body.replayed === true。
|
|
159
|
+
|
|
160
|
+
### 关键事实
|
|
161
|
+
|
|
162
|
+
- 活动名里**没有**「签到」二字,所以照着 checkin / signin / reward 猜路径一律 404
|
|
163
|
+
(我实测猜了 13 个全 404)。真正的词是 **campaigns**(活动/权益)。
|
|
164
|
+
- 状态机:`claimStatus` ∈ {CLAIMABLE, CLAIMED};只有 `actionType === "CLAIM_BENEFIT"`
|
|
165
|
+
且 `CLAIMABLE` 的才可领。
|
|
166
|
+
- 官方刷新时间:**每天 10:00 (UTC+8)** 开窗(阿里云文档写 0 点,桌面端截图显示 10:00
|
|
167
|
+
——以桌面端为准)。
|
|
168
|
+
- **国际版**还需要设备风控头 `Cosy-MachineToken` / `Cosy-MachineCode` /
|
|
169
|
+
`Cosy-MachineType`;**CN 不需要**(实测多发这些头在 CN 侧是噪音)。
|
|
170
|
+
三件套由 Qoder 客户端自带的 UMID 组件在本机生成,插件按区域读取:
|
|
171
|
+
|
|
172
|
+
| 区域 | 优先组件路径 |
|
|
173
|
+
|---|---|
|
|
174
|
+
| 国内版 | `/Applications/Qoder CN.app/Contents/Resources/umid/runtime-info` |
|
|
175
|
+
| 国际版 | `/Applications/Qoder.app/Contents/Resources/umid/runtime-info` |
|
|
176
|
+
|
|
177
|
+
两侧都装了时各自优先自己那个 —— 设备身份与区域绑定,用错一侧会被风控拒绝。
|
|
178
|
+
组件不存在时签到**如实报错**(「未找到 Qoder 设备风控组件」),而不是把
|
|
179
|
+
「取不到设备身份」伪装成「今天没有活动」。也可用 `QODER_UMID_PATH` 显式指定。
|
|
180
|
+
读取结果按 50 分钟在进程内缓存(参考实现同量级),避免每次签到都 fork 进程。
|
|
181
|
+
- 企业版账号不支持该活动(仅个人用户)。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/bin.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/bin.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Standalone status/diagnostics CLI for the dsh-connect-qoder bundle.
|
|
4
|
+
*
|
|
5
|
+
* 参考:dsh-connect-workbuddy(MIT,Copyright (c) 2026 LaoDing)——三个子命令
|
|
6
|
+
* 的骨架(`doctor` / `status` / `logout`)、`--json` 输出、`safeMessage` 脱敏与
|
|
7
|
+
* 「凭据来源 + 上游连通性」诊断的结构由该项目设计。
|
|
8
|
+
* 改动(按 Qoder 上游的现实):
|
|
9
|
+
* - 凭据只读环境变量 + 本地 vault(CLI 运行于宿主之外,无法访问设置服务);
|
|
10
|
+
* - `doctor` 增加 cosy 指纹派生自检、pi-ai 代际、宿主心跳存活、vault 账号计数;
|
|
11
|
+
* - `status` 汇报每区域凭据来源 + 上游可达性 + 当前剩余积分(总额);
|
|
12
|
+
* - `logout` 清除本区域的 vault 凭据与账号池测量副本(可 `--region` 指定,
|
|
13
|
+
* 否则两区域都清)。
|
|
14
|
+
*
|
|
15
|
+
* @module dsh-connect-qoder/bin
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* 从 argv 里取出**命令词**:剥掉 flag 与区域实参,剩下的第一个就是。
|
|
19
|
+
*
|
|
20
|
+
* 必须是「保留**不是** flag、**不是**区域名的实参」。写反成
|
|
21
|
+
* `REGION_KEYS.includes(arg)`(只留 cn/global)会让命令词自己被过滤掉,
|
|
22
|
+
* 于是三条子命令全部只会打印 usage。抽成纯函数就是为了能对它断言。
|
|
23
|
+
*/
|
|
24
|
+
declare function commandArgOf(argv: readonly string[]): string | undefined;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { commandArgOf };
|