billion-context 0.1.97-pr.667.487 → 0.1.97-pr.669.486

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
@@ -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 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,7 @@ 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 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
181
  bili pi --mitm-domain api.foo.com # add a domain to the MITM whitelist
181
182
  ```
182
183
 
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 trae`)
88
88
 
89
89
  启动器把客户端包进一条命令:在独立端口拉起一个代理(总是全新实例,绝不复用端口),再按客户端支持的机制把它指向代理 —— 能吃代理/CA 环境变量的走**证书 MITM**,不吃的走隔离的**`/bili/` 配置重写**。真实配置文件从不被修改;客户端自己的配置只被**读取**,用来发现它实际连接的 HTTPS 上游主机,把这些主机加入 MITM 白名单 —— 代理只 TLS 终结它们,其余流量盲透传。
90
90
 
@@ -96,6 +96,7 @@ 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 trae # Trae CLI(字节跳动,闭源 Go 二进制,无 base-URL 覆盖)—— 证书 MITM(HTTPS_PROXY + SSL_CERT_FILE),模型主机取 TRAE_CLI_API_HOST 或默认企业网关(#655)
99
100
  bili pi --mitm-domain api.foo.com # 向 MITM 白名单追加域名
100
101
  ```
101
102
 
package/dist/index.js CHANGED
@@ -48726,7 +48726,6 @@ function mergeCompress(global2, provider, model) {
48726
48726
  const promptLevels = [global2?.prompts, provider?.prompts, model?.prompts].filter(Boolean);
48727
48727
  const rangeOf = (s3) => s3?.minCompressRangeChars ?? s3?.minCompressRange;
48728
48728
  const absorbLevels = [global2?.absorb, provider?.absorb, model?.absorb].filter(Boolean);
48729
- const reasoningLevels = [global2?.reasoning, provider?.reasoning, model?.reasoning].filter(Boolean);
48730
48729
  return {
48731
48730
  modelContextLimit: pick("modelContextLimit"),
48732
48731
  maxContextLimit: pick("maxContextLimit"),
@@ -48740,11 +48739,7 @@ function mergeCompress(global2, provider, model) {
48740
48739
  acknowledgePromptsRisk: pick("acknowledgePromptsRisk"),
48741
48740
  absorb: absorbLevels.length > 0 ? Object.assign({}, ...absorbLevels) : void 0,
48742
48741
  stripImages: pick("stripImages"),
48743
- stripImagesKeepRecent: pick("stripImagesKeepRecent"),
48744
- // `reasoning` is a third nested-object field merged sub-field-wise
48745
- // exactly like `absorb`/`prompts`: a model-level `threshold` must not
48746
- // discard a provider-level `drop: false`.
48747
- reasoning: reasoningLevels.length > 0 ? Object.assign({}, ...reasoningLevels) : void 0
48742
+ stripImagesKeepRecent: pick("stripImagesKeepRecent")
48748
48743
  };
48749
48744
  }
48750
48745
  function resolveCompress(routes, upstreamUrl, model, global2) {
@@ -48824,53 +48819,6 @@ function resolveRequestConfig(base, routes, embeddedUrl, model, native, globalCo
48824
48819
  return applyCompressSettings(base, limit, compress);
48825
48820
  }
48826
48821
 
48827
- // src/reasoning-drop.ts
48828
- var DEFAULT_COMPRESS_REASONING = { drop: true, threshold: 2048 };
48829
- function resolveReasoningDrop(cfg) {
48830
- let threshold = DEFAULT_COMPRESS_REASONING.threshold;
48831
- if (cfg?.threshold !== void 0) {
48832
- const t = cfg.threshold;
48833
- if (typeof t === "number" && Number.isFinite(t) && t >= 0) {
48834
- threshold = Math.floor(t);
48835
- }
48836
- }
48837
- return { drop: cfg?.drop !== false, threshold };
48838
- }
48839
- function dropCompressReasoning(messages, cfg) {
48840
- const { drop, threshold } = resolveReasoningDrop(cfg);
48841
- if (!drop || messages.length === 0) return messages;
48842
- try {
48843
- const last = messages.length - 1;
48844
- const resultAt = /* @__PURE__ */ new Map();
48845
- for (let i = 0; i <= last; i++) {
48846
- const m2 = messages[i];
48847
- if (m2.contentType === "tool-result" && typeof m2.toolCallId === "string" && !resultAt.has(m2.toolCallId)) {
48848
- resultAt.set(m2.toolCallId, i);
48849
- }
48850
- }
48851
- const dropIdx = /* @__PURE__ */ new Set();
48852
- for (let i = 0; i <= last; i++) {
48853
- const m2 = messages[i];
48854
- if (m2.contentType !== "tool-call" || m2.toolName !== "compress") continue;
48855
- const ri2 = typeof m2.toolCallId === "string" ? resultAt.get(m2.toolCallId) : void 0;
48856
- if (ri2 === void 0 || ri2 <= i || ri2 >= last) continue;
48857
- let total = 0;
48858
- let j2 = i - 1;
48859
- while (j2 >= 0 && messages[j2].contentType === "reasoning") {
48860
- total += (messages[j2].text ?? "").length;
48861
- j2--;
48862
- }
48863
- if (total > threshold) {
48864
- for (let k2 = j2 + 1; k2 < i; k2++) dropIdx.add(k2);
48865
- }
48866
- }
48867
- if (dropIdx.size === 0) return messages;
48868
- return messages.filter((_2, idx) => !dropIdx.has(idx));
48869
- } catch {
48870
- return messages;
48871
- }
48872
- }
48873
-
48874
48822
  // src/strip-images.ts
48875
48823
  var DEFAULT_STRIP_IMAGES_KEEP_RECENT = 5;
48876
48824
  var IMAGE_PLACEHOLDER = "[image]";
@@ -56969,6 +56917,20 @@ function readDshConfig(dshHome) {
56969
56917
  }
56970
56918
  return { baseUrls: parseDshSettingsYaml(text) };
56971
56919
  }
56920
+ var TRAE_DEFAULT_MODEL_HOSTS = [
56921
+ "console.enterprise.trae.cn",
56922
+ "www.trae.cn"
56923
+ ];
56924
+ function resolveTraeHome(env) {
56925
+ const h = os.homedir();
56926
+ return nonEmpty2(env.TRAE_CONFIG_DIR) ? env.TRAE_CONFIG_DIR : path10.join(h, ".trae");
56927
+ }
56928
+ function readTraeConfig(env) {
56929
+ const result = {};
56930
+ const host = nonEmpty2(env.TRAE_CLI_API_HOST) ? env.TRAE_CLI_API_HOST.replace(/^https?:\/\//i, "").replace(/\/+$/, "") : void 0;
56931
+ if (host) result.modelApiHost = host;
56932
+ return result;
56933
+ }
56972
56934
  function readClaudeSettings(homeDir, cwd, env = process.env) {
56973
56935
  const files = [
56974
56936
  path10.join(homeDir, ".claude", "settings.json"),
@@ -57319,6 +57281,7 @@ function loadClientConfig(env, cwd) {
57319
57281
  config.opencode = readOpencodeConfig(resolveOpencodeConfigFile(env));
57320
57282
  config.hermes = readHermesConfig(resolveHermesHome(env));
57321
57283
  config.dsh = readDshConfig(resolveDshHome(env));
57284
+ config.trae = readTraeConfig(env);
57322
57285
  return config;
57323
57286
  }
57324
57287
  function collectModelWindows(config, scope) {
@@ -57376,6 +57339,10 @@ function extractHttpsHosts(config) {
57376
57339
  if (config.zcode) {
57377
57340
  for (const prov of Object.values(config.zcode.providers)) push(prov.baseURL);
57378
57341
  }
57342
+ if (config.trae) {
57343
+ const hosts = nonEmpty2(config.trae.modelApiHost) ? [config.trae.modelApiHost] : TRAE_DEFAULT_MODEL_HOSTS;
57344
+ for (const h of hosts) push(`https://${h}`);
57345
+ }
57379
57346
  return out;
