billion-context 0.1.102 → 0.1.103-pr.696.525
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 +4 -1
- package/README.zh-CN.md +4 -1
- package/dist/index.js +320 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ rewrite until dsh gains a settings-path env or an upstream loopback opt-out.
|
|
|
158
158
|
Overlay dirs created by older versions are left in place and never merged back
|
|
159
159
|
into the real home.
|
|
160
160
|
|
|
161
|
-
### Option 1 — Launcher (`bili pi` / `bili codex` / `bili claude` / `bili omp` / `bili opencode` / `bili hermes` / `bili dsh`)
|
|
161
|
+
### Option 1 — Launcher (`bili pi` / `bili codex` / `bili claude` / `bili omp` / `bili opencode` / `bili hermes` / `bili dsh` / `bili codebuddy` / `bili qoder` / `bili trae`)
|
|
162
162
|
|
|
163
163
|
The launcher wraps a client in one command: it starts a proxy on an
|
|
164
164
|
independent port (a fresh instance is always spawned — a port is never
|
|
@@ -177,6 +177,9 @@ bili omp # pi-style, file-free (#535): env + extens
|
|
|
177
177
|
bili opencode # MITM for HTTPS + temp opencode.json (/bili/ for HTTP) + thin /acp plugin
|
|
178
178
|
bili hermes # file-free (#535): hermes proxy env (HTTPS_PROXY + HERMES_CA_BUNDLE) — https via CONNECT MITM, http via absolute-form forward proxy; real ~/.hermes untouched
|
|
179
179
|
bili dsh # deepseek-harness: non-loopback upstreams ride proxy envs (https MITM, http absolute-form), loopback keeps the overlay DSH_HOME (~/.dsh-bili) rewrite (#535), built-in deepseek route via DEEPSEEK_BASE_URL, native /acp command injected via --patch
|
|
180
|
+
bili codebuddy # Tencent CodeBuddy Code CLI: CODEBUDDY_BASE_URL /bili/ rewrite (OpenAI chat completions wire), budget aligned via CODEBUDDY_AUTO_COMPACT_WINDOW; real ~/.codebuddy untouched
|
|
181
|
+
bili qoder # qoder: model endpoint is hardcoded https (no /bili/ rewrite possible) — cert-MITM via HTTPS_PROXY + NODE_EXTRA_CA_CERTS, default model hosts whitelisted (#653)
|
|
182
|
+
bili trae # Trae CLI (ByteDance, closed Go binary, no base-URL override) — cert-MITM via HTTPS_PROXY + SSL_CERT_FILE, model host from TRAE_CLI_API_HOST or the default enterprise gateway (#655)
|
|
180
183
|
bili pi --mitm-domain api.foo.com # add a domain to the MITM whitelist
|
|
181
184
|
```
|
|
182
185
|
|
package/README.zh-CN.md
CHANGED
|
@@ -84,7 +84,7 @@ npm install -g billion-context
|
|
|
84
84
|
|
|
85
85
|
bili 永不拥有用户数据:每个被启动的客户端都跑在**真实 home** 上,运行期写入落在用户预期的位置。把客户端指向代理时,启动器按优先级选择——**优先 env 变量**(hermes/dsh/codex 的代理/CA env;pi/omp 的 `BILI_PROVIDER_REWRITES` URL 清单,由扩展加载时经 `registerProvider` 消费),其次 **CLI 参数或扩展 API**(codex `-c key=value`、opencode 插件),最后才是**生成文件**——目前仅剩 opencode 的临时 `opencode.json`(退出即删)和 dsh 的回环例外:dsh 的 fetch 栈对回环目标无条件绕过代理 env,所以本地上游保留持久 `~/.dsh-bili` overlay 改写,直到 dsh 提供 settings-path env 或上游支持回环 opt-out。旧版本创建的 overlay 目录原地保留,绝不合并回真实 home。
|
|
86
86
|
|
|
87
|
-
### 方式 1 —— 启动器(`bili pi` / `bili codex` / `bili claude` / `bili omp` / `bili opencode` / `bili hermes` / `bili dsh`)
|
|
87
|
+
### 方式 1 —— 启动器(`bili pi` / `bili codex` / `bili claude` / `bili omp` / `bili opencode` / `bili hermes` / `bili dsh` / `bili codebuddy` / `bili qoder` / `bili trae`)
|
|
88
88
|
|
|
89
89
|
启动器把客户端包进一条命令:在独立端口拉起一个代理(总是全新实例,绝不复用端口),再按客户端支持的机制把它指向代理 —— 能吃代理/CA 环境变量的走**证书 MITM**,不吃的走隔离的**`/bili/` 配置重写**。真实配置文件从不被修改;客户端自己的配置只被**读取**,用来发现它实际连接的 HTTPS 上游主机,把这些主机加入 MITM 白名单 —— 代理只 TLS 终结它们,其余流量盲透传。
|
|
90
90
|
|
|
@@ -96,6 +96,9 @@ bili omp # pi 同款,file-free(#535):环境变量 +
|
|
|
96
96
|
bili opencode # HTTPS 走 MITM + 临时 opencode.json(HTTP 走 /bili/)+ 轻量 /acp 插件
|
|
97
97
|
bili hermes # file-free(#535):hermes 代理环境变量(HTTPS_PROXY + HERMES_CA_BUNDLE)—— https 走 CONNECT MITM,http 走绝对形式转发;真实 ~/.hermes 不动
|
|
98
98
|
bili dsh # deepseek-harness:非回环上游走代理 env(https MITM、http absolute-form),回环上游保留 overlay DSH_HOME(~/.dsh-bili)改写(#535),内置 deepseek 路由走 DEEPSEEK_BASE_URL,经 --patch 注入原生 /acp 命令
|
|
99
|
+
bili codebuddy # Tencent CodeBuddy Code CLI:CODEBUDDY_BASE_URL /bili/ 重写(OpenAI chat completions wire),预算对齐走 CODEBUDDY_AUTO_COMPACT_WINDOW;真实 ~/.codebuddy 不动
|
|
100
|
+
bili qoder # qoder:模型端点硬编码 https(无法 /bili/ 改写)—— 证书 MITM(HTTPS_PROXY + NODE_EXTRA_CA_CERTS),默认模型主机已加白名单(#653)
|
|
101
|
+
bili trae # Trae CLI(字节跳动,闭源 Go 二进制,无 base-URL 覆盖)—— 证书 MITM(HTTPS_PROXY + SSL_CERT_FILE),模型主机取 TRAE_CLI_API_HOST 或默认企业网关(#655)
|
|
99
102
|
bili pi --mitm-domain api.foo.com # 向 MITM 白名单追加域名
|
|
100
103
|
```
|
|
101
104
|
|
package/dist/index.js
CHANGED
|
@@ -51956,7 +51956,11 @@ ${reasons.map((r) => `- ${r}`).join("\n")}` : "";
|
|
|
51956
51956
|
const shrinkRatio = preContext > 0 ? r.tokensCompressed / preContext : 0;
|
|
51957
51957
|
const foldPoint = [...ranges].sort((a, b2) => refNum(a.startRef) - refNum(b2.startRef))[0]?.startRef ?? "unknown";
|
|
51958
51958
|
ctx.session.lastCompress = { at: Date.now(), shrinkRatio, foldPoint, blocks: r.blocksCreated, tokensCompressed: r.tokensCompressed };
|
|
51959
|
-
ctx.
|
|
51959
|
+
ctx.session.stats.pendingFoldUsage = true;
|
|
51960
|
+
const anchorTok = res.state.blocks.reduce((n, b2) => n + (b2.active ? Math.ceil(b2.summary.length / 4) : 0), 0);
|
|
51961
|
+
const postCtx = Math.max(0, preContext - r.tokensCompressed);
|
|
51962
|
+
const ceiling = postCtx > 0 ? Math.floor(100 * anchorTok / postCtx) : 0;
|
|
51963
|
+
ctx.log(`[acp-compress-obs] shrink ${Math.round(shrinkRatio * 100)}% (~${r.tokensCompressed}/${preContext} tok) foldPoint=${foldPoint} blocks=${r.blocksCreated} anchor\u2248${anchorTok} tok (${res.state.blocks.filter((b2) => b2.active).length} active blocks, sys excluded) postCtx\u2248${postCtx} \u2192 next-request cache ceiling \u2265${ceiling}%`);
|
|
51960
51964
|
const warn = r.warnings.length > 0 ? ` ${r.warnings.join("; ")}` : "";
|
|
51961
51965
|
let msg = `[Compressed ${detail} \u2192 ${r.blocksCreated} block(s), ~${r.tokensCompressed} tokens saved.${warn}]`;
|
|
51962
51966
|
const maxShrink = maxShrinkPerCompress();
|
|
@@ -53490,8 +53494,10 @@ function recordUsage(ctx, usage, round) {
|
|
|
53490
53494
|
if (typeof out === "number") ctx.session.stats.outputTokens += out;
|
|
53491
53495
|
const hitPct = typeof cached === "number" && total > 0 ? Math.round(cached / total * 100) : 0;
|
|
53492
53496
|
warnCacheCollapse(ctx.session, total, cached ?? 0);
|
|
53497
|
+
const foldNew = ctx.session.stats.pendingFoldUsage === true;
|
|
53498
|
+
if (foldNew) ctx.session.stats.pendingFoldUsage = false;
|
|
53493
53499
|
ctx.log(
|
|
53494
|
-
`[acp-usage] round ${round} input=${total} cached=${cached ?? 0} (cache hit ${hitPct}%)`
|
|
53500
|
+
`[acp-usage] round ${round} input=${total} cached=${cached ?? 0} (cache hit ${hitPct}%)${foldNew ? " fold=new" : ""}`
|
|
53495
53501
|
);
|
|
53496
53502
|
}
|
|
53497
53503
|
async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adapter, systemPrompt, signal) {
|
|
@@ -56770,6 +56776,10 @@ function applyUsageSample(session, sample, protocol) {
|
|
|
56770
56776
|
session.stats.lastInputTokens = Math.max(0, total - (session.stats.compressCreditTokens ?? 0));
|
|
56771
56777
|
warnCacheCollapse(session, total, sample.cachedTokens ?? 0);
|
|
56772
56778
|
session.hostContextTokens = total + (session.hostCreditTokens ?? 0);
|
|
56779
|
+
const hit = sample.cachedTokens === void 0 || total <= 0 ? void 0 : Math.round(100 * (sample.cachedTokens ?? 0) / total);
|
|
56780
|
+
const foldNew = session.stats.pendingFoldUsage === true;
|
|
56781
|
+
if (foldNew) session.stats.pendingFoldUsage = false;
|
|
56782
|
+
log("info", `[${session.id}] [plugin] [acp-usage] input=${total} cached=${sample.cachedTokens ?? "n/a"}${hit === void 0 ? "" : ` (cache hit ${hit}%)`} ctx=${session.hostContextTokens}${foldNew ? " fold=new" : ""}`);
|
|
56773
56783
|
}
|
|
56774
56784
|
if (sample.outputTokens !== void 0) session.stats.outputTokens += sample.outputTokens;
|
|
56775
56785
|
}
|
|
@@ -57282,6 +57292,55 @@ import path10 from "path";
|
|
|
57282
57292
|
function toModelWindow(id, contextWindow) {
|
|
57283
57293
|
return typeof id === "string" && id.length > 0 && typeof contextWindow === "number" && Number.isFinite(contextWindow) && contextWindow > 0 ? { id, contextWindow: Math.floor(contextWindow) } : null;
|
|
57284
57294
|
}
|
|
57295
|
+
var QODER_DEFAULT_MODEL_HOSTS = [
|
|
57296
|
+
"api2-v2.qoder.sh",
|
|
57297
|
+
"api1.qoder.sh",
|
|
57298
|
+
"api2.qoder.sh",
|
|
57299
|
+
"api3.qoder.sh",
|
|
57300
|
+
"gateway.qoder.com.cn"
|
|
57301
|
+
];
|
|
57302
|
+
function qoderIsCnSite(env = process.env) {
|
|
57303
|
+
const site = env.QODERCLI_SITE?.trim().toLowerCase();
|
|
57304
|
+
if (site === "cn") return true;
|
|
57305
|
+
if (nonEmpty2(env.QODERCN_CONFIG_DIR) || nonEmpty2(env.QODERCN_CLI_HOME)) return true;
|
|
57306
|
+
const h = os.homedir();
|
|
57307
|
+
const cnDir = path10.join(h, ".qoder-cn");
|
|
57308
|
+
const intlDir = path10.join(h, ".qoder");
|
|
57309
|
+
try {
|
|
57310
|
+
if (fs6.existsSync(cnDir) && !fs6.existsSync(intlDir)) return true;
|
|
57311
|
+
} catch {
|
|
57312
|
+
}
|
|
57313
|
+
return false;
|
|
57314
|
+
}
|
|
57315
|
+
function resolveQoderHome(env = process.env) {
|
|
57316
|
+
const h = os.homedir();
|
|
57317
|
+
const cn2 = qoderIsCnSite(env);
|
|
57318
|
+
const configDir2 = cn2 ? env.QODERCN_CONFIG_DIR : env.QODER_CONFIG_DIR;
|
|
57319
|
+
if (nonEmpty2(configDir2)) return configDir2;
|
|
57320
|
+
const cliHomeEnv = cn2 ? env.QODERCN_CLI_HOME : env.QODER_CLI_HOME;
|
|
57321
|
+
const cliHome = nonEmpty2(cliHomeEnv) ? cliHomeEnv : h;
|
|
57322
|
+
const dirNameEnv = cn2 ? env.QODERCN_CONFIG_DIR_NAME : env.QODER_CONFIG_DIR_NAME;
|
|
57323
|
+
const dirName = nonEmpty2(dirNameEnv) ? dirNameEnv : cn2 ? ".qoder-cn" : ".qoder";
|
|
57324
|
+
return path10.join(cliHome, dirName);
|
|
57325
|
+
}
|
|
57326
|
+
function readQoderConfig(qoderHome, env = process.env) {
|
|
57327
|
+
const result = {};
|
|
57328
|
+
const obj = readJsonObject(path10.join(qoderHome, "settings.json"));
|
|
57329
|
+
const model = obj?.model;
|
|
57330
|
+
if (typeof model === "string" && model.trim().length > 0) {
|
|
57331
|
+
result.model = model.trim();
|
|
57332
|
+
} else if (model && typeof model === "object" && !Array.isArray(model)) {
|
|
57333
|
+
const name = model.name;
|
|
57334
|
+
if (nonEmpty2(name)) result.model = name.trim();
|
|
57335
|
+
}
|
|
57336
|
+
const cn2 = qoderIsCnSite(env);
|
|
57337
|
+
const host = nonEmpty2(cn2 ? env.QODERCN_MODEL_SERVER_HOST : env.QODER_MODEL_SERVER_HOST) ? cn2 ? env.QODERCN_MODEL_SERVER_HOST : env.QODER_MODEL_SERVER_HOST : void 0;
|
|
57338
|
+
if (host) {
|
|
57339
|
+
const bare = host.trim().replace(/^https?:\/\//i, "").replace(/\/+$/, "");
|
|
57340
|
+
if (bare.length > 0) result.modelServerHost = bare;
|
|
57341
|
+
}
|
|
57342
|
+
return result;
|
|
57343
|
+
}
|
|
57285
57344
|
function nonEmpty2(s3) {
|
|
57286
57345
|
return typeof s3 === "string" && s3.trim().length > 0;
|
|
57287
57346
|
}
|
|
@@ -57314,6 +57373,98 @@ function resolveCodexHome(env) {
|
|
|
57314
57373
|
const h = os.homedir();
|
|
57315
57374
|
return nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path10.join(h, ".codex");
|
|
57316
57375
|
}
|
|
57376
|
+
function resolveCodebuddyHome(env) {
|
|
57377
|
+
const h = os.homedir();
|
|
57378
|
+
return nonEmpty2(env.CODEBUDDY_CONFIG_DIR) ? env.CODEBUDDY_CONFIG_DIR : path10.join(h, ".codebuddy");
|
|
57379
|
+
}
|
|
57380
|
+
function parseCodebuddyModelsJson(obj) {
|
|
57381
|
+
const out = { models: [], urls: [] };
|
|
57382
|
+
const seenUrl = /* @__PURE__ */ new Set();
|
|
57383
|
+
const collect = (id, entry) => {
|
|
57384
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return;
|
|
57385
|
+
const e = entry;
|
|
57386
|
+
const url = e.url;
|
|
57387
|
+
if (typeof url === "string" && url.length > 0 && !seenUrl.has(url)) {
|
|
57388
|
+
seenUrl.add(url);
|
|
57389
|
+
out.urls.push(url);
|
|
57390
|
+
}
|
|
57391
|
+
const win = toModelWindow(id, e.maxInputTokens);
|
|
57392
|
+
if (win) out.models.push(win);
|
|
57393
|
+
};
|
|
57394
|
+
if (!obj) return out;
|
|
57395
|
+
if (Array.isArray(obj)) {
|
|
57396
|
+
for (const item of obj) {
|
|
57397
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
57398
|
+
const it2 = item;
|
|
57399
|
+
collect(it2.id ?? it2.name, it2);
|
|
57400
|
+
}
|
|
57401
|
+
return out;
|
|
57402
|
+
}
|
|
57403
|
+
if (typeof obj !== "object") return out;
|
|
57404
|
+
const root = obj;
|
|
57405
|
+
const modelsField = root.models;
|
|
57406
|
+
if (Array.isArray(modelsField)) {
|
|
57407
|
+
for (const item of modelsField) {
|
|
57408
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
57409
|
+
const it2 = item;
|
|
57410
|
+
collect(it2.id ?? it2.name, it2);
|
|
57411
|
+
}
|
|
57412
|
+
return out;
|
|
57413
|
+
}
|
|
57414
|
+
if (modelsField && typeof modelsField === "object") {
|
|
57415
|
+
for (const [id, val] of Object.entries(modelsField)) collect(id, val);
|
|
57416
|
+
return out;
|
|
57417
|
+
}
|
|
57418
|
+
for (const [id, val] of Object.entries(root)) collect(id, val);
|
|
57419
|
+
return out;
|
|
57420
|
+
}
|
|
57421
|
+
function readJsonFile(filePath) {
|
|
57422
|
+
try {
|
|
57423
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf8"));
|
|
57424
|
+
} catch {
|
|
57425
|
+
return null;
|
|
57426
|
+
}
|
|
57427
|
+
}
|
|
57428
|
+
function readCodebuddyConfig(codebuddyHome, cwd, env = process.env) {
|
|
57429
|
+
let codebuddyBaseUrl;
|
|
57430
|
+
let model;
|
|
57431
|
+
let autoCompactWindow;
|
|
57432
|
+
const settings = readJsonObject(path10.join(codebuddyHome, "settings.json"));
|
|
57433
|
+
const settingsEnv = settings?.env;
|
|
57434
|
+
if (settingsEnv && typeof settingsEnv === "object" && !Array.isArray(settingsEnv)) {
|
|
57435
|
+
const e = settingsEnv;
|
|
57436
|
+
const v2 = e.CODEBUDDY_BASE_URL;
|
|
57437
|
+
if (nonEmpty2(v2)) codebuddyBaseUrl = v2;
|
|
57438
|
+
}
|
|
57439
|
+
const tm = settings?.model;
|
|
57440
|
+
if (nonEmpty2(tm)) model = String(tm);
|
|
57441
|
+
const tacw = Number(settings?.autoCompactWindow);
|
|
57442
|
+
if (Number.isFinite(tacw) && tacw > 0) autoCompactWindow = tacw;
|
|
57443
|
+
if (!codebuddyBaseUrl && nonEmpty2(env.CODEBUDDY_BASE_URL)) codebuddyBaseUrl = env.CODEBUDDY_BASE_URL;
|
|
57444
|
+
const windowByModel = /* @__PURE__ */ new Map();
|
|
57445
|
+
const urls = [];
|
|
57446
|
+
const seenUrl = /* @__PURE__ */ new Set();
|
|
57447
|
+
for (const f2 of [
|
|
57448
|
+
path10.join(codebuddyHome, "models.json"),
|
|
57449
|
+
path10.join(cwd, ".codebuddy", "models.json")
|
|
57450
|
+
]) {
|
|
57451
|
+
const parsed = parseCodebuddyModelsJson(readJsonFile(f2));
|
|
57452
|
+
for (const w2 of parsed.models) windowByModel.set(w2.id, w2.contextWindow);
|
|
57453
|
+
for (const u2 of parsed.urls) {
|
|
57454
|
+
if (!seenUrl.has(u2)) {
|
|
57455
|
+
seenUrl.add(u2);
|
|
57456
|
+
urls.push(u2);
|
|
57457
|
+
}
|
|
57458
|
+
}
|
|
57459
|
+
}
|
|
57460
|
+
return {
|
|
57461
|
+
...codebuddyBaseUrl ? { codebuddyBaseUrl } : {},
|
|
57462
|
+
...model ? { model } : {},
|
|
57463
|
+
...autoCompactWindow ? { autoCompactWindow } : {},
|
|
57464
|
+
...windowByModel.size > 0 ? { models: [...windowByModel.entries()].map(([id, contextWindow]) => ({ id, contextWindow })) } : {},
|
|
57465
|
+
...urls.length > 0 ? { modelUrls: urls } : {}
|
|
57466
|
+
};
|
|
57467
|
+
}
|
|
57317
57468
|
function parseDshSettingsYaml(text) {
|
|
57318
57469
|
const out = [];
|
|
57319
57470
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -57337,6 +57488,20 @@ function readDshConfig(dshHome) {
|
|
|
57337
57488
|
}
|
|
57338
57489
|
return { baseUrls: parseDshSettingsYaml(text) };
|
|
57339
57490
|
}
|
|
57491
|
+
var TRAE_DEFAULT_MODEL_HOSTS = [
|
|
57492
|
+
"console.enterprise.trae.cn",
|
|
57493
|
+
"www.trae.cn"
|
|
57494
|
+
];
|
|
57495
|
+
function resolveTraeHome(env) {
|
|
57496
|
+
const h = os.homedir();
|
|
57497
|
+
return nonEmpty2(env.TRAE_CONFIG_DIR) ? env.TRAE_CONFIG_DIR : path10.join(h, ".trae");
|
|
57498
|
+
}
|
|
57499
|
+
function readTraeConfig(env) {
|
|
57500
|
+
const result = {};
|
|
57501
|
+
const host = nonEmpty2(env.TRAE_CLI_API_HOST) ? env.TRAE_CLI_API_HOST.replace(/^https?:\/\//i, "").replace(/\/+$/, "") : void 0;
|
|
57502
|
+
if (host) result.modelApiHost = host;
|
|
57503
|
+
return result;
|
|
57504
|
+
}
|
|
57340
57505
|
function readClaudeSettings(homeDir, cwd, env = process.env) {
|
|
57341
57506
|
const files = [
|
|
57342
57507
|
path10.join(homeDir, ".claude", "settings.json"),
|
|
@@ -57687,6 +57852,9 @@ function loadClientConfig(env, cwd) {
|
|
|
57687
57852
|
config.opencode = readOpencodeConfig(resolveOpencodeConfigFile(env));
|
|
57688
57853
|
config.hermes = readHermesConfig(resolveHermesHome(env));
|
|
57689
57854
|
config.dsh = readDshConfig(resolveDshHome(env));
|
|
57855
|
+
config.codebuddy = readCodebuddyConfig(resolveCodebuddyHome(env), cwd, env);
|
|
57856
|
+
config.qoder = readQoderConfig(resolveQoderHome(env), env);
|
|
57857
|
+
config.trae = readTraeConfig(env);
|
|
57690
57858
|
return config;
|
|
57691
57859
|
}
|
|
57692
57860
|
function collectModelWindows(config, scope) {
|
|
@@ -57701,12 +57869,14 @@ function collectModelWindows(config, scope) {
|
|
|
57701
57869
|
else if (scope === "pi") for (const p2 of Object.values(config.pi?.providers ?? {})) add(p2.models);
|
|
57702
57870
|
else if (scope === "omp") for (const p2 of Object.values(config.omp?.providers ?? {})) add(p2.models);
|
|
57703
57871
|
else if (scope === "opencode") for (const p2 of Object.values(config.opencode?.providers ?? {})) add(p2.models);
|
|
57872
|
+
else if (scope === "codebuddy") add(config.codebuddy?.models);
|
|
57704
57873
|
return out;
|
|
57705
57874
|
}
|
|
57706
57875
|
for (const p2 of Object.values(config.pi?.providers ?? {})) add(p2.models);
|
|
57707
57876
|
for (const p2 of Object.values(config.omp?.providers ?? {})) add(p2.models);
|
|
57708
57877
|
for (const p2 of Object.values(config.opencode?.providers ?? {})) add(p2.models);
|
|
57709
57878
|
add(config.codex?.modelWindows);
|
|
57879
|
+
add(config.codebuddy?.models);
|
|
57710
57880
|
return out;
|
|
57711
57881
|
}
|
|
57712
57882
|
|
|
@@ -57744,18 +57914,36 @@ function extractHttpsHosts(config) {
|
|
|
57744
57914
|
if (config.zcode) {
|
|
57745
57915
|
for (const prov of Object.values(config.zcode.providers)) push(prov.baseURL);
|
|
57746
57916
|
}
|
|
57917
|
+
if (config.codebuddy) {
|
|
57918
|
+
push(config.codebuddy.codebuddyBaseUrl);
|
|
57919
|
+
for (const u2 of config.codebuddy.modelUrls ?? []) push(u2);
|
|
57920
|
+
}
|
|
57921
|
+
if (config.qoder) {
|
|
57922
|
+
const hosts = nonEmpty2(config.qoder.modelServerHost) ? [config.qoder.modelServerHost] : QODER_DEFAULT_MODEL_HOSTS;
|
|
57923
|
+
for (const h of hosts) push(`https://${h}`);
|
|
57924
|
+
}
|
|
57925
|
+
if (config.trae) {
|
|
57926
|
+
const hosts = nonEmpty2(config.trae.modelApiHost) ? [config.trae.modelApiHost] : TRAE_DEFAULT_MODEL_HOSTS;
|
|
57927
|
+
for (const h of hosts) push(`https://${h}`);
|
|
57928
|
+
}
|
|
57747
57929
|
return out;
|
|
57748
57930
|
}
|
|
57749
57931
|
function configFilePaths(env) {
|
|
57750
57932
|
const home = os2.homedir();
|
|
57751
57933
|
const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path11.join(home, ".codex");
|
|
57752
57934
|
const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path11.join(home, ".zcode");
|
|
57935
|
+
const codebuddyHome = resolveCodebuddyHome(env);
|
|
57753
57936
|
return [
|
|
57754
57937
|
path11.join(home, ".claude", "settings.json"),
|
|
57755
57938
|
path11.join(process.cwd(), ".claude", "settings.json"),
|
|
57756
57939
|
path11.join(codexHome, "config.toml"),
|
|
57757
57940
|
path11.join(resolvePiHome(env), "models.json"),
|
|
57758
|
-
path11.join(zcodeHome, "v2", "config.json")
|
|
57941
|
+
path11.join(zcodeHome, "v2", "config.json"),
|
|
57942
|
+
path11.join(codebuddyHome, "settings.json"),
|
|
57943
|
+
path11.join(codebuddyHome, "models.json"),
|
|
57944
|
+
path11.join(process.cwd(), ".codebuddy", "models.json"),
|
|
57945
|
+
path11.join(resolveQoderHome(env), "settings.json"),
|
|
57946
|
+
path11.join(resolveTraeHome(env), "traecli.yaml")
|
|
57759
57947
|
];
|
|
57760
57948
|
}
|
|
57761
57949
|
function readMtimes(paths) {
|
|
@@ -58801,7 +58989,7 @@ function logUnrecognizedPath(log2, url) {
|
|
|
58801
58989
|
const n = (unrecognizedPathCounts.get(key) ?? 0) + 1;
|
|
58802
58990
|
unrecognizedPathCounts.set(key, n);
|
|
58803
58991
|
if (n <= 3) {
|
|
58804
|
-
log2("warn", `unrecognized path ${key} \u2014 not a known protocol (/chat/completions, /v1/messages, /responses, /responses/compact); forwarding unchanged`);
|
|
58992
|
+
log2("warn", `unrecognized path ${key} \u2014 not a known protocol (/chat/completions, /llm_raw_chat, /v1/messages, /responses, /responses/compact); forwarding unchanged`);
|
|
58805
58993
|
} else if (n === 4) {
|
|
58806
58994
|
log2("info", `unrecognized path ${key}: forwarding unchanged; further occurrences suppressed`);
|
|
58807
58995
|
}
|
|
@@ -59354,7 +59542,7 @@ async function handle(req, res, opts, core, config, log2, instanceId, instanceSt
|
|
|
59354
59542
|
}
|
|
59355
59543
|
}
|
|
59356
59544
|
upstreamOrigin = route ? route.upstream : /^https?:\/\//i.test(url) ? new URL(url).origin : opts.upstream;
|
|
59357
|
-
protocol = route?.explicitProtocol ?? (req.method === "POST" && bodyBuffer.length > 0 ? urlPath.endsWith("/chat/completions") ? "openai" : urlPath.endsWith("/v1/messages") || urlPath.endsWith("/messages") ? "anthropic" : urlPath.endsWith("/responses") || responsesCompact ? "responses" : null : null);
|
|
59545
|
+
protocol = route?.explicitProtocol ?? (req.method === "POST" && bodyBuffer.length > 0 ? urlPath.endsWith("/chat/completions") || urlPath.endsWith("/llm_raw_chat") ? "openai" : urlPath.endsWith("/v1/messages") || urlPath.endsWith("/messages") ? "anthropic" : urlPath.endsWith("/responses") || responsesCompact ? "responses" : null : null);
|
|
59358
59546
|
if (protocol !== null && bodyBuffer.length > 0) {
|
|
59359
59547
|
try {
|
|
59360
59548
|
const decoded = await decodeRequestBody(headerValue2(req, "content-encoding"), bodyBuffer, MAX_REQUEST_BYTES);
|
|
@@ -60436,7 +60624,7 @@ function logUpstreamProxyDecision(opts, upstreamUrl, decision) {
|
|
|
60436
60624
|
}
|
|
60437
60625
|
function inferWireProtocol(path18) {
|
|
60438
60626
|
const p2 = path18.split("?", 2)[0];
|
|
60439
|
-
if (p2.endsWith("/chat/completions")) return "openai";
|
|
60627
|
+
if (p2.endsWith("/chat/completions") || p2.endsWith("/llm_raw_chat")) return "openai";
|
|
60440
60628
|
if (p2.endsWith("/responses") || p2.endsWith("/responses/compact")) return "responses";
|
|
60441
60629
|
return null;
|
|
60442
60630
|
}
|
|
@@ -65383,7 +65571,7 @@ function selfDistFile(name) {
|
|
|
65383
65571
|
return path15.join(selfPackageRoot(), "dist", name);
|
|
65384
65572
|
}
|
|
65385
65573
|
var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
|
|
65386
|
-
var LAUNCH_CLIENTS = ["pi", "codex", "claude", "omp", "opencode", "hermes", "dsh", "pi-test"];
|
|
65574
|
+
var LAUNCH_CLIENTS = ["pi", "codex", "claude", "omp", "opencode", "hermes", "dsh", "codebuddy", "qoder", "trae", "pi-test"];
|
|
65387
65575
|
var HEALTH_PATH = "/__bili/health";
|
|
65388
65576
|
var HEALTH_POLL_INTERVAL_MS = 200;
|
|
65389
65577
|
var SPAWN_WAIT_MS = 2e4;
|
|
@@ -65471,6 +65659,29 @@ function discoverRoutes(client, config) {
|
|
|
65471
65659
|
}
|
|
65472
65660
|
} catch {
|
|
65473
65661
|
}
|
|
65662
|
+
} else if (client === "codebuddy") {
|
|
65663
|
+
const raw = nonEmpty2(config.codebuddy?.codebuddyBaseUrl) ? config.codebuddy.codebuddyBaseUrl : "https://tencent.sso.codebuddy.cn/v2";
|
|
65664
|
+
const real = unwrapUpstream2(raw);
|
|
65665
|
+
try {
|
|
65666
|
+
const url = new URL(real);
|
|
65667
|
+
if ((url.protocol === "https:" || url.protocol === "http:") && !rewriteKeys.has("CODEBUDDY_BASE_URL")) {
|
|
65668
|
+
rewriteKeys.add("CODEBUDDY_BASE_URL");
|
|
65669
|
+
httpRewrites.push({ key: "CODEBUDDY_BASE_URL", realUpstream: real });
|
|
65670
|
+
}
|
|
65671
|
+
} catch {
|
|
65672
|
+
}
|
|
65673
|
+
for (const rawModelUrl of config.codebuddy?.modelUrls ?? []) {
|
|
65674
|
+
try {
|
|
65675
|
+
const url = new URL(unwrapUpstream2(rawModelUrl));
|
|
65676
|
+
if (url.protocol !== "https:") continue;
|
|
65677
|
+
const host = url.hostname;
|
|
65678
|
+
if (host && !httpsSeen.has(host.toLowerCase())) {
|
|
65679
|
+
httpsSeen.add(host.toLowerCase());
|
|
65680
|
+
httpsDomains.push(host);
|
|
65681
|
+
}
|
|
65682
|
+
} catch {
|
|
65683
|
+
}
|
|
65684
|
+
}
|
|
65474
65685
|
} else if (client === "pi") {
|
|
65475
65686
|
for (const [name, prov] of Object.entries(config.pi?.providers ?? {})) {
|
|
65476
65687
|
classify(prov.baseUrl, name);
|
|
@@ -65532,6 +65743,24 @@ function discoverRoutes(client, config) {
|
|
|
65532
65743
|
} catch {
|
|
65533
65744
|
}
|
|
65534
65745
|
}
|
|
65746
|
+
} else if (client === "qoder") {
|
|
65747
|
+
const hosts = nonEmpty2(config.qoder?.modelServerHost) ? [config.qoder.modelServerHost] : QODER_DEFAULT_MODEL_HOSTS;
|
|
65748
|
+
for (const host of hosts) {
|
|
65749
|
+
const h = host.toLowerCase();
|
|
65750
|
+
if (h && !httpsSeen.has(h)) {
|
|
65751
|
+
httpsSeen.add(h);
|
|
65752
|
+
httpsDomains.push(h);
|
|
65753
|
+
}
|
|
65754
|
+
}
|
|
65755
|
+
} else if (client === "trae") {
|
|
65756
|
+
const hosts = nonEmpty2(config.trae?.modelApiHost) ? [config.trae.modelApiHost] : TRAE_DEFAULT_MODEL_HOSTS;
|
|
65757
|
+
for (const h of hosts) {
|
|
65758
|
+
const host = h.split(":", 2)[0].toLowerCase();
|
|
65759
|
+
if (host && !httpsSeen.has(host)) {
|
|
65760
|
+
httpsSeen.add(host);
|
|
65761
|
+
httpsDomains.push(host);
|
|
65762
|
+
}
|
|
65763
|
+
}
|
|
65535
65764
|
} else {
|
|
65536
65765
|
for (const [name, prov] of Object.entries(config.codex?.providers ?? {})) {
|
|
65537
65766
|
classify(prov.baseUrl, `model_providers.${name}.base_url`);
|
|
@@ -65564,6 +65793,9 @@ function buildPiEnv(origin, caPath, baseEnv, httpRewrites = [], httpsRewrites =
|
|
|
65564
65793
|
function buildCodexEnv(origin, caPath, baseEnv) {
|
|
65565
65794
|
return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath, BILLION_CONTEXT_PROXY: origin };
|
|
65566
65795
|
}
|
|
65796
|
+
function buildTraeEnv(origin, caPath, baseEnv) {
|
|
65797
|
+
return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath, BILLION_CONTEXT_PROXY: origin };
|
|
65798
|
+
}
|
|
65567
65799
|
function buildCodexArgs(origin, httpRewrites, httpsRewrites, extra) {
|
|
65568
65800
|
const args = [];
|
|
65569
65801
|
for (const r of httpRewrites) {
|
|
@@ -65614,6 +65846,31 @@ function buildClaudeEnv(origin, caPath, httpRewrites, httpsRewrites, baseEnv) {
|
|
|
65614
65846
|
if (hr2) env.ANTHROPIC_BASE_URL = hr2.realUpstream;
|
|
65615
65847
|
return env;
|
|
65616
65848
|
}
|
|
65849
|
+
async function resolveCodebuddyBudgetEnv(opts) {
|
|
65850
|
+
const { model, userAutoCompactWindow, shellAutoCompactWindow, routes, upstreamUrl } = opts;
|
|
65851
|
+
if (!model || userAutoCompactWindow !== void 0 || nonEmpty2(shellAutoCompactWindow)) return {};
|
|
65852
|
+
const window2 = await resolveLauncherWindow(model, routes, upstreamUrl);
|
|
65853
|
+
if (!window2) return {};
|
|
65854
|
+
return { CODEBUDDY_AUTO_COMPACT_WINDOW: String(window2) };
|
|
65855
|
+
}
|
|
65856
|
+
function buildCodebuddyEnv(origin, caPath, httpRewrites, httpsRewrites, baseEnv) {
|
|
65857
|
+
const env = { ...baseEnv, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: caPath, BILLION_CONTEXT_PROXY: origin };
|
|
65858
|
+
const r = httpRewrites.find((rw) => rw.key === "CODEBUDDY_BASE_URL");
|
|
65859
|
+
if (r) env.CODEBUDDY_BASE_URL = wrapUpstream(origin, r.realUpstream);
|
|
65860
|
+
const hr2 = httpsRewrites.find((rw) => rw.key === "CODEBUDDY_BASE_URL");
|
|
65861
|
+
if (hr2) env.CODEBUDDY_BASE_URL = hr2.realUpstream;
|
|
65862
|
+
return env;
|
|
65863
|
+
}
|
|
65864
|
+
function buildQoderEnv(origin, caPath, baseEnv) {
|
|
65865
|
+
return { ...baseEnv, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: caPath, BILLION_CONTEXT_PROXY: origin };
|
|
65866
|
+
}
|
|
65867
|
+
async function resolveQoderBudgetEnv(opts) {
|
|
65868
|
+
const { model, userAutoCompactWindow, windowKey, routes, upstreamUrl } = opts;
|
|
65869
|
+
if (!model || nonEmpty2(userAutoCompactWindow)) return {};
|
|
65870
|
+
const window2 = await resolveLauncherWindow(model, routes, upstreamUrl);
|
|
65871
|
+
if (!window2) return {};
|
|
65872
|
+
return { [windowKey]: String(window2) };
|
|
65873
|
+
}
|
|
65617
65874
|
function launcherDirectUrl(env) {
|
|
65618
65875
|
return env.BILI_LAUNCHER_DIRECT === "1";
|
|
65619
65876
|
}
|
|
@@ -65654,7 +65911,7 @@ function isPrivateIPv4(host) {
|
|
|
65654
65911
|
return false;
|
|
65655
65912
|
}
|
|
65656
65913
|
function launcherInjectMcp(env, base, codexUpstream) {
|
|
65657
|
-
if (base === "pi" || base === "omp" || base === "opencode" || base === "hermes" || base === "dsh") return false;
|
|
65914
|
+
if (base === "pi" || base === "omp" || base === "opencode" || base === "hermes" || base === "dsh" || base === "codebuddy" || base === "qoder" || base === "trae") return false;
|
|
65658
65915
|
if (env.BILI_LAUNCHER_PLUGIN === "0") return false;
|
|
65659
65916
|
if (base === "codex" && env.BILI_LAUNCHER_PLUGIN === void 0 && codexUpstream !== void 0 && isPrivateUpstreamHost(codexUpstream)) {
|
|
65660
65917
|
return false;
|
|
@@ -66477,6 +66734,18 @@ function resolveClientCommand(client, env) {
|
|
|
66477
66734
|
);
|
|
66478
66735
|
return { command: process.execPath, prefixArgs: [cli] };
|
|
66479
66736
|
}
|
|
66737
|
+
if (client === "codebuddy") {
|
|
66738
|
+
const resolved2 = resolveOnPath("codebuddy", env) ?? resolveOnPath("cbc", env);
|
|
66739
|
+
return { command: resolved2 ?? "codebuddy", prefixArgs: [] };
|
|
66740
|
+
}
|
|
66741
|
+
if (client === "qoder") {
|
|
66742
|
+
const resolved2 = resolveOnPath("qoder", env) ?? resolveOnPath("qodercli", env);
|
|
66743
|
+
return { command: resolved2 ?? "qoder", prefixArgs: [] };
|
|
66744
|
+
}
|
|
66745
|
+
if (client === "trae") {
|
|
66746
|
+
const traeBin = resolveOnPath("traecli", env) ?? resolveOnPath("trae-cli", env) ?? resolveOnPath("trae", env);
|
|
66747
|
+
return { command: traeBin ?? "traecli", prefixArgs: [] };
|
|
66748
|
+
}
|
|
66480
66749
|
const resolved = resolveOnPath(client, env);
|
|
66481
66750
|
return { command: resolved ?? client, prefixArgs: [] };
|
|
66482
66751
|
}
|
|
@@ -66543,6 +66812,10 @@ async function runLaunch(params, deps = {}) {
|
|
|
66543
66812
|
console.error(
|
|
66544
66813
|
"bili: direct-URL mode \u2014 claude's ANTHROPIC_BASE_URL is overridden to the proxy; a pre-configured relay is bypassed unless BILI_CLAUDE_UPSTREAM=<relay> is set. OAuth-subscription traffic requires the default MITM mode."
|
|
66545
66814
|
);
|
|
66815
|
+
} else if (base === "qoder") {
|
|
66816
|
+
console.error(
|
|
66817
|
+
"bili: BILI_LAUNCHER_DIRECT has no effect for qoder \u2014 its model endpoint scheme is hardcoded https with no base-URL override env, so qoder always runs in cert-MITM mode."
|
|
66818
|
+
);
|
|
66546
66819
|
}
|
|
66547
66820
|
}
|
|
66548
66821
|
const codexUpstream = base === "codex" ? codexUpstreamUrl(config.codex) : void 0;
|
|
@@ -66612,6 +66885,23 @@ async function runLaunch(params, deps = {}) {
|
|
|
66612
66885
|
}
|
|
66613
66886
|
const dshAcpPatch = writeDshAcpPatch(dshHomeDir);
|
|
66614
66887
|
if (dshAcpPatch) clientArgs = dshArgsWithPatch(clientArgs, dshAcpPatch);
|
|
66888
|
+
} else if (base === "qoder") {
|
|
66889
|
+
env = buildQoderEnv(origin, ca, stripInheritedProxy(process.env));
|
|
66890
|
+
const qoderPrefix = qoderIsCnSite(process.env) ? "QODERCN" : "QODER";
|
|
66891
|
+
env[`${qoderPrefix}_MODEL_TRANSPORT`] = "http";
|
|
66892
|
+
const qoderBudget = await resolveQoderBudgetEnv({
|
|
66893
|
+
model: nonEmpty2(process.env[`${qoderPrefix}_MODEL`]) ? process.env[`${qoderPrefix}_MODEL`] : config.qoder?.model,
|
|
66894
|
+
userAutoCompactWindow: process.env[`${qoderPrefix}_AUTOCOMPACT_WINDOW`],
|
|
66895
|
+
windowKey: `${qoderPrefix}_AUTOCOMPACT_WINDOW`,
|
|
66896
|
+
routes: biliRoutes,
|
|
66897
|
+
upstreamUrl: `https://${config.qoder?.modelServerHost ?? QODER_DEFAULT_MODEL_HOSTS[0]}`
|
|
66898
|
+
});
|
|
66899
|
+
Object.assign(env, qoderBudget);
|
|
66900
|
+
if (qoderBudget[`${qoderPrefix}_AUTOCOMPACT_WINDOW`] !== void 0) {
|
|
66901
|
+
console.error(`bili: qoder budget aligned \u2014 ${qoderPrefix}_AUTOCOMPACT_WINDOW=${qoderBudget[`${qoderPrefix}_AUTOCOMPACT_WINDOW`]}`);
|
|
66902
|
+
}
|
|
66903
|
+
} else if (base === "trae") {
|
|
66904
|
+
env = buildTraeEnv(origin, resolveCombinedCaPath(process.env), stripInheritedProxy(process.env));
|
|
66615
66905
|
} else if (base === "codex") {
|
|
66616
66906
|
const codexConversationId = injectMcp ? randomUUID5() : void 0;
|
|
66617
66907
|
if (directUrl) {
|
|
@@ -66642,6 +66932,19 @@ async function runLaunch(params, deps = {}) {
|
|
|
66642
66932
|
Object.assign(env, inj.envPatch);
|
|
66643
66933
|
if (inj.warning) console.error(`bili: ${inj.warning}`);
|
|
66644
66934
|
}
|
|
66935
|
+
} else if (base === "codebuddy") {
|
|
66936
|
+
env = buildCodebuddyEnv(origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);
|
|
66937
|
+
const codebuddyBudget = await resolveCodebuddyBudgetEnv({
|
|
66938
|
+
model: config.codebuddy?.model,
|
|
66939
|
+
userAutoCompactWindow: config.codebuddy?.autoCompactWindow,
|
|
66940
|
+
shellAutoCompactWindow: process.env.CODEBUDDY_AUTO_COMPACT_WINDOW,
|
|
66941
|
+
routes: biliRoutes,
|
|
66942
|
+
upstreamUrl: config.codebuddy?.codebuddyBaseUrl ?? "https://tencent.sso.codebuddy.cn/v2"
|
|
66943
|
+
});
|
|
66944
|
+
Object.assign(env, codebuddyBudget);
|
|
66945
|
+
if (codebuddyBudget.CODEBUDDY_AUTO_COMPACT_WINDOW !== void 0) {
|
|
66946
|
+
console.error(`bili: codebuddy budget aligned \u2014 CODEBUDDY_AUTO_COMPACT_WINDOW=${codebuddyBudget.CODEBUDDY_AUTO_COMPACT_WINDOW}`);
|
|
66947
|
+
}
|
|
66645
66948
|
} else {
|
|
66646
66949
|
env = directUrl ? buildClaudePluginEnv(origin, true, process.env) : buildClaudeEnv(origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);
|
|
66647
66950
|
if (directUrl) env.BILLION_CONTEXT_PROXY = origin;
|
|
@@ -66896,6 +67199,9 @@ Usage:
|
|
|
66896
67199
|
bili opencode [opts --] [args] start a proxy + launch opencode against it (cert-MITM)
|
|
66897
67200
|
bili hermes [opts --] [args] start a proxy + launch hermes-agent against it (/bili/ rewrite)
|
|
66898
67201
|
bili dsh [opts --] [args] start a proxy + launch deepseek-harness against it (/bili/ rewrite)
|
|
67202
|
+
bili codebuddy [opts --] [args] start a proxy + launch codebuddy against it (/bili/ rewrite)
|
|
67203
|
+
bili qoder [opts --] [args] start a proxy + launch qoder against it (cert-MITM)
|
|
67204
|
+
bili trae [opts --] [args] start a proxy + launch Trae CLI against it (cert-MITM)
|
|
66899
67205
|
bili test pi non-polluting pi smoke test through the proxy
|
|
66900
67206
|
bili export [session] [--full] list sessions / export one as a Markdown handoff
|
|
66901
67207
|
(--full includes original messages; --output FILE)
|
|
@@ -66910,12 +67216,12 @@ Usage:
|
|
|
66910
67216
|
bili --version print version
|
|
66911
67217
|
bili --help show this help
|
|
66912
67218
|
|
|
66913
|
-
Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili hermes / bili dsh):
|
|
67219
|
+
Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili hermes / bili dsh / bili codebuddy / bili qoder / bili trae):
|
|
66914
67220
|
Brings up a proxy on an independent port (a fresh instance every launch), then runs the client pointed at it via HTTPS_PROXY + the proxy's
|
|
66915
67221
|
MITM CA \u2014 no config-file edits. Discovered HTTPS upstream domains are
|
|
66916
67222
|
auto-whitelisted for MITM so the proxy TLS-terminates exactly the hosts the
|
|
66917
|
-
client uses; HTTP / localhost providers go direct. pi/claude trust the CA
|
|
66918
|
-
via NODE_EXTRA_CA_CERTS, codex via SSL_CERT_FILE. Proxy killed on client exit.
|
|
67223
|
+
client uses; HTTP / localhost providers go direct. pi/claude/qoder trust the CA
|
|
67224
|
+
via NODE_EXTRA_CA_CERTS, codex/trae via SSL_CERT_FILE. Proxy killed on client exit.
|
|
66919
67225
|
bili flags (-F, --mitm-domain, --port, ...) must precede the client name;
|
|
66920
67226
|
everything after the client name is passed through to the client.
|
|
66921
67227
|
bili pi # launch pi through the proxy
|
|
@@ -66926,6 +67232,9 @@ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili h
|
|
|
66926
67232
|
bili omp # launch omp through the proxy (pi-based; /bili/ rewrite)
|
|
66927
67233
|
bili hermes # launch hermes-agent through the proxy (/bili/ rewrite of ~/.hermes/config.yaml)
|
|
66928
67234
|
bili dsh --profile web "task" # launch deepseek-harness through the proxy (/bili/ rewrite of ~/.dsh/settings.yaml)
|
|
67235
|
+
bili codebuddy # launch codebuddy through the proxy (CODEBUDDY_BASE_URL /bili/ rewrite)
|
|
67236
|
+
bili qoder # launch qoder through the proxy (cert-MITM; model endpoint is hardcoded https, so no /bili/ rewrite)
|
|
67237
|
+
bili trae # launch Trae CLI through the proxy (cert-MITM; model host via TRAE_CLI_API_HOST or --mitm-domain)
|
|
66929
67238
|
bili test pi # quick end-to-end check of the pi path
|
|
66930
67239
|
bili --mitm-domain api.foo.com pi # add a domain to the MITM whitelist (flags precede the client)
|
|
66931
67240
|
bili -F http://127.0.0.1:7897 codex # route bili's upstream through a proxy (gost-style -F)
|