billion-context 0.1.63 → 0.1.64-pr.360.210
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/dist/agent/omp.js +9 -1
- package/dist/agent/omp.js.map +1 -1
- package/dist/agent/pi.js +9 -1
- package/dist/agent/pi.js.map +1 -1
- package/dist/index.js +265 -159
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47708,8 +47708,9 @@ function loadOptions(env = process.env) {
|
|
|
47708
47708
|
const webProxy = nonEmpty(fileConfig.upstreamProxy);
|
|
47709
47709
|
const configProxy = nonEmpty(fileConfig.proxy);
|
|
47710
47710
|
const rawProxyMode = env.BILI_UPSTREAM_PROXY_MODE ?? fileConfig.upstreamProxyMode ?? (webProxy ? "manual" : void 0);
|
|
47711
|
-
const
|
|
47712
|
-
const
|
|
47711
|
+
const effectiveMode = rawProxyMode ?? "direct";
|
|
47712
|
+
const proxyMode = parseUpstreamProxyMode(effectiveMode);
|
|
47713
|
+
const explicitDirect = proxyMode === "direct" && !biliProxy;
|
|
47713
47714
|
const proxy = biliProxy ?? (proxyMode === "direct" ? "" : proxyMode === "manual" ? webProxy ?? configProxy : configProxy);
|
|
47714
47715
|
const proxySource = biliProxy ? "bili-env" : proxyMode === "direct" ? "direct" : proxyMode === "manual" && webProxy ? "web-manual" : configProxy ? "config" : "auto";
|
|
47715
47716
|
const httpProxy = nonEmpty(env.HTTP_PROXY ?? env.http_proxy);
|
|
@@ -50625,6 +50626,153 @@ import { readFileSync as readFileSync3 } from "fs";
|
|
|
50625
50626
|
import { dirname as dirname4, join as join3 } from "path";
|
|
50626
50627
|
import { fileURLToPath } from "url";
|
|
50627
50628
|
|
|
50629
|
+
// src/web/page.ts
|
|
50630
|
+
import { existsSync as existsSync3 } from "fs";
|
|
50631
|
+
|
|
50632
|
+
// src/ca.ts
|
|
50633
|
+
var import_node_forge = __toESM(require_lib(), 1);
|
|
50634
|
+
import fs2 from "fs";
|
|
50635
|
+
import path6 from "path";
|
|
50636
|
+
import tls2 from "tls";
|
|
50637
|
+
var ROOT_CERT_FILE = "root-ca.pem";
|
|
50638
|
+
var ROOT_KEY_FILE = "root-ca-key.pem";
|
|
50639
|
+
var COMBINED_CA_FILE = "combined-ca.pem";
|
|
50640
|
+
var ROOT_CN = "billion-context MITM Root CA";
|
|
50641
|
+
var PLATFORM_CA_CANDIDATES = process.platform === "darwin" ? ["/etc/ssl/cert.pem", "/private/etc/ssl/cert.pem"] : [
|
|
50642
|
+
"/etc/ssl/certs/ca-certificates.crt",
|
|
50643
|
+
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
50644
|
+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
|
50645
|
+
"/etc/ssl/ca-bundle.pem",
|
|
50646
|
+
"/etc/ssl/cert.pem"
|
|
50647
|
+
];
|
|
50648
|
+
var rootCertPem;
|
|
50649
|
+
var rootKeyPem;
|
|
50650
|
+
var rootCert;
|
|
50651
|
+
var rootKey;
|
|
50652
|
+
var secureContextCache = /* @__PURE__ */ new Map();
|
|
50653
|
+
var SECURE_CONTEXT_CACHE_MAX = 64;
|
|
50654
|
+
function rootCaPath() {
|
|
50655
|
+
return path6.join(caDir(), ROOT_CERT_FILE);
|
|
50656
|
+
}
|
|
50657
|
+
function collectSystemCaPems(env = process.env) {
|
|
50658
|
+
const pems = [];
|
|
50659
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50660
|
+
const pushFile = (file) => {
|
|
50661
|
+
try {
|
|
50662
|
+
const text = fs2.readFileSync(file, "utf8");
|
|
50663
|
+
if (!text.includes("BEGIN CERTIFICATE") || seen.has(text)) return false;
|
|
50664
|
+
seen.add(text);
|
|
50665
|
+
pems.push(text);
|
|
50666
|
+
return true;
|
|
50667
|
+
} catch {
|
|
50668
|
+
}
|
|
50669
|
+
return false;
|
|
50670
|
+
};
|
|
50671
|
+
const userBundle = env.SSL_CERT_FILE?.trim();
|
|
50672
|
+
if (userBundle && pushFile(userBundle)) return pems;
|
|
50673
|
+
for (const candidate of PLATFORM_CA_CANDIDATES) {
|
|
50674
|
+
if (pushFile(candidate)) break;
|
|
50675
|
+
}
|
|
50676
|
+
return pems;
|
|
50677
|
+
}
|
|
50678
|
+
function writeCombinedBundle() {
|
|
50679
|
+
const certs = /* @__PURE__ */ new Set();
|
|
50680
|
+
for (const pem of collectSystemCaPems()) certs.add(pem.trim());
|
|
50681
|
+
for (const pem of tls2.rootCertificates) certs.add(pem.trim());
|
|
50682
|
+
certs.add(rootCertPem.trim());
|
|
50683
|
+
const body = [...certs].map((pem) => pem.endsWith("\n") ? pem : pem + "\n").join("");
|
|
50684
|
+
fs2.writeFileSync(path6.join(caDir(), COMBINED_CA_FILE), body, { mode: 420 });
|
|
50685
|
+
}
|
|
50686
|
+
function generateRootCA() {
|
|
50687
|
+
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
50688
|
+
const cert = import_node_forge.default.pki.createCertificate();
|
|
50689
|
+
cert.publicKey = keys.publicKey;
|
|
50690
|
+
cert.serialNumber = "01";
|
|
50691
|
+
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
50692
|
+
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
50693
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
|
50694
|
+
const attrs = [
|
|
50695
|
+
{ name: "commonName", value: ROOT_CN },
|
|
50696
|
+
{ name: "organizationName", value: "billion-context" }
|
|
50697
|
+
];
|
|
50698
|
+
cert.setSubject(attrs);
|
|
50699
|
+
cert.setIssuer(attrs);
|
|
50700
|
+
cert.setExtensions([
|
|
50701
|
+
{ name: "basicConstraints", cA: true },
|
|
50702
|
+
{ name: "keyUsage", keyCertSign: true, cRLSign: true, digitalSignature: true },
|
|
50703
|
+
{ name: "subjectKeyIdentifier" }
|
|
50704
|
+
]);
|
|
50705
|
+
cert.sign(keys.privateKey, import_node_forge.default.md.sha256.create());
|
|
50706
|
+
return {
|
|
50707
|
+
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
50708
|
+
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey)
|
|
50709
|
+
};
|
|
50710
|
+
}
|
|
50711
|
+
function ensureRootCA() {
|
|
50712
|
+
if (rootCertPem && rootKeyPem) {
|
|
50713
|
+
writeCombinedBundle();
|
|
50714
|
+
return;
|
|
50715
|
+
}
|
|
50716
|
+
const dir = caDir();
|
|
50717
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
50718
|
+
const certPath = path6.join(dir, ROOT_CERT_FILE);
|
|
50719
|
+
const keyPath = path6.join(dir, ROOT_KEY_FILE);
|
|
50720
|
+
if (fs2.existsSync(certPath) && fs2.existsSync(keyPath)) {
|
|
50721
|
+
rootCertPem = fs2.readFileSync(certPath, "utf8");
|
|
50722
|
+
rootKeyPem = fs2.readFileSync(keyPath, "utf8");
|
|
50723
|
+
rootCert = import_node_forge.default.pki.certificateFromPem(rootCertPem);
|
|
50724
|
+
rootKey = import_node_forge.default.pki.privateKeyFromPem(rootKeyPem);
|
|
50725
|
+
writeCombinedBundle();
|
|
50726
|
+
return;
|
|
50727
|
+
}
|
|
50728
|
+
const { cert, key } = generateRootCA();
|
|
50729
|
+
fs2.writeFileSync(certPath, cert, { mode: 420 });
|
|
50730
|
+
fs2.writeFileSync(keyPath, key, { mode: 384 });
|
|
50731
|
+
rootCertPem = cert;
|
|
50732
|
+
rootKeyPem = key;
|
|
50733
|
+
rootCert = import_node_forge.default.pki.certificateFromPem(cert);
|
|
50734
|
+
rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
|
|
50735
|
+
writeCombinedBundle();
|
|
50736
|
+
}
|
|
50737
|
+
function getSecureContext(host) {
|
|
50738
|
+
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
50739
|
+
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
50740
|
+
}
|
|
50741
|
+
const cached = secureContextCache.get(host);
|
|
50742
|
+
if (cached) {
|
|
50743
|
+
secureContextCache.delete(host);
|
|
50744
|
+
secureContextCache.set(host, cached);
|
|
50745
|
+
return cached;
|
|
50746
|
+
}
|
|
50747
|
+
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
50748
|
+
const cert = import_node_forge.default.pki.createCertificate();
|
|
50749
|
+
cert.publicKey = keys.publicKey;
|
|
50750
|
+
cert.serialNumber = Date.now().toString() + Math.floor(Math.random() * 1e6).toString();
|
|
50751
|
+
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
50752
|
+
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
50753
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2);
|
|
50754
|
+
cert.setSubject([{ name: "commonName", value: host }]);
|
|
50755
|
+
cert.setIssuer(rootCert.subject.attributes);
|
|
50756
|
+
cert.setExtensions([
|
|
50757
|
+
{ name: "basicConstraints", cA: false },
|
|
50758
|
+
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true },
|
|
50759
|
+
{ name: "extKeyUsage", serverAuth: true },
|
|
50760
|
+
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] }
|
|
50761
|
+
]);
|
|
50762
|
+
cert.sign(rootKey, import_node_forge.default.md.sha256.create());
|
|
50763
|
+
const ctx = tls2.createSecureContext({
|
|
50764
|
+
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
50765
|
+
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey),
|
|
50766
|
+
ca: rootCertPem
|
|
50767
|
+
});
|
|
50768
|
+
secureContextCache.set(host, ctx);
|
|
50769
|
+
if (secureContextCache.size > SECURE_CONTEXT_CACHE_MAX) {
|
|
50770
|
+
const oldest = secureContextCache.keys().next().value;
|
|
50771
|
+
if (oldest !== void 0) secureContextCache.delete(oldest);
|
|
50772
|
+
}
|
|
50773
|
+
return ctx;
|
|
50774
|
+
}
|
|
50775
|
+
|
|
50628
50776
|
// src/web/client.ts
|
|
50629
50777
|
var WEB_CLIENT = `
|
|
50630
50778
|
const byId=(id)=>document.getElementById(id);
|
|
@@ -50657,7 +50805,13 @@ var WEB_STYLES = `
|
|
|
50657
50805
|
`;
|
|
50658
50806
|
|
|
50659
50807
|
// src/web/page.ts
|
|
50808
|
+
function escapeHtml(value) {
|
|
50809
|
+
return value.replace(/[&<>"']/g, (char) => char === "&" ? "&" : char === "<" ? "<" : char === ">" ? ">" : char === '"' ? """ : "'");
|
|
50810
|
+
}
|
|
50660
50811
|
function renderPage(origin, version2) {
|
|
50812
|
+
const caPath = rootCaPath();
|
|
50813
|
+
const caPathEsc = escapeHtml(caPath);
|
|
50814
|
+
const caReady = existsSync3(caPath);
|
|
50661
50815
|
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>billion-context</title><style>${WEB_STYLES}</style></head><body>
|
|
50662
50816
|
<div class="app"><aside class="sidebar"><div class="brand"><div class="brand-title">billion<span>-context</span></div><div class="version">v${version2}</div></div><a class="fork-ribbon" href="https://github.com/ranxianglei/billion-context" target="_blank" rel="noopener">\u2605 Fork me on GitHub</a><nav class="nav"><button class="active" data-page="overview">\u6982\u89C8</button><button data-page="routing">\u63A5\u5165</button><button data-page="upstream">\u4E0A\u6E38</button><button data-page="sessions">\u4F1A\u8BDD</button><button data-page="settings">\u8BBE\u7F6E</button></nav></aside>
|
|
50663
50817
|
<main class="main"><section id="page-overview" class="page active"><h1>\u6982\u89C8</h1><p class="lead">\u672C\u5730\u8DEF\u7531\u4E0E\u4E0A\u6E38\u7F51\u7EDC\u76F8\u4E92\u72EC\u7ACB\uFF0CACP \u538B\u7F29\u8FD0\u884C\u5728\u4E24\u8005\u4E4B\u95F4\u3002</p><div class="grid"><div class="card"><h2>\u670D\u52A1\u5730\u5740</h2><p class="mono">${origin}</p></div><div class="card"><h2>\u5BA2\u6237\u7AEF\u63A5\u5165</h2><p class="status">\u5728"\u63A5\u5165"\u9875\u5C06\u5404\u5BA2\u6237\u7AEF\uFF08Codex / Claude Code / OpenCode / Pi \u7B49\uFF09\u7684\u6D41\u91CF\u8DEF\u7531\u5230 bili\u3002</p></div></div></section>
|
|
@@ -50672,14 +50826,14 @@ function renderPage(origin, version2) {
|
|
|
50672
50826
|
<div class="card"><div class="card-head"><h2>\u5176\u4ED6\uFF08Cursor / Aider / Continue\uFF09</h2><button class="btn small copy-btn" data-copy="${origin}/bili/">\u590D\u5236</button></div><dl class="kv"><dt>\u89C4\u5219</dt><dd>\u4EFB\u610F baseURL \u524D\u52A0 <span class="mono">${origin}/bili/</span></dd><dt>\u793A\u4F8B</dt><dd class="mono">${origin}/bili/https://api.openai.com/v1</dd></dl></div>
|
|
50673
50827
|
<h2 class="section-title">B. \u8BC1\u4E66\u63A5\u5165\u65B9\u5F0F\uFF08zcode \u7B49\u7C7B\u578B\uFF09</h2>
|
|
50674
50828
|
<p class="hint">\u4E0D\u652F\u6301\u6539 URL \u7684\u5BA2\u6237\u7AEF\uFF08endpoint \u786C\u7F16\u7801\uFF09\u9700 MITM \u900F\u660E\u4EE3\u7406\uFF0C\u8BBE HTTPS_PROXY + \u4FE1\u4EFB CA \u8BC1\u4E66\u3002</p>
|
|
50675
|
-
<div class="card"><div class="card-head"><h2>ZCode\uFF08\u7F16\u7A0B\u5957\u9910\uFF09</h2><span class="badge">MITM</span></div><dl class="kv"><dt>\u65B9\u5F0F</dt><dd>MITM \u900F\u660E\u4EE3\u7406</dd><dt>\u8BBE\u7F6E</dt><dd>Settings \u2192 Network \u2192 HTTP Proxy = <span class="mono">${origin}</span></dd><dt>CA \u8BC1\u4E66</dt><dd class="mono"
|
|
50829
|
+
<div class="card"><div class="card-head"><h2>ZCode\uFF08\u7F16\u7A0B\u5957\u9910\uFF09</h2><span class="badge">MITM</span><button class="btn small copy-btn" data-copy="${caPathEsc}">\u590D\u5236 CA \u8DEF\u5F84</button></div><dl class="kv"><dt>\u65B9\u5F0F</dt><dd>MITM \u900F\u660E\u4EE3\u7406</dd><dt>\u8BBE\u7F6E</dt><dd>Settings \u2192 Network \u2192 HTTP Proxy = <span class="mono">${origin}</span></dd><dt>CA \u8BC1\u4E66</dt><dd class="mono">${caPathEsc}${caReady ? "" : "\uFF08\u5C1A\u672A\u751F\u6210\uFF0C\u542F\u52A8\u4EE3\u7406\u540E\u81EA\u52A8\u521B\u5EFA\uFF09"}</dd></dl><p class="hint">CA \u8DEF\u5F84\u662F\u672C\u673A bili \u5B9E\u9645\u751F\u6210\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u70B9"\u590D\u5236 CA \u8DEF\u5F84"\u540E\u76F4\u63A5\u7C98\u8D34\u8FDB ZCode\u3002\u26A0\uFE0F Windows \u4E0A ZCode \u4E0D\u4F1A\u5C55\u5F00 <span class="mono">~</span>\uFF0C\u8BF7\u52FF\u624B\u586B <span class="mono">~/\u2026</span> \u5F62\u5F0F\u7684\u8DEF\u5F84\u3002</p></div></section>
|
|
50676
50830
|
<section id="page-upstream" class="page"><h1>\u4E0A\u6E38\u7F51\u7EDC</h1><p class="lead">\u63A7\u5236 bili \u5982\u4F55\u8BBF\u95EE\u771F\u5B9E Provider\uFF0C\u4E0D\u4F1A\u6539\u53D8\u5BA2\u6237\u7AEF\u7684\u672C\u5730\u8DEF\u7531\u5730\u5740\u3002</p><div class="card"><div class="card-head"><h2>\u5168\u5C40\u4EE3\u7406</h2></div><div class="modes"><label><input type="radio" name="proxy-mode" value="direct" checked>\u76F4\u8FDE\uFF08\u9ED8\u8BA4\uFF09</label><label><input type="radio" name="proxy-mode" value="manual">\u624B\u52A8\u4EE3\u7406</label><label><input type="radio" name="proxy-mode" value="auto">\u81EA\u52A8\uFF08\u8DDF\u968F\u7CFB\u7EDF\uFF09</label></div><div class="field"><label>HTTP / HTTPS Proxy</label><input id="proxy-url" class="mono" placeholder="http://127.0.0.1:7897"></div><dl class="kv"><dt>\u5F53\u524D\u6765\u6E90</dt><dd id="upstream-source">\u76F4\u8FDE</dd><dt>\u6709\u6548\u4EE3\u7406</dt><dd id="upstream-effective" class="mono">direct</dd><dt>\u7CFB\u7EDF PAC</dt><dd id="upstream-pac" class="mono">\u2014</dd><dt>\u72B6\u6001</dt><dd id="upstream-state" class="status">\u5C1A\u672A\u6D4B\u8BD5</dd></dl><div class="actions"><button id="save-upstream" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button><button id="test-upstream" class="btn">\u6D4B\u8BD5\u8FDE\u63A5</button></div></div><div class="card"><div class="card-head"><h2>\u6309 URL \u8986\u76D6</h2></div><p class="status">\u4E3A\u7279\u5B9A Provider \u5355\u72EC\u8BBE\u7F6E\u4E0A\u6E38\u4EE3\u7406\uFF0C\u8986\u76D6\u5168\u5C40\u8BBE\u7F6E\u3002\u7559\u7A7A = \u7EE7\u627F\u5168\u5C40\u3002</p><div id="upstream-overrides" class="status">\u52A0\u8F7D\u4E2D</div><div class="actions"><button id="save-overrides" class="btn primary">\u4FDD\u5B58\u8986\u76D6\u5E76\u70ED\u66F4\u65B0</button></div></div></section>
|
|
50677
50831
|
<section id="page-sessions" class="page"><div class="card-head"><div><h1>\u4F1A\u8BDD</h1><p class="lead">ACP \u538B\u7F29\u72B6\u6001\u4E0E\u4E0A\u6E38\u7528\u91CF\u3002</p></div><button id="refresh-sessions" class="btn">\u5237\u65B0</button></div><div class="card"><table><thead><tr><th>\u6807\u9898</th><th>\u534F\u8BAE</th><th>\u6807\u8BC6</th><th>\u8BF7\u6C42</th><th>\u4E0A\u4E0B\u6587</th><th>\u6700\u540E\u6D3B\u52A8</th></tr></thead><tbody id="sessions-body"></tbody></table></div></section>
|
|
50678
50832
|
<section id="page-settings" class="page"><h1>\u9AD8\u7EA7\u8BBE\u7F6E</h1><p class="lead">\u76F4\u63A5\u7F16\u8F91 providers JSON\uFF08\u6DFB\u52A0\u65B0 Provider\u3001\u914D\u7F6E\u6A21\u578B\u4E0A\u4E0B\u6587\u7A97\u53E3\u3001\u6309 URL \u4EE3\u7406\u7B49\uFF09\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u70ED\u66F4\u65B0\u3002</p><div class="card"><div class="field"><label>providers JSON</label><textarea id="providers-json">{}</textarea></div><div class="actions"><button id="save-providers" class="btn primary">\u4FDD\u5B58\u5E76\u5E94\u7528</button></div></div><div class="card"><div class="card-head"><h2>\u538B\u7F29\u53C2\u6570\uFF08\u5168\u5C40\uFF09</h2></div><p class="status">\u5168\u5C40 compress \u914D\u7F6E\uFF08modelContextLimit / maxContextLimit / emergencyThresholdPercent / nudgeGrowthTokens / preserveRecentMessages / preserveRecentTokens / minCompressRange / tiers / injectTool / injectNudge\uFF09\u3002\u4FDD\u5B58\u540E\u70ED\u66F4\u65B0\uFF0C\u65E0\u9700\u91CD\u542F\u3002\u7F6E\u7A7A = \u6062\u590D\u9ED8\u8BA4\u3002</p><div class="field"><label>compress JSON</label><textarea id="compress-json" placeholder='{"modelContextLimit": 200000}'></textarea></div><div class="actions"><button id="save-compress" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button></div></div></section></main></div><div id="toast" class="toast"></div><script>${WEB_CLIENT}</script></body></html>`;
|
|
50679
50833
|
}
|
|
50680
50834
|
|
|
50681
50835
|
// src/web/api.ts
|
|
50682
|
-
import { closeSync, existsSync as
|
|
50836
|
+
import { closeSync, existsSync as existsSync4, fsyncSync, mkdirSync as mkdirSync4, openSync, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
50683
50837
|
import { dirname as dirname3 } from "path";
|
|
50684
50838
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
50685
50839
|
function readConfig() {
|
|
@@ -50687,7 +50841,7 @@ function readConfig() {
|
|
|
50687
50841
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
50688
50842
|
}
|
|
50689
50843
|
function configParseError() {
|
|
50690
|
-
if (!
|
|
50844
|
+
if (!existsSync4(configFile())) return null;
|
|
50691
50845
|
const parsed = safeReadJson(configFile());
|
|
50692
50846
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return null;
|
|
50693
50847
|
return `config file is not valid JSON: ${configFile()}`;
|
|
@@ -52736,6 +52890,65 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
|
|
|
52736
52890
|
return current;
|
|
52737
52891
|
}
|
|
52738
52892
|
|
|
52893
|
+
// src/acp-panel.ts
|
|
52894
|
+
var PANEL_BOX_TOP = "\u256D";
|
|
52895
|
+
var PANEL_BOX_TITLE = "ACP Context Analysis";
|
|
52896
|
+
var PANEL_FALLBACK_HEADER = "\u{1F4CA} ACP status";
|
|
52897
|
+
function isAcpPanelText(text) {
|
|
52898
|
+
const t = text.trim();
|
|
52899
|
+
if (t.length === 0) return false;
|
|
52900
|
+
if (t.startsWith(PANEL_BOX_TOP) && t.includes(PANEL_BOX_TITLE)) return true;
|
|
52901
|
+
if (t.startsWith(PANEL_FALLBACK_HEADER)) return true;
|
|
52902
|
+
return false;
|
|
52903
|
+
}
|
|
52904
|
+
function messageText(content) {
|
|
52905
|
+
if (typeof content === "string") return content;
|
|
52906
|
+
if (Array.isArray(content)) {
|
|
52907
|
+
let joined = "";
|
|
52908
|
+
for (const part of content) {
|
|
52909
|
+
const p2 = part;
|
|
52910
|
+
if (p2 === null || typeof p2 !== "object") return void 0;
|
|
52911
|
+
const pt2 = p2.type;
|
|
52912
|
+
if (pt2 !== void 0 && pt2 !== "text" && pt2 !== "input_text" && pt2 !== "output_text") return void 0;
|
|
52913
|
+
if (typeof p2.text === "string") joined += p2.text;
|
|
52914
|
+
}
|
|
52915
|
+
return joined;
|
|
52916
|
+
}
|
|
52917
|
+
return void 0;
|
|
52918
|
+
}
|
|
52919
|
+
function stripAcpPanelMessages(messages) {
|
|
52920
|
+
if (!Array.isArray(messages)) return 0;
|
|
52921
|
+
let stripped = 0;
|
|
52922
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
52923
|
+
const rec = messages[i];
|
|
52924
|
+
if (rec === null || typeof rec !== "object") continue;
|
|
52925
|
+
if (rec.role !== "user") continue;
|
|
52926
|
+
const text = messageText(rec.content);
|
|
52927
|
+
if (text !== void 0 && isAcpPanelText(text)) {
|
|
52928
|
+
messages.splice(i, 1);
|
|
52929
|
+
stripped++;
|
|
52930
|
+
}
|
|
52931
|
+
}
|
|
52932
|
+
return stripped;
|
|
52933
|
+
}
|
|
52934
|
+
function stripAcpPanelResponsesInput(input) {
|
|
52935
|
+
if (!Array.isArray(input)) return 0;
|
|
52936
|
+
let stripped = 0;
|
|
52937
|
+
for (let i = input.length - 1; i >= 0; i--) {
|
|
52938
|
+
const rec = input[i];
|
|
52939
|
+
if (rec === null || typeof rec !== "object") continue;
|
|
52940
|
+
const type = rec.type;
|
|
52941
|
+
if (type !== "message" && type !== void 0) continue;
|
|
52942
|
+
if (rec.role !== "user") continue;
|
|
52943
|
+
const text = messageText(rec.content);
|
|
52944
|
+
if (text !== void 0 && isAcpPanelText(text)) {
|
|
52945
|
+
input.splice(i, 1);
|
|
52946
|
+
stripped++;
|
|
52947
|
+
}
|
|
52948
|
+
}
|
|
52949
|
+
return stripped;
|
|
52950
|
+
}
|
|
52951
|
+
|
|
52739
52952
|
// src/stream-openai.ts
|
|
52740
52953
|
function rewriteOpenaiJsonResponse(body, ctx) {
|
|
52741
52954
|
if (!body || typeof body !== "object") return body;
|
|
@@ -53344,13 +53557,13 @@ function buildStatusPanel(input) {
|
|
|
53344
53557
|
|
|
53345
53558
|
// src/plugin.ts
|
|
53346
53559
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
53347
|
-
import
|
|
53348
|
-
import
|
|
53560
|
+
import fs3 from "fs";
|
|
53561
|
+
import path7 from "path";
|
|
53349
53562
|
var PROXY_VERSION = (() => {
|
|
53350
53563
|
try {
|
|
53351
53564
|
const here = fileURLToPath2(import.meta.url);
|
|
53352
|
-
const pkg =
|
|
53353
|
-
return JSON.parse(
|
|
53565
|
+
const pkg = path7.join(path7.dirname(here), "..", "package.json");
|
|
53566
|
+
return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
|
|
53354
53567
|
} catch {
|
|
53355
53568
|
return "dev";
|
|
53356
53569
|
}
|
|
@@ -53362,8 +53575,8 @@ var PLUGIN_PROTOCOL_VERSION = 1;
|
|
|
53362
53575
|
var VERSION = (() => {
|
|
53363
53576
|
try {
|
|
53364
53577
|
const here = fileURLToPath2(import.meta.url);
|
|
53365
|
-
const pkg =
|
|
53366
|
-
return JSON.parse(
|
|
53578
|
+
const pkg = path7.join(path7.dirname(here), "..", "package.json");
|
|
53579
|
+
return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
|
|
53367
53580
|
} catch {
|
|
53368
53581
|
return "dev";
|
|
53369
53582
|
}
|
|
@@ -53392,14 +53605,14 @@ function pluginReportedContextWindow(headers) {
|
|
|
53392
53605
|
var MAX_PLUGIN_CONVERSATIONS = 1024;
|
|
53393
53606
|
var conversations = /* @__PURE__ */ new Map();
|
|
53394
53607
|
var remembered = /* @__PURE__ */ new Map();
|
|
53395
|
-
var conversationsFile = () =>
|
|
53608
|
+
var conversationsFile = () => path7.join(stateDir(), "plugin-conversations.json");
|
|
53396
53609
|
var conversationsSaveTimer;
|
|
53397
53610
|
function writeConversationsFile() {
|
|
53398
53611
|
try {
|
|
53399
53612
|
const obj = {};
|
|
53400
53613
|
for (const [k2, v2] of conversations) obj[k2] = v2;
|
|
53401
|
-
|
|
53402
|
-
|
|
53614
|
+
fs3.mkdirSync(stateDir(), { recursive: true });
|
|
53615
|
+
fs3.writeFileSync(conversationsFile(), JSON.stringify(obj));
|
|
53403
53616
|
} catch {
|
|
53404
53617
|
}
|
|
53405
53618
|
}
|
|
@@ -53419,7 +53632,7 @@ function flushConversations() {
|
|
|
53419
53632
|
}
|
|
53420
53633
|
function loadConversations() {
|
|
53421
53634
|
try {
|
|
53422
|
-
const raw =
|
|
53635
|
+
const raw = fs3.readFileSync(conversationsFile(), "utf8");
|
|
53423
53636
|
const obj = JSON.parse(raw);
|
|
53424
53637
|
for (const [k2, v2] of Object.entries(obj)) {
|
|
53425
53638
|
if (v2 && typeof v2.sessionId === "string" && v2.sessionId.length > 0) {
|
|
@@ -53880,147 +54093,6 @@ async function pipePluginJson(stream2, res, session, protocol) {
|
|
|
53880
54093
|
// src/mitm.ts
|
|
53881
54094
|
import tls3 from "tls";
|
|
53882
54095
|
|
|
53883
|
-
// src/ca.ts
|
|
53884
|
-
var import_node_forge = __toESM(require_lib(), 1);
|
|
53885
|
-
import fs3 from "fs";
|
|
53886
|
-
import path7 from "path";
|
|
53887
|
-
import tls2 from "tls";
|
|
53888
|
-
var ROOT_CERT_FILE = "root-ca.pem";
|
|
53889
|
-
var ROOT_KEY_FILE = "root-ca-key.pem";
|
|
53890
|
-
var COMBINED_CA_FILE = "combined-ca.pem";
|
|
53891
|
-
var ROOT_CN = "billion-context MITM Root CA";
|
|
53892
|
-
var PLATFORM_CA_CANDIDATES = process.platform === "darwin" ? ["/etc/ssl/cert.pem", "/private/etc/ssl/cert.pem"] : [
|
|
53893
|
-
"/etc/ssl/certs/ca-certificates.crt",
|
|
53894
|
-
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
53895
|
-
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
|
53896
|
-
"/etc/ssl/ca-bundle.pem",
|
|
53897
|
-
"/etc/ssl/cert.pem"
|
|
53898
|
-
];
|
|
53899
|
-
var rootCertPem;
|
|
53900
|
-
var rootKeyPem;
|
|
53901
|
-
var rootCert;
|
|
53902
|
-
var rootKey;
|
|
53903
|
-
var secureContextCache = /* @__PURE__ */ new Map();
|
|
53904
|
-
var SECURE_CONTEXT_CACHE_MAX = 64;
|
|
53905
|
-
function collectSystemCaPems(env = process.env) {
|
|
53906
|
-
const pems = [];
|
|
53907
|
-
const seen = /* @__PURE__ */ new Set();
|
|
53908
|
-
const pushFile = (file) => {
|
|
53909
|
-
try {
|
|
53910
|
-
const text = fs3.readFileSync(file, "utf8");
|
|
53911
|
-
if (!text.includes("BEGIN CERTIFICATE") || seen.has(text)) return false;
|
|
53912
|
-
seen.add(text);
|
|
53913
|
-
pems.push(text);
|
|
53914
|
-
return true;
|
|
53915
|
-
} catch {
|
|
53916
|
-
}
|
|
53917
|
-
return false;
|
|
53918
|
-
};
|
|
53919
|
-
const userBundle = env.SSL_CERT_FILE?.trim();
|
|
53920
|
-
if (userBundle && pushFile(userBundle)) return pems;
|
|
53921
|
-
for (const candidate of PLATFORM_CA_CANDIDATES) {
|
|
53922
|
-
if (pushFile(candidate)) break;
|
|
53923
|
-
}
|
|
53924
|
-
return pems;
|
|
53925
|
-
}
|
|
53926
|
-
function writeCombinedBundle() {
|
|
53927
|
-
const certs = /* @__PURE__ */ new Set();
|
|
53928
|
-
for (const pem of collectSystemCaPems()) certs.add(pem.trim());
|
|
53929
|
-
for (const pem of tls2.rootCertificates) certs.add(pem.trim());
|
|
53930
|
-
certs.add(rootCertPem.trim());
|
|
53931
|
-
const body = [...certs].map((pem) => pem.endsWith("\n") ? pem : pem + "\n").join("");
|
|
53932
|
-
fs3.writeFileSync(path7.join(caDir(), COMBINED_CA_FILE), body, { mode: 420 });
|
|
53933
|
-
}
|
|
53934
|
-
function generateRootCA() {
|
|
53935
|
-
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
53936
|
-
const cert = import_node_forge.default.pki.createCertificate();
|
|
53937
|
-
cert.publicKey = keys.publicKey;
|
|
53938
|
-
cert.serialNumber = "01";
|
|
53939
|
-
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
53940
|
-
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
53941
|
-
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
|
53942
|
-
const attrs = [
|
|
53943
|
-
{ name: "commonName", value: ROOT_CN },
|
|
53944
|
-
{ name: "organizationName", value: "billion-context" }
|
|
53945
|
-
];
|
|
53946
|
-
cert.setSubject(attrs);
|
|
53947
|
-
cert.setIssuer(attrs);
|
|
53948
|
-
cert.setExtensions([
|
|
53949
|
-
{ name: "basicConstraints", cA: true },
|
|
53950
|
-
{ name: "keyUsage", keyCertSign: true, cRLSign: true, digitalSignature: true },
|
|
53951
|
-
{ name: "subjectKeyIdentifier" }
|
|
53952
|
-
]);
|
|
53953
|
-
cert.sign(keys.privateKey, import_node_forge.default.md.sha256.create());
|
|
53954
|
-
return {
|
|
53955
|
-
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
53956
|
-
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey)
|
|
53957
|
-
};
|
|
53958
|
-
}
|
|
53959
|
-
function ensureRootCA() {
|
|
53960
|
-
if (rootCertPem && rootKeyPem) {
|
|
53961
|
-
writeCombinedBundle();
|
|
53962
|
-
return;
|
|
53963
|
-
}
|
|
53964
|
-
const dir = caDir();
|
|
53965
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
53966
|
-
const certPath = path7.join(dir, ROOT_CERT_FILE);
|
|
53967
|
-
const keyPath = path7.join(dir, ROOT_KEY_FILE);
|
|
53968
|
-
if (fs3.existsSync(certPath) && fs3.existsSync(keyPath)) {
|
|
53969
|
-
rootCertPem = fs3.readFileSync(certPath, "utf8");
|
|
53970
|
-
rootKeyPem = fs3.readFileSync(keyPath, "utf8");
|
|
53971
|
-
rootCert = import_node_forge.default.pki.certificateFromPem(rootCertPem);
|
|
53972
|
-
rootKey = import_node_forge.default.pki.privateKeyFromPem(rootKeyPem);
|
|
53973
|
-
writeCombinedBundle();
|
|
53974
|
-
return;
|
|
53975
|
-
}
|
|
53976
|
-
const { cert, key } = generateRootCA();
|
|
53977
|
-
fs3.writeFileSync(certPath, cert, { mode: 420 });
|
|
53978
|
-
fs3.writeFileSync(keyPath, key, { mode: 384 });
|
|
53979
|
-
rootCertPem = cert;
|
|
53980
|
-
rootKeyPem = key;
|
|
53981
|
-
rootCert = import_node_forge.default.pki.certificateFromPem(cert);
|
|
53982
|
-
rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
|
|
53983
|
-
writeCombinedBundle();
|
|
53984
|
-
}
|
|
53985
|
-
function getSecureContext(host) {
|
|
53986
|
-
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
53987
|
-
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
53988
|
-
}
|
|
53989
|
-
const cached = secureContextCache.get(host);
|
|
53990
|
-
if (cached) {
|
|
53991
|
-
secureContextCache.delete(host);
|
|
53992
|
-
secureContextCache.set(host, cached);
|
|
53993
|
-
return cached;
|
|
53994
|
-
}
|
|
53995
|
-
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
53996
|
-
const cert = import_node_forge.default.pki.createCertificate();
|
|
53997
|
-
cert.publicKey = keys.publicKey;
|
|
53998
|
-
cert.serialNumber = Date.now().toString() + Math.floor(Math.random() * 1e6).toString();
|
|
53999
|
-
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
54000
|
-
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
54001
|
-
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2);
|
|
54002
|
-
cert.setSubject([{ name: "commonName", value: host }]);
|
|
54003
|
-
cert.setIssuer(rootCert.subject.attributes);
|
|
54004
|
-
cert.setExtensions([
|
|
54005
|
-
{ name: "basicConstraints", cA: false },
|
|
54006
|
-
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true },
|
|
54007
|
-
{ name: "extKeyUsage", serverAuth: true },
|
|
54008
|
-
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] }
|
|
54009
|
-
]);
|
|
54010
|
-
cert.sign(rootKey, import_node_forge.default.md.sha256.create());
|
|
54011
|
-
const ctx = tls2.createSecureContext({
|
|
54012
|
-
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
54013
|
-
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey),
|
|
54014
|
-
ca: rootCertPem
|
|
54015
|
-
});
|
|
54016
|
-
secureContextCache.set(host, ctx);
|
|
54017
|
-
if (secureContextCache.size > SECURE_CONTEXT_CACHE_MAX) {
|
|
54018
|
-
const oldest = secureContextCache.keys().next().value;
|
|
54019
|
-
if (oldest !== void 0) secureContextCache.delete(oldest);
|
|
54020
|
-
}
|
|
54021
|
-
return ctx;
|
|
54022
|
-
}
|
|
54023
|
-
|
|
54024
54096
|
// src/discover.ts
|
|
54025
54097
|
import fs5 from "fs";
|
|
54026
54098
|
import os2 from "os";
|
|
@@ -56070,6 +56142,10 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
56070
56142
|
let rebuiltMessages = parsed.messages;
|
|
56071
56143
|
let systemOut = parsed.system;
|
|
56072
56144
|
let toolsOut = parsed.tools;
|
|
56145
|
+
const strippedPanels = stripAcpPanelMessages(parsed.messages);
|
|
56146
|
+
if (strippedPanels > 0) {
|
|
56147
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
56148
|
+
}
|
|
56073
56149
|
try {
|
|
56074
56150
|
const { msgs, cacheControls } = anthropicToCore(parsed);
|
|
56075
56151
|
originalMessages = msgs;
|
|
@@ -56126,6 +56202,10 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
56126
56202
|
const isTitleGen = maxTokens <= 200;
|
|
56127
56203
|
const shouldInject = opts.compress.injectTool && !isTitleGen;
|
|
56128
56204
|
const injectTools = shouldInject && !pluginMode;
|
|
56205
|
+
const strippedPanels = stripAcpPanelMessages(parsed.messages);
|
|
56206
|
+
if (strippedPanels > 0) {
|
|
56207
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
56208
|
+
}
|
|
56129
56209
|
try {
|
|
56130
56210
|
const { msgs, systemText } = openaiToCore(parsed);
|
|
56131
56211
|
openaiSystemText = systemText;
|
|
@@ -56207,6 +56287,10 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
56207
56287
|
if (droppedEmpty > 0) {
|
|
56208
56288
|
log2("info", `[${sessionId}] dropped ${droppedEmpty} whitespace-only message item(s) before projection (flattened-turn artifact)`);
|
|
56209
56289
|
}
|
|
56290
|
+
const strippedPanels = stripAcpPanelResponsesInput(parsed.input);
|
|
56291
|
+
if (strippedPanels > 0) {
|
|
56292
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
56293
|
+
}
|
|
56210
56294
|
const shouldInject = opts.compress.injectTool;
|
|
56211
56295
|
const injectTools = shouldInject && !pluginMode;
|
|
56212
56296
|
const isCompactionTrigger = hasCompactionTrigger(parsed.input);
|
|
@@ -56445,6 +56529,20 @@ function injectResponsesTool(tools, toolsToAdd = ACP_TOOLS_RESPONSES) {
|
|
|
56445
56529
|
const additions = toolsToAdd.filter((t) => !present.has(t.name));
|
|
56446
56530
|
return [...tools, ...additions];
|
|
56447
56531
|
}
|
|
56532
|
+
var loggedUpstreamProxyDecisions = /* @__PURE__ */ new Set();
|
|
56533
|
+
function logUpstreamProxyDecision(opts, upstreamUrl, decision) {
|
|
56534
|
+
if (!upstreamUrl) return;
|
|
56535
|
+
let host = upstreamUrl;
|
|
56536
|
+
try {
|
|
56537
|
+
host = new URL(upstreamUrl).host;
|
|
56538
|
+
} catch {
|
|
56539
|
+
}
|
|
56540
|
+
const key = `${host}|${decision.proxy ?? ""}|${decision.source}`;
|
|
56541
|
+
if (loggedUpstreamProxyDecisions.has(key)) return;
|
|
56542
|
+
loggedUpstreamProxyDecisions.add(key);
|
|
56543
|
+
const via = decision.proxy ? `via ${maskUrlForLog(decision.proxy)}` : "direct";
|
|
56544
|
+
logMsg(opts, "info", `[upstream-proxy] ${maskHostPortForLog(host)} ${via} (source=${decision.source})`);
|
|
56545
|
+
}
|
|
56448
56546
|
function buildForwardTarget(req, opts, route, affinity, hopMarker) {
|
|
56449
56547
|
const reqUrl = req.url ?? "";
|
|
56450
56548
|
const isAbsoluteUrl = /^https?:\/\//i.test(reqUrl);
|
|
@@ -56468,8 +56566,9 @@ function buildForwardTarget(req, opts, route, affinity, hopMarker) {
|
|
|
56468
56566
|
if (affinity && !clientConversationHeader(req.headers)) {
|
|
56469
56567
|
headers["x-session-id"] = affinity;
|
|
56470
56568
|
}
|
|
56471
|
-
const
|
|
56472
|
-
|
|
56569
|
+
const decision = resolveProxyDecision(opts.routes, opts.proxy, route?.rewrittenUrl ?? upstreamUrl, opts.proxyFallback);
|
|
56570
|
+
logUpstreamProxyDecision(opts, upstreamUrl, decision);
|
|
56571
|
+
return { upstreamUrl, headers, proxyUrl: decision.proxy };
|
|
56473
56572
|
}
|
|
56474
56573
|
function isPreflightFailFast(outcome) {
|
|
56475
56574
|
return "failFast" in outcome;
|
|
@@ -62263,6 +62362,8 @@ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili h
|
|
|
62263
62362
|
auto-whitelisted for MITM so the proxy TLS-terminates exactly the hosts the
|
|
62264
62363
|
client uses; HTTP / localhost providers go direct. pi/claude trust the CA
|
|
62265
62364
|
via NODE_EXTRA_CA_CERTS, codex via SSL_CERT_FILE. Proxy killed on client exit.
|
|
62365
|
+
bili flags (-F, --mitm-domain, --port, ...) must precede the client name;
|
|
62366
|
+
everything after the client name is passed through to the client.
|
|
62266
62367
|
bili pi # launch pi through the proxy
|
|
62267
62368
|
bili pi -- print "hi" # args after the client are passed through
|
|
62268
62369
|
bili pi-test # pi through the proxy with extensions off (proxy owns compression)
|
|
@@ -62272,9 +62373,12 @@ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili h
|
|
|
62272
62373
|
bili hermes # launch hermes-agent through the proxy (/bili/ rewrite of ~/.hermes/config.yaml)
|
|
62273
62374
|
bili dsh --profile web "task" # launch deepseek-harness through the proxy (/bili/ rewrite of ~/.dsh/settings.yaml)
|
|
62274
62375
|
bili test pi # quick end-to-end check of the pi path
|
|
62275
|
-
bili
|
|
62376
|
+
bili --mitm-domain api.foo.com pi # add a domain to the MITM whitelist (flags precede the client)
|
|
62377
|
+
bili -F http://127.0.0.1:7897 codex # route bili's upstream through a proxy (gost-style -F)
|
|
62276
62378
|
|
|
62277
62379
|
Options (override config file / env):
|
|
62380
|
+
-F <url> upstream proxy to forward through (gost-style;
|
|
62381
|
+
http://host:port; must precede the client name)
|
|
62278
62382
|
--port <N> listen port (default 8787)
|
|
62279
62383
|
--host <ADDR> listen host (default 127.0.0.1)
|
|
62280
62384
|
--mitm-domain <domain> extra MITM domain (repeatable; launcher only)
|
|
@@ -62353,6 +62457,7 @@ function parseArgs(argv) {
|
|
|
62353
62457
|
exportOutput = val;
|
|
62354
62458
|
break;
|
|
62355
62459
|
}
|
|
62460
|
+
case "-F":
|
|
62356
62461
|
case "--port":
|
|
62357
62462
|
case "--host":
|
|
62358
62463
|
case "--config":
|
|
@@ -62369,6 +62474,7 @@ function parseArgs(argv) {
|
|
|
62369
62474
|
else if (a === "--config") overrides.BILI_CONFIG_FILE = val;
|
|
62370
62475
|
else if (a === "--origin") overrides.BILI_MCP_PROXY = val;
|
|
62371
62476
|
else if (a === "--bin") process.env.BILI_CLIENT_BIN = val;
|
|
62477
|
+
else if (a === "-F") overrides.BILI_UPSTREAM_PROXY = val;
|
|
62372
62478
|
else overrides.BILI_PLUGIN_AGENT = val;
|
|
62373
62479
|
break;
|
|
62374
62480
|
}
|