57380
57347
  }
57381
57348
  function configFilePaths(env) {
@@ -57387,7 +57354,8 @@ function configFilePaths(env) {
57387
57354
  path11.join(process.cwd(), ".claude", "settings.json"),
57388
57355
  path11.join(codexHome, "config.toml"),
57389
57356
  path11.join(resolvePiHome(env), "models.json"),
57390
- path11.join(zcodeHome, "v2", "config.json")
57357
+ path11.join(zcodeHome, "v2", "config.json"),
57358
+ path11.join(resolveTraeHome(env), "traecli.yaml")
57391
57359
  ];
57392
57360
  }
57393
57361
  function readMtimes(paths) {
@@ -58433,7 +58401,7 @@ function logUnrecognizedPath(log2, url) {
58433
58401
  const n = (unrecognizedPathCounts.get(key) ?? 0) + 1;
58434
58402
  unrecognizedPathCounts.set(key, n);
58435
58403
  if (n <= 3) {
58436
- log2("warn", `unrecognized path ${key} \u2014 not a known protocol (/chat/completions, /v1/messages, /responses, /responses/compact); forwarding unchanged`);
58404
+ log2("warn", `unrecognized path ${key} \u2014 not a known protocol (/chat/completions, /llm_raw_chat, /v1/messages, /responses, /responses/compact); forwarding unchanged`);
58437
58405
  } else if (n === 4) {
58438
58406
  log2("info", `unrecognized path ${key}: forwarding unchanged; further occurrences suppressed`);
58439
58407
  }
@@ -58985,7 +58953,7 @@ async function handle(req, res, opts, core, config, log2, instanceId, instanceSt
58985
58953
  }
58986
58954
  }
58987
58955
  upstreamOrigin = route ? route.upstream : /^https?:\/\//i.test(url) ? new URL(url).origin : opts.upstream;
58988
- 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);
58956
+ 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);
58989
58957
  if (protocol !== null && bodyBuffer.length > 0) {
58990
58958
  try {
58991
58959
  const decoded = await decodeRequestBody(headerValue2(req, "content-encoding"), bodyBuffer, MAX_REQUEST_BYTES);
@@ -59266,14 +59234,13 @@ ${bodyBuffer.toString("utf8")}`);
59266
59234
  await withSessionLock(session, async () => {
59267
59235
  const runPrepare = () => {
59268
59236
  const cs2 = resolveCompress(opts.routes, route?.rewrittenUrl, parsed.model, opts.compress);
59269
- const reasoningCfg = cs2.reasoning;
59270
59237
  const keepRecent = cs2.stripImagesKeepRecent ?? DEFAULT_STRIP_IMAGES_KEEP_RECENT;
59271
59238
  const stripped = cs2.stripImages ? stripHistoricalImages(parsed, protocol, keepRecent) : { body: parsed, removed: 0 };
59272
59239
  if (opts.debug && stripped.removed > 0) {
59273
59240
  log2("info", `[debug] strip-images: dropped ${stripped.removed} historical image part(s), kept last ${keepRecent} (session=${session.id})`);
59274
59241
  }
59275
59242
  const work = stripped.body;
59276
- return countTokens ? prepareCountTokens(work, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, reasoningCfg) : protocol === "openai" ? prepareOpenai(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, nativeWindow, reasoningCfg) : responsesCompact ? prepareResponsesCompact(stripped.removed > 0 ? Buffer.from(JSON.stringify(work)) : bodyBuffer, work, session, req, core, reqConfig, log2) : prepareResponses(work, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin, nativeWindow, reasoningCfg);
59243
+ return countTokens ? prepareCountTokens(work, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(work, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, nativeWindow) : responsesCompact ? prepareResponsesCompact(stripped.removed > 0 ? Buffer.from(JSON.stringify(work)) : bodyBuffer, work, session, req, core, reqConfig, log2) : prepareResponses(work, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin, nativeWindow);
59277
59244
  };
59278
59245
  const isCodexCompactTrigger = protocol === "responses" && !responsesCompact && isCodexClient(req.headers) && hasCompactionTrigger(parsed.input);
59279
59246
  if (isCodexCompactTrigger) {
@@ -59361,13 +59328,6 @@ ${bodyBuffer.toString("utf8")}`);
59361
59328
  }
