devinfra-bridge 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +130 -18
- package/dist/agents/types.d.ts +5 -2
- package/dist/auth/bytedcli-provider.d.ts +7 -0
- package/dist/auth/credential-provider.d.ts +3 -0
- package/dist/daemon/auto-sync.d.ts +20 -0
- package/dist/daemon/daemon.d.ts +7 -3
- package/dist/daemon/single-instance.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +520 -179
- package/dist/main.js +520 -179
- package/dist/proxy/errors.d.ts +2 -1
- package/dist/proxy/forward-model-request.d.ts +4 -0
- package/dist/proxy/headers.d.ts +3 -2
- package/dist/proxy/jwt-expired.d.ts +6 -0
- package/dist/util/logger.d.ts +7 -2
- package/docs/acceptance.md +14 -0
- package/docs/development.md +28 -10
- package/package.json +2 -2
- package/dist/proxy/forward-messages.d.ts +0 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# devinfra_bridge
|
|
2
2
|
|
|
3
|
-
本机 proxy daemon:接收 Claude Code
|
|
3
|
+
本机 proxy daemon:接收 Claude Code 的 Messages 和 Codex 的 Responses 原生请求,附加机器已有的 ByteCloud JWT,转发到固定 llm gateway。使用 TypeScript,要求 Node.js >=22;无生产 npm 依赖。当前实际验收环境为 Node.js 22,构建目标为 node22。
|
|
4
4
|
|
|
5
5
|
## 开发与运行
|
|
6
6
|
|
|
@@ -11,6 +11,22 @@ cd ~/code/devinfra/devinfra_bridge
|
|
|
11
11
|
npm ci
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
### 最短本机调试流程
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 终端 1:安装开发依赖,构建并前台启动最新 daemon
|
|
18
|
+
cd ~/code/devinfra/devinfra_bridge
|
|
19
|
+
npm ci
|
|
20
|
+
./scripts/debug-daemon.sh
|
|
21
|
+
|
|
22
|
+
# 终端 2:实时查看请求日志(-F 在日志轮转后继续跟随)
|
|
23
|
+
tail -F ~/.local/state/devinfra-bridge/daemon.log
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
终端 1 显示构建、重启、就绪和启动错误;每次 query 的日志在终端 2 查看。修改源码后重新执行重启脚本,当前进程不会自动加载新代码。结束调试,在终端 1 按 Ctrl+C。
|
|
27
|
+
|
|
28
|
+
daemon 启动只完成代理服务就绪;CC/Codex 的模型和 provider 配置由独立 `devinfra_bridge_cli` 工程负责。下面的 curl 验证可以先确认 daemon 和 Gateway 链路。
|
|
29
|
+
|
|
14
30
|
### 命令速查
|
|
15
31
|
|
|
16
32
|
| 功能 | 命令 | 行为与前置条件 |
|
|
@@ -25,11 +41,11 @@ npm ci
|
|
|
25
41
|
| 构建产物启动 | `npm start -- serve --config /absolute/path/bridge.json` | 前台运行 dist/main.js;修改源码后先 build |
|
|
26
42
|
| 文本版本 | `npm start -- --version` | 输出已构建产物的版本,无需配置文件 |
|
|
27
43
|
| JSON 版本 | `npm start -- --version --json` | 输出 `{"version":"..."}`,无需配置文件 |
|
|
28
|
-
| 打包运行验证 | `npm run smoke:artifact` | 先 build;npm pack
|
|
44
|
+
| 打包运行验证 | `npm run smoke:artifact` | 先 build;npm pack 后临时解包,验证 CLI 版本、daemon API 启动、Messages/Responses 和 SIGTERM,不上传 npm |
|
|
29
45
|
| 完整发布前检查 | `npm run prepublishOnly` | 顺序执行 typecheck → lint → test → build → smoke:artifact,不上传 npm |
|
|
30
46
|
| 发布预演 | `npm run publish:dry` | 完整检查后列出包清单;允许当前功能分支,不上传、不要求 npm 登录 |
|
|
31
47
|
|
|
32
|
-
|
|
48
|
+
测试与打包运行验证使用系统分配的独立临时端口,可以与监听 18765 的调试 daemon 同时运行。普通启动命令遇到端口占用会失败,不会终止占用进程。
|
|
33
49
|
|
|
34
50
|
### 调试重启脚本
|
|
35
51
|
|
|
@@ -40,6 +56,11 @@ npm ci
|
|
|
40
56
|
# 指定实际存在的绝对路径;支持含空格的路径
|
|
41
57
|
./scripts/debug-daemon.sh --config "/absolute/path/bridge.json"
|
|
42
58
|
|
|
59
|
+
# 使用独立调试配置/状态目录(首次自动生成;后续复用)
|
|
60
|
+
DEVINFRA_BRIDGE_STATE_ROOT="$HOME/.local/state/devinfra-bridge-debug" ./scripts/debug-daemon.sh
|
|
61
|
+
# 另开终端查看这份配置对应的日志
|
|
62
|
+
tail -F "$HOME/.local/state/devinfra-bridge-debug/daemon.log"
|
|
63
|
+
|
|
43
64
|
# 首次生成配置时覆盖内置 Gateway(已有配置不会被覆盖)
|
|
44
65
|
DEVINFRA_GATEWAY_ORIGIN=https://another-gateway.example ./scripts/debug-daemon.sh
|
|
45
66
|
|
|
@@ -47,19 +68,57 @@ DEVINFRA_GATEWAY_ORIGIN=https://another-gateway.example ./scripts/debug-daemon.s
|
|
|
47
68
|
./scripts/debug-daemon.sh --help
|
|
48
69
|
```
|
|
49
70
|
|
|
50
|
-
设置 `DEVINFRA_BRIDGE_STATE_ROOT` 时,默认配置路径改为该目录下的 `bridge.json
|
|
71
|
+
设置 `DEVINFRA_BRIDGE_STATE_ROOT` 时,默认配置路径改为该目录下的 `bridge.json`;首次生成配置将这个目录写为 `state_root`,已有配置则继续使用其原 `state_root`。daemon 本身不读取这个变量。即使使用独立状态目录,端口仍固定为 18765,不能同时启动两个 daemon。首次运行且默认文件不存在时,脚本自动生成配置(权限 0600),使用内置 Gateway 和 PATH 中的 bytedcli;不写入 JWT。已有配置保持不变;显式 `--config` 指向不存在的文件时仍报错。脚本不修改 CC/Codex 文件、不安装 Node 或依赖,首次使用先执行 `npm ci`。
|
|
51
72
|
|
|
52
73
|
执行顺序:构建最新代码 → 必要时生成默认配置 → 校验运行时和配置 → 打印 TCP 18765 监听进程的 PID/进程名 → SIGTERM → 等待最多 12 秒 → 对仍监听的原进程 SIGKILL → 前台启动 `dist/main.js`。即使监听者不是 bridge,也会按该规则停止;权限不足或端口被其他新进程抢占时退出,不使用 sudo。构建或配置校验失败时保留当前进程。
|
|
53
74
|
|
|
54
75
|
终端显示就绪/启动错误;请求日志写入配置 `state_root` 下的 `daemon.log`,省略 state_root 时为 `~/.local/state/devinfra-bridge/daemon.log`。Ctrl+C 停止 daemon。此脚本供本机开发调试,不包含在 npm 发布包中。
|
|
55
76
|
|
|
77
|
+
### curl 验证真实 Gateway
|
|
78
|
+
|
|
79
|
+
先启动 daemon,再从另一个终端执行。下面两条命令使用 `doubao-seed-evolving`(本机已联调模型);实际模型权限以 Gateway 为准。curl 会产生真实模型调用。
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Messages:非流式;-D 保存响应头,可查看 x-tt-logid
|
|
83
|
+
curl --silent --show-error --max-time 150 \
|
|
84
|
+
-D /tmp/devinfra-bridge-messages.headers \
|
|
85
|
+
http://127.0.0.1:18765/v1/messages \
|
|
86
|
+
-H 'Content-Type: application/json' \
|
|
87
|
+
-H 'Authorization: Bearer devinfra-bridge:cc' \
|
|
88
|
+
-H 'anthropic-version: 2023-06-01' \
|
|
89
|
+
--data-binary '{"model":"doubao-seed-evolving","max_tokens":128,"messages":[{"role":"user","content":"Reply with OK only."}],"stream":false}'
|
|
90
|
+
|
|
91
|
+
# Responses:SSE 流式;-N 关闭 curl 输出缓冲
|
|
92
|
+
curl --silent --show-error -N --max-time 150 \
|
|
93
|
+
-D /tmp/devinfra-bridge-responses.headers \
|
|
94
|
+
http://127.0.0.1:18765/v1/responses \
|
|
95
|
+
-H 'Content-Type: application/json' \
|
|
96
|
+
-H 'Authorization: Bearer devinfra-bridge:codex' \
|
|
97
|
+
--data-binary '{"model":"doubao-seed-evolving","input":"Reply with OK only.","stream":true,"store":false}'
|
|
98
|
+
|
|
99
|
+
# 查看 HTTP 状态、Content-Type 和 Gateway LogID
|
|
100
|
+
cat /tmp/devinfra-bridge-responses.headers
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Responses 将 `stream` 改成 `false` 可测试普通 JSON。本机占位 token 只标识 agent;真实 JWT 由 daemon 自动获取,curl 不需要提供。请求完成后,对应日志应含 `path=/v1/messages` 或 `/v1/responses`、`protocol`、来源 `agent` 和 Gateway LogID。
|
|
104
|
+
|
|
105
|
+
### JWT 过期恢复
|
|
106
|
+
|
|
107
|
+
默认 bytedcli 模式在首个 Gateway 响应为 `HTTP 401`、完整 JSON 的 `error.code` 为 `JWT_EXPIRED` 时,清除过期凭证缓存,执行 `auth get-bytecloud-jwt-token --force-refresh`,随后用原始 body 和新 JWT 重试一次。首个 401 不发送给客户端;第二次响应直接返回,不再次刷新或重试。
|
|
108
|
+
|
|
109
|
+
同一个过期 JWT 的并发请求共用一次刷新;延迟返回的旧 401 不清除新凭证。刷新失败时返回原来的 401。直接读取 JWT 文件/环境变量不刷新、不重试。错误判定最多读取/解压 64 KiB,超限、非 JSON、未知编码或其他错误码均原样返回。成功的 JSON/SSE 保持字节透传,流中错误不重试。
|
|
110
|
+
|
|
111
|
+
`jwt_refresh_started` / `jwt_refresh_succeeded` / `jwt_refresh_failed` / `query_retry` 日志与最终 `request` 使用同一个本机 request_id;恢复日志保留首次 Gateway LogID,最终请求日志保存最终响应 LogID,不记录 JWT 或 query。
|
|
112
|
+
|
|
56
113
|
### 请求日志与 Gateway LogID
|
|
57
114
|
|
|
58
115
|
```bash
|
|
59
|
-
tail -
|
|
116
|
+
tail -F ~/.local/state/devinfra-bridge/daemon.log
|
|
60
117
|
```
|
|
61
118
|
|
|
62
|
-
|
|
119
|
+
通过路由、方法、query、退出状态和并发检查的请求,在完成或中断后写入日志(SSE 在流结束后);请求刚开始时没有日志,启动终端也不会输出请求日志。上述检查提前拒绝的请求,当前不写 `request` 日志,例如未知路由 404、方法错误 405、非法 query 400 或并发超限 429。
|
|
120
|
+
|
|
121
|
+
配置了自定义 `state_root` 时,查看该目录下的 `daemon.log`,不一定是默认路径。日志轮转为 `daemon.log.1` / `daemon.log.2`,推荐使用 `tail -F`。字段包括:
|
|
63
122
|
|
|
64
123
|
| 字段 | 含义 |
|
|
65
124
|
| --- | --- |
|
|
@@ -68,10 +127,20 @@ tail -f ~/.local/state/devinfra-bridge/daemon.log
|
|
|
68
127
|
| `gateway_logid` | Gateway 响应头 `x-tt-logid`,用于云端查日志 |
|
|
69
128
|
| `gateway_request_id` | Gateway 响应头 `request-id` |
|
|
70
129
|
| `gateway_x_request_id` | Gateway 响应头 `x-request-id` |
|
|
71
|
-
| `path` / `
|
|
130
|
+
| `path` / `protocol` / `agent` | 实际路由、messages/responses、识别出的 cc/codex/hermes/x |
|
|
131
|
+
| `status` / `duration_ms` / `code` | 返回状态、耗时、本机错误码 |
|
|
72
132
|
|
|
73
133
|
三个 Gateway ID 分别保存,不互相替代;云端未返回或值不符合长度/字符校验时省略。`x-tt-logid`、`request-id`、`x-request-id` 透传给客户端,仍遵守 HTTP connection header 的剥离规则。日志不记录 query 内容、JWT 或整组 headers,因此不能用 query 文本搜索历史请求。
|
|
74
134
|
|
|
135
|
+
#### 没看到日志时
|
|
136
|
+
|
|
137
|
+
1. 用 `lsof -nP -iTCP:18765 -sTCP:LISTEN` 确认 daemon 正在监听。
|
|
138
|
+
2. 用上面的 curl 命令测试,查看 HTTP 状态和 `x-tt-logid`;这不依赖 agent 的 provider 配置。
|
|
139
|
+
3. 确认读取的是 `bridge.json` 中 `state_root` 对应的日志,流式请求已完成或取消。
|
|
140
|
+
4. curl 有日志、Codex 没日志时,核对有效配置的 `model_provider=devinfra`、provider `base_url=http://127.0.0.1:18765/v1`;同时检查 `CODEX_HOME`、`--profile`、`-c` 或项目配置的覆盖。
|
|
141
|
+
|
|
142
|
+
重启 daemon 不会修改 Codex 配置,也不会把已有 Codex 会话切换到 devinfra provider。未知路径和 WebSocket 当前不转发;提前拒绝的请求不能依赖完成日志定位,应先看客户端返回的状态和错误。
|
|
143
|
+
|
|
75
144
|
### 常用执行组合
|
|
76
145
|
|
|
77
146
|
```bash
|
|
@@ -90,7 +159,7 @@ node dist/main.js serve --config /absolute/path/bridge.json
|
|
|
90
159
|
npm run prepublishOnly
|
|
91
160
|
```
|
|
92
161
|
|
|
93
|
-
|
|
162
|
+
脚本本身也可直接执行(仍在仓库根目录)。两个 shell 脚本也支持 `bash scripts/debug-daemon.sh` / `bash scripts/publish.sh --force`,参数与 `./scripts/...` 相同。
|
|
94
163
|
|
|
95
164
|
```bash
|
|
96
165
|
node scripts/test.mjs # 等价于 npm test
|
|
@@ -111,18 +180,38 @@ node scripts/smoke-artifact.mjs # 等价于 npm run smoke:artifact,先 build
|
|
|
111
180
|
}
|
|
112
181
|
```
|
|
113
182
|
|
|
114
|
-
`gateway_origin` 可选,省略时使用内置 `https://devinfra-llm-gateway.bytedance.net`;显式配置优先。Messages
|
|
183
|
+
`gateway_origin` 可选,省略时使用内置 `https://devinfra-llm-gateway.bytedance.net`;显式配置优先。Messages / Responses 分别发往该 origin 下的 `/v1/messages`、`/v1/responses`。`DEVINFRA_GATEWAY_ORIGIN` 只供调试脚本首次生成配置使用,daemon 本身不读取该环境变量。
|
|
115
184
|
|
|
116
185
|
`state_root` 可选,默认 `~/.local/state/devinfra-bridge`。使用同一 OS 用户及其认证环境启动 daemon;bytedcli 子进程继承 `BYTEDCLI_CLOUD_SITE` / `BYTEDCLI_PROFILE`,无 site 覆盖,固定 `--as user`,不执行登录、不读取 refresh token。
|
|
117
186
|
|
|
118
187
|
正常启动后 stdout 输出一行就绪 JSON。固定监听 `127.0.0.1:18765`;端口占用则退出。用 SIGINT/SIGTERM 停止,最多 10 秒排空 HTTP 请求,随后清理资源。
|
|
119
188
|
|
|
189
|
+
## 周期模型同步
|
|
190
|
+
|
|
191
|
+
daemon ready 后 30 秒调用 CLI;每轮结束后等待 10 分钟,单轮超时 120 秒。固定执行 `sync --yes --non-interactive`,不带 `--force`。模型判断和配置修改全部由 CLI 当前 sync 实现负责。
|
|
192
|
+
|
|
193
|
+
每轮读取 `<state_root>/auto-sync.json`,CLI 接入/同步和软件更新维护该文件:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"enabled": true,
|
|
198
|
+
"cli_entry": "/absolute/path/to/cli/dist/main.js",
|
|
199
|
+
"claude_config_dir": "/Users/example/.claude"
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`enabled=false` 关闭周期同步。文件不存在、`cli_entry` 缺失或目标文件不存在时,直接调用 PATH 中的 `devinfra-bridge-cli` 兜底。有效入口使用 daemon 自身 Node 启动;状态目录固定传入 `DEVINFRA_BRIDGE_STATE_ROOT`,CC 目录使用登记值。配置无效时记录错误,不执行该轮;下一轮重新读取,无需重启。CLI 缺失或执行失败不影响 Query 代理。
|
|
204
|
+
|
|
205
|
+
`daemon.log` 记录 `auto_sync_started`、`auto_sync_finished`、`auto_sync_failed`、`auto_sync_fallback`,包含耗时、退出码和固定错误码,不保存 CLI stdout/stderr。超时或 daemon 退出时结束同步子进程及其派生进程。目录变化写入后,新开的 CC/Codex 会话使用新列表。
|
|
206
|
+
|
|
207
|
+
CLI 必须支持 `sync --yes --non-interactive`;旧 CLI 会返回参数错误,日志为 `CLI_SYNC_FAILED`。`--yes` 仅自动确认当前 sync 修改;`--non-interactive` 禁止交互登录。普通手动 sync 继续要求确认。
|
|
208
|
+
|
|
120
209
|
## 首版行为
|
|
121
210
|
|
|
122
|
-
-
|
|
123
|
-
- 注入 `x-use-agent-plan: 1`、`x-identity-token: <ByteCloud JWT>`、`x-identity-token-type: jwt`、`x-llm-app: devinfra-bridge:<agent>`;剥离客户端 Authorization、x-api-key、Cookie
|
|
124
|
-
- `devinfra-bridge:cc` 是 CC 配置中的固定占位 token,本版不校验;来源 header
|
|
125
|
-
-
|
|
211
|
+
- 转发 `POST /v1/messages`(可带 `?beta=true`)和 `POST /v1/responses`(无 query 参数);共用同一转发实现,原始 body 与 JSON/SSE 字节不转换。不解析请求 JSON、不验证 UTF-8 或 model,模型及参数是否合法交给 Gateway。保留请求大小、未压缩编码、超时和并发限制。
|
|
212
|
+
- 注入 `x-use-agent-plan: 1`、`x-identity-token: <ByteCloud JWT>`、`x-identity-token-type: jwt`、`x-llm-app: devinfra-bridge:<agent>`;剥离客户端 Authorization、x-api-key、Cookie 等凭据。`X-Devinfra-Agent` 保留路由标签语义:Messages 为 `claude-code`,Responses 为 `codex`;真实来源统计使用 `x-llm-app`。
|
|
213
|
+
- `devinfra-bridge:cc` 是 CC 配置中的固定占位 token,本版不校验;来源 header 由占位标记或客户端 header 识别,不能证明发送进程身份。
|
|
214
|
+
- 背压、取消、分阶段超时;只在首个响应为 `401 + error.code=JWT_EXPIRED` 时强制刷新并用原始 body 重试一次;第二次响应直接返回,其他错误不重试。
|
|
126
215
|
- `/v1/models`、`count_tokens`、管理接口返回 404;CLI、安装、模型配置、配置恢复、目录查询由其他项目负责。
|
|
127
216
|
|
|
128
217
|
更多见 [开发说明](docs/development.md)、[验收说明](docs/acceptance.md)和 [实施计划](docs/superpowers/plans/2026-11-09-cc-gateway-integration.md)。
|
|
@@ -131,15 +220,38 @@ node scripts/smoke-artifact.mjs # 等价于 npm run smoke:artifact,先 build
|
|
|
131
220
|
|
|
132
221
|
CLI 配置 agent 的占位凭据使用 `devinfra-bridge:{agent}`:CC 为 `devinfra-bridge:cc`,Codex 为 `devinfra-bridge:codex`,Hermes 为 `devinfra-bridge:hermes`,未知类型为 `devinfra-bridge:x`。CC 写在 settings.json 的 `env.ANTHROPIC_AUTH_TOKEN`;真实 JWT 只由 daemon 获取,不写入 agent 配置。
|
|
133
222
|
|
|
134
|
-
daemon 优先读取 Authorization Bearer 中的标记,再读取 x-api-key;没有显式标记时,通过已知 User-Agent 和 Codex originator 兜底识别。未知标记或无法识别的客户端统一为 x;不按 Messages/Responses 协议推断 agent。新增类型需同步 `src/agents/identity.ts` 注册表。所有上游身份 header
|
|
223
|
+
daemon 优先读取 Authorization Bearer 中的标记,再读取 x-api-key;没有显式标记时,通过已知 User-Agent 和 Codex originator 兜底识别。未知标记或无法识别的客户端统一为 x;不按 Messages/Responses 协议推断 agent。新增类型需同步 `src/agents/identity.ts` 注册表。所有上游身份 header 由共用转发函数覆盖生成,Messages 与 Responses 复用这套规则。
|
|
135
224
|
|
|
136
225
|
占位标记和客户端 header 都只用于来源统计,不认证发送进程;缺少或使用任意占位凭据不会被本机 daemon 拒绝。CLI 无需自行配置 Gateway 身份 header。
|
|
137
226
|
|
|
227
|
+
### Codex 接入
|
|
228
|
+
|
|
229
|
+
外部 CLI 负责合并 `~/.codex/config.toml`、生成模型目录和恢复配置,daemon 不修改用户文件。以下仅示意 provider 的接入字段;模型 ID 与完整目录由 CLI 提供:
|
|
230
|
+
|
|
231
|
+
```toml
|
|
232
|
+
model_provider = "devinfra"
|
|
233
|
+
|
|
234
|
+
[model_providers.devinfra]
|
|
235
|
+
name = "devinfra"
|
|
236
|
+
base_url = "http://127.0.0.1:18765/v1"
|
|
237
|
+
wire_api = "responses"
|
|
238
|
+
experimental_bearer_token = "devinfra-bridge:codex"
|
|
239
|
+
requires_openai_auth = false
|
|
240
|
+
supports_websockets = false
|
|
241
|
+
|
|
242
|
+
[features]
|
|
243
|
+
enable_request_compression = false
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
首版使用未压缩请求和 HTTP SSE,不提供 WebSocket、专用 `/v1/responses/compact` 或 Response 查询/删除等附属端点。普通 `devinfra` provider 的摘要请求由 Codex 组织,走同一个 `/v1/responses`;目标 Codex 版本需由 CLI 和 Gateway 联调验收。
|
|
247
|
+
|
|
248
|
+
Responses 保留已声明的 Codex 会话、轮次和协议 header,尤其 `x-codex-turn-state` 双向透传;不无条件放行全部 `x-*`。Gateway 错误原样返回,daemon 本机错误用 OpenAI 格式。日志记录实际 `path`、`protocol`、来源 `agent` 与 Gateway LogID,不记录请求 body 或 JWT。
|
|
249
|
+
|
|
138
250
|
## npm 包与发布
|
|
139
251
|
|
|
140
|
-
包名 `devinfra-bridge
|
|
252
|
+
包名 `devinfra-bridge`,MIT 许可证。初始版本为 `0.1.0-alpha.1`,当前发版版本以 `package.json` 为准。发布到公网 npm 的 `alpha` 标签,供外部 CLI 联调;真实 CC + Gateway 验收见验收说明。
|
|
141
253
|
|
|
142
|
-
|
|
254
|
+
发布和预演都会执行完整检查(`--help` 除外);测试和解包验证使用独立临时端口,无需停止调试 daemon。`--force` 仅跳过分支限制,不会跳过测试、npm 权限或 2FA。真实发布需 npm 公网登录凭据具有目标包写权限,并满足 2FA 要求。第一次发新包可通过账号登录并完成 2FA,或使用覆盖新包、启用 bypass 2FA 的 granular token;`npm whoami` 成功仅确认登录身份。
|
|
143
255
|
|
|
144
256
|
| 执行方式 | 行为 |
|
|
145
257
|
| --- | --- |
|
|
@@ -148,7 +260,7 @@ daemon 优先读取 Authorization Bearer 中的标记,再读取 x-api-key;
|
|
|
148
260
|
| `./scripts/publish.sh --force` | 从当前功能分支发布,只跳过分支限制,仍检查并确认 |
|
|
149
261
|
| `./scripts/publish.sh --dry-run` | 检查并列出包清单,不上传;保留分支限制 |
|
|
150
262
|
| `./scripts/publish.sh --dry-run --force` | 功能分支发布预演,等价于 `npm run publish:dry` |
|
|
151
|
-
| `./scripts/publish.sh --yes
|
|
263
|
+
| `./scripts/publish.sh --yes`(或 `-y`) | 跳过最终 y/N,仍检查分支及完整验证;可用于 CI |
|
|
152
264
|
| `./scripts/publish.sh --force --yes` | 跳过分支限制和最终确认,检查通过后直接上传 |
|
|
153
265
|
|
|
154
266
|
```bash
|
|
@@ -166,6 +278,6 @@ npm run publish:dry
|
|
|
166
278
|
npm view devinfra-bridge@alpha version --registry=https://registry.npmjs.org/
|
|
167
279
|
```
|
|
168
280
|
|
|
169
|
-
|
|
281
|
+
每次发布选择一个尚未发布的新版本,例如将 `0.1.0-alpha.2` 改为 `0.1.0-alpha.3`;npm 同一版本不能重复发布。发版只需手工修改 `package.json` 的 `version`;发布脚本以它为准,不要求 lockfile 根版本同步,仍校验 npm 包和构建产物版本。脚本不会自动修改版本、暂存或提交。预发布版本自动使用 alpha/beta/rc/next 标签,正式版本使用 latest;检查包括 typecheck、lint、测试、构建与解包运行。直接运行 `npm publish` 会通过 `prepublishOnly` 执行这些检查;发布脚本先执行检查,再使用 `npm publish --ignore-scripts` 上传,避免重复验证。
|
|
170
282
|
|
|
171
283
|
外部 CLI 可添加依赖 `devinfra-bridge@alpha`,通过 Node.js >=22 启动安装包中的 `dist/main.js serve --config ...`,或导入 `startDaemon`。本包没有 `bin` 命令,用户 CLI 在独立项目中提供。
|
package/dist/agents/types.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import type { ProxyContext } from "../proxy/server.js";
|
|
3
|
+
export type ModelProtocol = "messages" | "responses";
|
|
3
4
|
export interface AgentRoute {
|
|
5
|
+
protocol: ModelProtocol;
|
|
6
|
+
allowedQueries: readonly string[];
|
|
4
7
|
agent: string;
|
|
5
|
-
path:
|
|
8
|
+
path: "/v1/messages" | "/v1/responses";
|
|
6
9
|
method: string;
|
|
7
|
-
forward(req: IncomingMessage, res: ServerResponse, context: ProxyContext, signal: AbortSignal, agent: string, onUpstreamHeaders?: (headers: IncomingHttpHeaders) => void): Promise<void>;
|
|
10
|
+
forward(req: IncomingMessage, res: ServerResponse, context: ProxyContext, signal: AbortSignal, agent: string, protocol: ModelProtocol, onUpstreamHeaders?: (headers: IncomingHttpHeaders) => void, requestId?: string): Promise<void>;
|
|
8
11
|
}
|
|
@@ -10,6 +10,8 @@ export declare class BytedcliProvider implements CredentialProvider {
|
|
|
10
10
|
private readonly controller;
|
|
11
11
|
private pending?;
|
|
12
12
|
private cached?;
|
|
13
|
+
private latestJwt?;
|
|
14
|
+
private recovery?;
|
|
13
15
|
private readonly timeoutMs;
|
|
14
16
|
private readonly outputBytes;
|
|
15
17
|
private readonly cacheMs;
|
|
@@ -17,6 +19,11 @@ export declare class BytedcliProvider implements CredentialProvider {
|
|
|
17
19
|
getJwt({ signal }?: {
|
|
18
20
|
signal?: AbortSignal;
|
|
19
21
|
}): Promise<string>;
|
|
22
|
+
refreshJwt(failedJwt: string, { signal }?: {
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}): Promise<string>;
|
|
25
|
+
private track;
|
|
26
|
+
private wait;
|
|
20
27
|
private acquire;
|
|
21
28
|
close(): Promise<void>;
|
|
22
29
|
}
|
|
@@ -3,6 +3,9 @@ export interface CredentialProvider {
|
|
|
3
3
|
getJwt(options?: {
|
|
4
4
|
signal?: AbortSignal;
|
|
5
5
|
}): Promise<string>;
|
|
6
|
+
refreshJwt?(failedJwt: string, options?: {
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
}): Promise<string>;
|
|
6
9
|
close(): Promise<void>;
|
|
7
10
|
}
|
|
8
11
|
export declare class CredentialError extends Error {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Logger } from "../util/logger.js";
|
|
2
|
+
export declare const AUTO_SYNC_STARTUP_MS = 30000;
|
|
3
|
+
export declare const AUTO_SYNC_INTERVAL_MS = 600000;
|
|
4
|
+
export declare const AUTO_SYNC_TIMEOUT_MS = 120000;
|
|
5
|
+
interface RunOptions {
|
|
6
|
+
signal: AbortSignal;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
killGraceMs?: number;
|
|
9
|
+
env?: NodeJS.ProcessEnv;
|
|
10
|
+
}
|
|
11
|
+
export declare function runAutoSync(stateRoot: string, logger: Logger, options: RunOptions): Promise<void>;
|
|
12
|
+
interface SchedulerOptions {
|
|
13
|
+
startupMs?: number;
|
|
14
|
+
intervalMs?: number;
|
|
15
|
+
run?: (signal: AbortSignal) => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare function startAutoSync(stateRoot: string, logger: Logger, options?: SchedulerOptions): {
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
package/dist/daemon/daemon.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { type DaemonConfig, HOST
|
|
1
|
+
import { type DaemonConfig, HOST } from "../config/types.js";
|
|
2
2
|
export interface DaemonHandle {
|
|
3
3
|
instanceId: string;
|
|
4
4
|
host: typeof HOST;
|
|
5
|
-
port:
|
|
5
|
+
port: number;
|
|
6
6
|
close(options?: {
|
|
7
7
|
drainMs?: number;
|
|
8
8
|
}): Promise<void>;
|
|
9
9
|
}
|
|
10
|
-
export
|
|
10
|
+
export interface DaemonOptions {
|
|
11
|
+
/** Defaults to 18765; use 0 to request an OS-assigned port for isolated tests. */
|
|
12
|
+
port?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function startDaemon(config: DaemonConfig, { port: requestedPort }?: DaemonOptions): Promise<DaemonHandle>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Server } from "node:http";
|
|
2
|
-
export declare function bindSingleInstance(server: Server): Promise<
|
|
3
|
-
export declare function writeInstance(stateRoot: string, id: string, version: string): Promise<() => Promise<void>>;
|
|
2
|
+
export declare function bindSingleInstance(server: Server, port?: number): Promise<number>;
|
|
3
|
+
export declare function writeInstance(stateRoot: string, id: string, version: string, port?: number): Promise<() => Promise<void>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { assertSupportedNode, loadDaemonConfig, parseDaemonConfig } from "./conf
|
|
|
2
2
|
export { CC_PLACEHOLDER_TOKEN, DEFAULT_GATEWAY_ORIGIN, HOST, PORT } from "./config/types.js";
|
|
3
3
|
export type { AuthConfig, DaemonConfig } from "./config/types.js";
|
|
4
4
|
export { startDaemon } from "./daemon/daemon.js";
|
|
5
|
-
export type { DaemonHandle } from "./daemon/daemon.js";
|
|
5
|
+
export type { DaemonHandle, DaemonOptions } from "./daemon/daemon.js";
|
|
6
6
|
export type { CredentialProvider } from "./auth/credential-provider.js";
|