59362
59329
  }
59363
59330
  var ACP_TAG_MARK = "<acp ";
59364
- function withReasoningDrop(msgs, reasoning, log2, sessionId) {
59365
- const out = dropCompressReasoning(msgs, reasoning);
59366
- if (out.length !== msgs.length) {
59367
- log2("info", `[${sessionId}] compress-reasoning: dropped ${msgs.length - out.length} reasoning message(s) from closed compress turns (#651)`);
59368
- }
59369
- return out;
59370
- }
59371
59331
  function stripKernelSummaries(messages, state) {
59372
59332
  const carried = /* @__PURE__ */ new Set();
59373
59333
  for (const b2 of state.blocks) {
@@ -59469,13 +59429,12 @@ function effectiveTokenCount(session, msgs) {
59469
59429
  if (!session.metadata.anonymousPrefixAffinity) return 0;
59470
59430
  return estimateCoreMessagesUpper(msgs);
59471
59431
  }
59472
- function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode, reasoning) {
59432
+ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, session, pluginMode) {
59473
59433
  const sessionId = session.id;
59474
59434
  const stream2 = parsed.stream === true;
59475
59435
  ++session.stats.requests;
59476
59436
  session.hostCreditTokens = 0;
59477
59437
  const injectTools = opts.compress.injectTool && !pluginMode;
59478
- const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59479
59438
  if (isAutoModeClassifier(parsed)) {
59480
59439
  log2("info", `[${sessionId}] auto-mode classifier passthrough (skipping compress injection)`);
59481
59440
  return { body: JSON.stringify(parsed), session, processedMessages: [], originalMessages: [], anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: false, pluginMode, nudge: void 0, prompts };
@@ -59513,7 +59472,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
59513
59472
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59514
59473
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59515
59474
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59516
- processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59475
+ processedMessages = stripKernelSummaries(turn.messages, turn.state);
59517
59476
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59518
59477
  reapOrphanBlocks(session, msgs, deactivateBlock);
59519
59478
  rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
@@ -59595,13 +59554,12 @@ function clampOutgoingOutput(rebuilt, field, ctx, sessionId, log2) {
59595
59554
  log2("info", `[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`);
59596
59555
  }
59597
59556
  }
59598
- function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow, reasoning) {
59557
+ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow) {
59599
59558
  const sessionId = session.id;
59600
59559
  const stream2 = parsed.stream === true;
59601
59560
  ++session.stats.requests;
59602
59561
  session.hostCreditTokens = 0;
59603
59562
  let openaiSystemText = "";
59604
- const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59605
59563
  let openaiOutboundSystem;
59606
59564
  let processedMessages = [];
59607
59565
  let originalMessages = [];
@@ -59639,7 +59597,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59639
59597
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59640
59598
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59641
59599
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59642
- processedMessages = stripReasoning(stripKernelSummaries(turn.messages, turn.state));
59600
+ processedMessages = stripKernelSummaries(turn.messages, turn.state);
59643
59601
  applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
59644
59602
  reapOrphanBlocks(session, msgs, deactivateBlock);
59645
59603
  rebuiltMessages = systemToUser(coreToOpenai(processedMessages));
@@ -59679,12 +59637,11 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
59679
59637
  markDirty(session);
59680
59638
  return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, protocol: "openai", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, openaiSystemText, renderTags: "text-only" };
59681
59639
  }
59682
- function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow, reasoning) {
59640
+ function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow) {
59683
59641
  const sessionId = session.id;
59684
59642
  const stream2 = parsed.stream === true;
59685
59643
  ++session.stats.requests;
59686
59644
  session.hostCreditTokens = 0;
59687
- const stripReasoning = (msgs) => withReasoningDrop(msgs, reasoning, log2, sessionId);
59688
59645
  if (reconcileNativeCompactionBoundary(session)) {
59689
59646
  log2("info", `[${sessionId}] reconciled ACP state after native Responses compact boundary`);
59690
59647
  }
@@ -59749,7 +59706,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
59749
59706
  log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
59750
59707
  const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && !isCompactionTrigger && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
59751
59708
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
59752
- processedMessages = repairResponsesAssistantOrdering(stripReasoning(stripKernelSummaries(turn.messages, turn.state)), originalMessages);
59709
+ processedMessages = repairResponsesAssistantOrdering(stripKernelSummaries(turn.messages, turn.state), originalMessages);
59753
59710
  reapOrphanBlocks(session, msgs, deactivateBlock);
59754
59711
  rebuiltInput = patchResponsesInput(projection, processedMessages);
59755
59712
  const forgedSummaries = echoReplaced ? [] : session.metadata.codexForgedSummaries ?? [];
@@ -60007,7 +59964,7 @@ function logUpstreamProxyDecision(opts, upstreamUrl, decision) {
60007
59964
  }
60008
59965
  function inferWireProtocol(path18) {
60009
59966
  const p2 = path18.split("?", 2)[0];
60010
- if (p2.endsWith("/chat/completions")) return "openai";
59967
+ if (p2.endsWith("/chat/completions") || p2.endsWith("/llm_raw_chat")) return "openai";
60011
59968
  if (p2.endsWith("/responses") || p2.endsWith("/responses/compact")) return "responses";
60012
59969
  return null;
60013
59970
  }
@@ -64924,7 +64881,7 @@ function selfDistFile(name) {
64924
64881
  return path15.join(selfPackageRoot(), "dist", name);
64925
64882
  }
64926
64883
  var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
64927
- var LAUNCH_CLIENTS = ["pi", "codex", "claude", "omp", "opencode", "hermes", "dsh", "pi-test"];
64884
+ var LAUNCH_CLIENTS = ["pi", "codex", "claude", "omp", "opencode", "hermes", "dsh", "trae", "pi-test"];
64928
64885
  var HEALTH_PATH = "/__bili/health";
64929
64886
  var HEALTH_POLL_INTERVAL_MS = 200;
64930
64887
  var SPAWN_WAIT_MS = 2e4;
@@ -65073,6 +65030,15 @@ function discoverRoutes(client, config) {
65073
65030
  } catch {
65074
65031
  }
65075
65032
  }
65033
+ } else if (client === "trae") {
65034
+ const hosts = nonEmpty2(config.trae?.modelApiHost) ? [config.trae.modelApiHost] : TRAE_DEFAULT_MODEL_HOSTS;
65035
+ for (const h of hosts) {
65036
+ const host = h.toLowerCase();
65037
+ if (host && !httpsSeen.has(host)) {
65038
+ httpsSeen.add(host);
65039
+ httpsDomains.push(host);
65040
+ }
65041
+ }
65076
65042
  } else {
65077
65043
  for (const [name, prov] of Object.entries(config.codex?.providers ?? {})) {
65078
65044
  classify(prov.baseUrl, `model_providers.${name}.base_url`);
@@ -65105,6 +65071,9 @@ function buildPiEnv(origin, caPath, baseEnv, httpRewrites = [], httpsRewrites =
65105
65071
  function buildCodexEnv(origin, caPath, baseEnv) {
65106
65072
  return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath, BILLION_CONTEXT_PROXY: origin };
65107
65073
  }
65074
+ function buildTraeEnv(origin, caPath, baseEnv) {
65075
+ return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath, BILLION_CONTEXT_PROXY: origin };
65076
+ }
65108
65077
  function buildCodexArgs(origin, httpRewrites, httpsRewrites, extra) {
65109
65078
  const args = [];
65110
65079
  for (const r of httpRewrites) {
@@ -65195,7 +65164,7 @@ function isPrivateIPv4(host) {
65195
65164
  return false;
65196
65165
  }
65197
65166
  function launcherInjectMcp(env, base, codexUpstream) {
65198
- if (base === "pi" || base === "omp" || base === "opencode" || base === "hermes" || base === "dsh") return false;
65167
+ if (base === "pi" || base === "omp" || base === "opencode" || base === "hermes" || base === "dsh" || base === "trae") return false;
65199
65168
  if (env.BILI_LAUNCHER_PLUGIN === "0") return false;
65200
65169
  if (base === "codex" && env.BILI_LAUNCHER_PLUGIN === void 0 && codexUpstream !== void 0 && isPrivateUpstreamHost(codexUpstream)) {
65201
65170
  return false;
@@ -65950,6 +65919,10 @@ function resolveClientCommand(client, env) {
65950
65919
  );
65951
65920
  return { command: process.execPath, prefixArgs: [cli] };
65952
65921
  }
65922
+ if (client === "trae") {
65923
+ const traeBin = resolveOnPath("traecli", env) ?? resolveOnPath("trae-cli", env) ?? resolveOnPath("trae", env);
65924
+ return { command: traeBin ?? "traecli", prefixArgs: [] };
65925
+ }
65953
65926
  const resolved = resolveOnPath(client, env);
65954
65927
  return { command: resolved ?? client, prefixArgs: [] };
65955
65928
  }
@@ -66085,6 +66058,8 @@ async function runLaunch(params, deps = {}) {
66085
66058
  }
66086
66059
  const dshAcpPatch = writeDshAcpPatch(dshHomeDir);
66087
66060
  if (dshAcpPatch) clientArgs = dshArgsWithPatch(clientArgs, dshAcpPatch);
66061
+ } else if (base === "trae") {
66062
+ env = buildTraeEnv(origin, resolveCombinedCaPath(process.env), stripInheritedProxy(process.env));
66088
66063
  } else if (base === "codex") {
66089
66064
  const codexConversationId = injectMcp ? randomUUID5() : void 0;
66090
66065
  if (directUrl) {
@@ -66360,6 +66335,7 @@ Usage:
66360
66335
  bili opencode [opts --] [args] start a proxy + launch opencode against it (cert-MITM)
66361
66336
  bili hermes [opts --] [args] start a proxy + launch hermes-agent against it (/bili/ rewrite)
66362
66337
  bili dsh [opts --] [args] start a proxy + launch deepseek-harness against it (/bili/ rewrite)
66338
+ bili trae [opts --] [args] start a proxy + launch Trae CLI against it (cert-MITM)
66363
66339
  bili test pi non-polluting pi smoke test through the proxy
66364
66340
  bili export [session] [--full] list sessions / export one as a Markdown handoff
66365
66341
  (--full includes original messages; --output FILE)
@@ -66374,12 +66350,12 @@ Usage:
66374
66350
  bili --version print version
66375
66351
  bili --help show this help
66376
66352
 
66377
- Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili hermes / bili dsh):
66353
+ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili hermes / bili dsh / bili trae):
66378
66354
  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
66379
66355
  MITM CA \u2014 no config-file edits. Discovered HTTPS upstream domains are
66380
66356
  auto-whitelisted for MITM so the proxy TLS-terminates exactly the hosts the
66381
- client uses; HTTP / localhost providers go direct. pi/claude trust the CA
66382
- via NODE_EXTRA_CA_CERTS, codex via SSL_CERT_FILE. Proxy killed on client exit.
66357
+ client uses; HTTP / localhost providers go direct. pi/claude trust the CA
66358
+ via NODE_EXTRA_CA_CERTS, codex/trae via SSL_CERT_FILE. Proxy killed on client exit.
66383
66359
  bili flags (-F, --mitm-domain, --port, ...) must precede the client name;
66384
66360
  everything after the client name is passed through to the client.
66385
66361
  bili pi # launch pi through the proxy
@@ -66389,8 +66365,9 @@ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili h
66389
66365
  bili claude # launch claude through the proxy
66390
66366
  bili omp # launch omp through the proxy (pi-based; /bili/ rewrite)
66391
66367
  bili hermes # launch hermes-agent through the proxy (/bili/ rewrite of ~/.hermes/config.yaml)
66392
- bili dsh --profile web "task" # launch deepseek-harness through the proxy (/bili/ rewrite of ~/.dsh/settings.yaml)
66393
- bili test pi # quick end-to-end check of the pi path
66368
+ bili dsh --profile web "task" # launch deepseek-harness through the proxy (/bili/ rewrite of ~/.dsh/settings.yaml)
66369
+ bili trae # launch Trae CLI through the proxy (cert-MITM; model host via TRAE_CLI_API_HOST or --mitm-domain)
66370
+ bili test pi # quick end-to-end check of the pi path
66394
66371
  bili --mitm-domain api.foo.com pi # add a domain to the MITM whitelist (flags precede the client)
66395
66372
  bili -F http://127.0.0.1:7897 codex # route bili's upstream through a proxy (gost-style -F)
66396
66373