billion-context 0.1.83 → 0.1.84-pr.360.366
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 +15 -4
- package/README.zh-CN.md +15 -4
- package/dist/agent/omp.js +73 -1
- package/dist/agent/omp.js.map +1 -1
- package/dist/agent/pi.js +73 -1
- package/dist/agent/pi.js.map +1 -1
- package/dist/index.js +297 -431
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49370,6 +49370,7 @@ function subagentNamespace(identityValue, instructions) {
|
|
|
49370
49370
|
|
|
49371
49371
|
// src/persist.ts
|
|
49372
49372
|
import { createHash as createHash3 } from "crypto";
|
|
49373
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
49373
49374
|
import { rm } from "fs/promises";
|
|
49374
49375
|
import * as path5 from "path";
|
|
49375
49376
|
|
|
@@ -49806,6 +49807,7 @@ function rel(p2, base) {
|
|
|
49806
49807
|
|
|
49807
49808
|
// src/persist.ts
|
|
49808
49809
|
var PERSIST_VERSION = 3;
|
|
49810
|
+
var MIGRATION_MARKER = ".bili-migration-286.done";
|
|
49809
49811
|
function mergeState(parsed) {
|
|
49810
49812
|
const fresh = createInitialState();
|
|
49811
49813
|
return {
|
|
@@ -49865,6 +49867,21 @@ var SessionStore = class {
|
|
|
49865
49867
|
}
|
|
49866
49868
|
return out;
|
|
49867
49869
|
}
|
|
49870
|
+
/** Single-pass boot (#401): ONE loadAll walk+parse, then the #286
|
|
49871
|
+
* identity migration over the SAME parsed map (no extra directory
|
|
49872
|
+
* walk), then hydration into Sessions. initSessions calls this instead
|
|
49873
|
+
* of migrateLegacyIds()+loadAll(), which walked and parsed the whole
|
|
49874
|
+
* tree twice per start. */
|
|
49875
|
+
async boot() {
|
|
49876
|
+
if (!this.enabled) return /* @__PURE__ */ new Map();
|
|
49877
|
+
const loaded = await this.store.loadAll();
|
|
49878
|
+
await this.applyLegacyMigration(loaded);
|
|
49879
|
+
const out = /* @__PURE__ */ new Map();
|
|
49880
|
+
for (const [id, envelope] of loaded) {
|
|
49881
|
+
out.set(id, buildSession(envelope.payload));
|
|
49882
|
+
}
|
|
49883
|
+
return out;
|
|
49884
|
+
}
|
|
49868
49885
|
/** One-time migration for the #286 identity change: sessions persisted
|
|
49869
49886
|
* under the old derived hash id are re-keyed to the client-provided
|
|
49870
49887
|
* conversation value stored in meta.label (which is now the session id
|
|
@@ -49873,10 +49890,21 @@ var SessionStore = class {
|
|
|
49873
49890
|
* session, are deleted. Records without a label cannot be mapped and are
|
|
49874
49891
|
* left in place (they load under their old id but are never requested
|
|
49875
49892
|
* again — the new proxy 400s anonymous requests). Self-terminating:
|
|
49876
|
-
* after one pass no loaded id differs from its label.
|
|
49893
|
+
* after one pass no loaded id differs from its label. A completion
|
|
49894
|
+
* marker makes it run ONCE EVER (#401): the old code re-scanned the tree
|
|
49895
|
+
* on every boot because unlabeled files are intentionally kept, so the
|
|
49896
|
+
* "one-time" log line repeated forever. */
|
|
49877
49897
|
async migrateLegacyIds() {
|
|
49878
49898
|
if (!this.enabled) return;
|
|
49899
|
+
if (existsSync3(this.markerPath())) return;
|
|
49879
49900
|
const loaded = await this.store.loadAll();
|
|
49901
|
+
await this.applyLegacyMigration(loaded);
|
|
49902
|
+
}
|
|
49903
|
+
markerPath() {
|
|
49904
|
+
return path5.join(this.dir, MIGRATION_MARKER);
|
|
49905
|
+
}
|
|
49906
|
+
async applyLegacyMigration(loaded) {
|
|
49907
|
+
if (existsSync3(this.markerPath())) return;
|
|
49880
49908
|
const claimed = /* @__PURE__ */ new Set();
|
|
49881
49909
|
const byLabel = /* @__PURE__ */ new Map();
|
|
49882
49910
|
let unlabeled = 0;
|
|
@@ -49894,24 +49922,39 @@ var SessionStore = class {
|
|
|
49894
49922
|
}
|
|
49895
49923
|
const prev = byLabel.get(label);
|
|
49896
49924
|
if (!prev || envelope.savedAt >= prev.savedAt) {
|
|
49897
|
-
if (prev)
|
|
49925
|
+
if (prev) {
|
|
49926
|
+
await this.removeLegacyFile(prev.id, prev.session);
|
|
49927
|
+
loaded.delete(prev.id);
|
|
49928
|
+
}
|
|
49898
49929
|
byLabel.set(label, { id, savedAt: envelope.savedAt, session });
|
|
49899
49930
|
} else {
|
|
49900
49931
|
await this.removeLegacyFile(id, session);
|
|
49932
|
+
loaded.delete(id);
|
|
49901
49933
|
}
|
|
49902
49934
|
}
|
|
49903
49935
|
let rekeyed = 0;
|
|
49904
49936
|
for (const [label, { id, session }] of byLabel) {
|
|
49905
49937
|
if (claimed.has(label)) {
|
|
49906
49938
|
await this.removeLegacyFile(id, session);
|
|
49939
|
+
loaded.delete(id);
|
|
49907
49940
|
continue;
|
|
49908
49941
|
}
|
|
49909
49942
|
session.id = label;
|
|
49910
49943
|
await this.store.writeNow(label, () => buildRecord(session));
|
|
49911
49944
|
await this.removeLegacyFile(id, session);
|
|
49945
|
+
const envelope = loaded.get(id);
|
|
49946
|
+
if (envelope) {
|
|
49947
|
+
loaded.set(label, { ...envelope, id: label, payload: { ...envelope.payload, id: label } });
|
|
49948
|
+
}
|
|
49949
|
+
loaded.delete(id);
|
|
49912
49950
|
claimed.add(label);
|
|
49913
49951
|
rekeyed++;
|
|
49914
49952
|
}
|
|
49953
|
+
try {
|
|
49954
|
+
mkdirSync3(this.dir, { recursive: true });
|
|
49955
|
+
writeFileSync2(this.markerPath(), String(Date.now()), "utf8");
|
|
49956
|
+
} catch {
|
|
49957
|
+
}
|
|
49915
49958
|
if (rekeyed || unlabeled) {
|
|
49916
49959
|
log("info", `[persist] one-time migration (#286): rekeyed ${rekeyed} legacy session(s), left ${unlabeled} unlabeled legacy file(s) in place`);
|
|
49917
49960
|
}
|
|
@@ -49997,10 +50040,21 @@ function buildRecord(session) {
|
|
|
49997
50040
|
createdAt: session.createdAt
|
|
49998
50041
|
};
|
|
49999
50042
|
}
|
|
50043
|
+
function isBlockView(v2) {
|
|
50044
|
+
return !!v2 && typeof v2 === "object" && typeof v2.text === "string" && typeof v2.count === "number";
|
|
50045
|
+
}
|
|
50000
50046
|
function buildSession(parsed) {
|
|
50001
50047
|
const blockContents = /* @__PURE__ */ new Map();
|
|
50002
50048
|
for (const [bid, content] of Object.entries(parsed.blockContents ?? {})) {
|
|
50003
|
-
if (content
|
|
50049
|
+
if (!content || typeof content !== "object") continue;
|
|
50050
|
+
const full = content.full;
|
|
50051
|
+
if (!isBlockView(full)) continue;
|
|
50052
|
+
const one = content.one;
|
|
50053
|
+
const oneView = isBlockView(one) ? one : null;
|
|
50054
|
+
blockContents.set(bid, {
|
|
50055
|
+
one: oneView && !(oneView.text === full.text && oneView.count === full.count) ? oneView : null,
|
|
50056
|
+
full
|
|
50057
|
+
});
|
|
50004
50058
|
}
|
|
50005
50059
|
const meta = parsed.meta ?? {};
|
|
50006
50060
|
const stats = parsed.stats ?? {};
|
|
@@ -50085,8 +50139,7 @@ async function initSessions() {
|
|
|
50085
50139
|
initialized = true;
|
|
50086
50140
|
const store = getStore();
|
|
50087
50141
|
if (!store.enabled) return;
|
|
50088
|
-
await store.
|
|
50089
|
-
const loaded = await store.loadAll();
|
|
50142
|
+
const loaded = await store.boot();
|
|
50090
50143
|
if (loaded.size > MAX_SESSIONS) {
|
|
50091
50144
|
const freshness = (s3) => Math.max(s3.createdAt ?? 0, s3.lastSeen ?? 0);
|
|
50092
50145
|
const entries = [...loaded.entries()].sort((a, b2) => freshness(b2[1]) - freshness(a[1]));
|
|
@@ -50292,7 +50345,7 @@ function withStagedCompressGuidance(text) {
|
|
|
50292
50345
|
}
|
|
50293
50346
|
|
|
50294
50347
|
// src/decompress-shared.ts
|
|
50295
|
-
import { mkdirSync as
|
|
50348
|
+
import { mkdirSync as mkdirSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
50296
50349
|
import { dirname as dirname2, join as join2 } from "path";
|
|
50297
50350
|
import { tmpdir } from "os";
|
|
50298
50351
|
var trackedTempFiles = [];
|
|
@@ -50339,7 +50392,7 @@ function resolveDecompress(args, ctx) {
|
|
|
50339
50392
|
let body;
|
|
50340
50393
|
let count;
|
|
50341
50394
|
if (cached) {
|
|
50342
|
-
const view = full ? cached.full : cached.one;
|
|
50395
|
+
const view = full ? cached.full : cached.one ?? cached.full;
|
|
50343
50396
|
body = view.text;
|
|
50344
50397
|
count = view.count;
|
|
50345
50398
|
} else {
|
|
@@ -50352,8 +50405,8 @@ function resolveDecompress(args, ctx) {
|
|
|
50352
50405
|
const outPath = body.length > 1e4 ? join2(tmpdir(), `acp-decompress-${safeBlockId}-${Date.now()}.txt`) : null;
|
|
50353
50406
|
if (outPath) {
|
|
50354
50407
|
try {
|
|
50355
|
-
|
|
50356
|
-
|
|
50408
|
+
mkdirSync4(dirname2(outPath), { recursive: true });
|
|
50409
|
+
writeFileSync3(outPath, body, "utf8");
|
|
50357
50410
|
trackedTempFiles.push({ path: outPath, mtimeMs: Date.now() });
|
|
50358
50411
|
reapTempFiles();
|
|
50359
50412
|
return `${header}
|
|
@@ -50649,8 +50702,9 @@ ${reasons.map((r) => `- ${r}`).join("\n")}` : "";
|
|
|
50649
50702
|
const full = collectBlockContent(res.state, b2, ctx.messages, { full: true });
|
|
50650
50703
|
const one = collectBlockContent(res.state, b2, ctx.messages, { full: false });
|
|
50651
50704
|
if (full.count > 0 || one.count > 0) {
|
|
50705
|
+
const sameView = one.text === full.text && one.count === full.count;
|
|
50652
50706
|
cacheBlockContent(ctx.session, b2.blockId, {
|
|
50653
|
-
one: { text: one.text, count: one.count },
|
|
50707
|
+
one: sameView ? null : { text: one.text, count: one.count },
|
|
50654
50708
|
full: { text: full.text, count: full.count }
|
|
50655
50709
|
});
|
|
50656
50710
|
}
|
|
@@ -51032,7 +51086,7 @@ import { dirname as dirname4, join as join3 } from "path";
|
|
|
51032
51086
|
import { fileURLToPath } from "url";
|
|
51033
51087
|
|
|
51034
51088
|
// src/web/page.ts
|
|
51035
|
-
import { existsSync as
|
|
51089
|
+
import { existsSync as existsSync4 } from "fs";
|
|
51036
51090
|
|
|
51037
51091
|
// src/ca.ts
|
|
51038
51092
|
var import_node_forge = __toESM(require_lib(), 1);
|
|
@@ -51103,7 +51157,7 @@ function generateRootCA() {
|
|
|
51103
51157
|
cert.setSubject(attrs);
|
|
51104
51158
|
cert.setIssuer(attrs);
|
|
51105
51159
|
cert.setExtensions([
|
|
51106
|
-
{ name: "basicConstraints", cA: true },
|
|
51160
|
+
{ name: "basicConstraints", cA: true, critical: true },
|
|
51107
51161
|
{ name: "keyUsage", keyCertSign: true, cRLSign: true, digitalSignature: true },
|
|
51108
51162
|
{ name: "subjectKeyIdentifier" }
|
|
51109
51163
|
]);
|
|
@@ -51139,16 +51193,10 @@ function ensureRootCA() {
|
|
|
51139
51193
|
rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
|
|
51140
51194
|
writeCombinedBundle();
|
|
51141
51195
|
}
|
|
51142
|
-
function
|
|
51196
|
+
function mintHostCert(host) {
|
|
51143
51197
|
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
51144
51198
|
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
51145
51199
|
}
|
|
51146
|
-
const cached = secureContextCache.get(host);
|
|
51147
|
-
if (cached) {
|
|
51148
|
-
secureContextCache.delete(host);
|
|
51149
|
-
secureContextCache.set(host, cached);
|
|
51150
|
-
return cached;
|
|
51151
|
-
}
|
|
51152
51200
|
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
51153
51201
|
const cert = import_node_forge.default.pki.createCertificate();
|
|
51154
51202
|
cert.publicKey = keys.publicKey;
|
|
@@ -51158,16 +51206,35 @@ function getSecureContext(host) {
|
|
|
51158
51206
|
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2);
|
|
51159
51207
|
cert.setSubject([{ name: "commonName", value: host }]);
|
|
51160
51208
|
cert.setIssuer(rootCert.subject.attributes);
|
|
51209
|
+
const rootSki = rootCert.generateSubjectKeyIdentifier().getBytes();
|
|
51161
51210
|
cert.setExtensions([
|
|
51162
51211
|
{ name: "basicConstraints", cA: false },
|
|
51163
51212
|
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true },
|
|
51164
51213
|
{ name: "extKeyUsage", serverAuth: true },
|
|
51165
|
-
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] }
|
|
51214
|
+
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] },
|
|
51215
|
+
{ name: "subjectKeyIdentifier" },
|
|
51216
|
+
{ name: "authorityKeyIdentifier", keyIdentifier: rootSki }
|
|
51166
51217
|
]);
|
|
51167
51218
|
cert.sign(rootKey, import_node_forge.default.md.sha256.create());
|
|
51219
|
+
return {
|
|
51220
|
+
certPem: import_node_forge.default.pki.certificateToPem(cert),
|
|
51221
|
+
keyPem: import_node_forge.default.pki.privateKeyToPem(keys.privateKey)
|
|
51222
|
+
};
|
|
51223
|
+
}
|
|
51224
|
+
function getSecureContext(host) {
|
|
51225
|
+
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
51226
|
+
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
51227
|
+
}
|
|
51228
|
+
const cached = secureContextCache.get(host);
|
|
51229
|
+
if (cached) {
|
|
51230
|
+
secureContextCache.delete(host);
|
|
51231
|
+
secureContextCache.set(host, cached);
|
|
51232
|
+
return cached;
|
|
51233
|
+
}
|
|
51234
|
+
const { certPem, keyPem } = mintHostCert(host);
|
|
51168
51235
|
const ctx = tls2.createSecureContext({
|
|
51169
|
-
cert:
|
|
51170
|
-
key:
|
|
51236
|
+
cert: certPem,
|
|
51237
|
+
key: keyPem,
|
|
51171
51238
|
ca: rootCertPem
|
|
51172
51239
|
});
|
|
51173
51240
|
secureContextCache.set(host, ctx);
|
|
@@ -51216,7 +51283,7 @@ function escapeHtml(value) {
|
|
|
51216
51283
|
function renderPage(origin, version2) {
|
|
51217
51284
|
const caPath = rootCaPath();
|
|
51218
51285
|
const caPathEsc = escapeHtml(caPath);
|
|
51219
|
-
const caReady =
|
|
51286
|
+
const caReady = existsSync4(caPath);
|
|
51220
51287
|
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>
|
|
51221
51288
|
<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>
|
|
51222
51289
|
<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>
|
|
@@ -51238,7 +51305,7 @@ function renderPage(origin, version2) {
|
|
|
51238
51305
|
}
|
|
51239
51306
|
|
|
51240
51307
|
// src/web/api.ts
|
|
51241
|
-
import { closeSync, existsSync as
|
|
51308
|
+
import { closeSync, existsSync as existsSync5, fsyncSync, mkdirSync as mkdirSync5, openSync, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
51242
51309
|
import { dirname as dirname3 } from "path";
|
|
51243
51310
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
51244
51311
|
function readConfig() {
|
|
@@ -51246,7 +51313,7 @@ function readConfig() {
|
|
|
51246
51313
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
51247
51314
|
}
|
|
51248
51315
|
function configParseError() {
|
|
51249
|
-
if (!
|
|
51316
|
+
if (!existsSync5(configFile())) return null;
|
|
51250
51317
|
const parsed = safeReadJson(configFile());
|
|
51251
51318
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return null;
|
|
51252
51319
|
return `config file is not valid JSON: ${configFile()}`;
|
|
@@ -51264,12 +51331,12 @@ function readUpstreamSettings() {
|
|
|
51264
51331
|
}
|
|
51265
51332
|
function atomicWriteConfig(config) {
|
|
51266
51333
|
const filePath = configFile();
|
|
51267
|
-
|
|
51334
|
+
mkdirSync5(dirname3(filePath), { recursive: true });
|
|
51268
51335
|
const tempPath = `${filePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
51269
51336
|
let descriptor;
|
|
51270
51337
|
try {
|
|
51271
51338
|
descriptor = openSync(tempPath, "wx", 384);
|
|
51272
|
-
|
|
51339
|
+
writeFileSync4(descriptor, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
51273
51340
|
fsyncSync(descriptor);
|
|
51274
51341
|
closeSync(descriptor);
|
|
51275
51342
|
descriptor = void 0;
|
|
@@ -51947,10 +52014,11 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
51947
52014
|
if (realCalls > 0) ctx.log(`[acp-loop] round ${round}: ${realCalls} real tool call(s) forwarded to client`);
|
|
51948
52015
|
}
|
|
51949
52016
|
if (proxyResults.length > 0) {
|
|
52017
|
+
const requiresThinkingSignature = ctx.protocol === "anthropic";
|
|
51950
52018
|
if (reasoningSegments.length > 0) {
|
|
51951
52019
|
for (let i = 0; i < reasoningSegments.length; i++) {
|
|
51952
52020
|
const seg = reasoningSegments[i];
|
|
51953
|
-
if (seg.text.length === 0 || seg.signature.length === 0) continue;
|
|
52021
|
+
if (seg.text.length === 0 || requiresThinkingSignature && seg.signature.length === 0) continue;
|
|
51954
52022
|
const reasoningMsg = {
|
|
51955
52023
|
id: i === 0 ? `acp_loop_r${round}_reasoning` : `acp_loop_r${round}_reasoning_${i + 1}`,
|
|
51956
52024
|
role: "assistant",
|
|
@@ -52073,7 +52141,7 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
52073
52141
|
try {
|
|
52074
52142
|
respResult = await fetchUpstream(newBody);
|
|
52075
52143
|
} catch (e) {
|
|
52076
|
-
if (!(e instanceof UpstreamHttpError) || e.status < 400 || e.status >= 500 || degradedRetried || !coreMessages.some(isLoopThinking)) {
|
|
52144
|
+
if (!(e instanceof UpstreamHttpError) || e.status < 400 || e.status >= 500 || degradedRetried || ctx.protocol !== "anthropic" || !coreMessages.some(isLoopThinking)) {
|
|
52077
52145
|
throw e;
|
|
52078
52146
|
}
|
|
52079
52147
|
degradedRetried = true;
|
|
@@ -52295,6 +52363,7 @@ data: ${JSON.stringify(obj)}
|
|
|
52295
52363
|
}
|
|
52296
52364
|
async function* iterSseEvents(stream2) {
|
|
52297
52365
|
const reader = stream2.getReader();
|
|
52366
|
+
const decoder = new TextDecoder();
|
|
52298
52367
|
let buf = "";
|
|
52299
52368
|
try {
|
|
52300
52369
|
while (true) {
|
|
@@ -52306,7 +52375,7 @@ async function* iterSseEvents(stream2) {
|
|
|
52306
52375
|
break;
|
|
52307
52376
|
}
|
|
52308
52377
|
if (done) break;
|
|
52309
|
-
buf +=
|
|
52378
|
+
buf += decoder.decode(value, { stream: true });
|
|
52310
52379
|
buf = buf.replace(/\r\n|\r/g, "\n");
|
|
52311
52380
|
let idx;
|
|
52312
52381
|
while ((idx = buf.indexOf("\n\n")) >= 0) {
|
|
@@ -52784,6 +52853,7 @@ function filterRealToolFragments(parsed, realIndexes) {
|
|
|
52784
52853
|
}
|
|
52785
52854
|
async function* iterSseChunks(stream2) {
|
|
52786
52855
|
const reader = stream2.getReader();
|
|
52856
|
+
const decoder = new TextDecoder();
|
|
52787
52857
|
let buf = "";
|
|
52788
52858
|
try {
|
|
52789
52859
|
while (true) {
|
|
@@ -52795,7 +52865,7 @@ async function* iterSseChunks(stream2) {
|
|
|
52795
52865
|
break;
|
|
52796
52866
|
}
|
|
52797
52867
|
if (done) break;
|
|
52798
|
-
buf +=
|
|
52868
|
+
buf += decoder.decode(value, { stream: true });
|
|
52799
52869
|
buf = buf.replace(/\r\n|\r/g, "\n");
|
|
52800
52870
|
let idx;
|
|
52801
52871
|
while ((idx = buf.indexOf("\n\n")) >= 0) {
|
|
@@ -53121,6 +53191,7 @@ function createOpenaiAdapter(requestBody, clientSystem) {
|
|
|
53121
53191
|
// src/loop/adapter-anthropic.ts
|
|
53122
53192
|
async function* iterSseEvents2(stream2) {
|
|
53123
53193
|
const reader = stream2.getReader();
|
|
53194
|
+
const decoder = new TextDecoder();
|
|
53124
53195
|
let buf = "";
|
|
53125
53196
|
try {
|
|
53126
53197
|
while (true) {
|
|
@@ -53132,7 +53203,7 @@ async function* iterSseEvents2(stream2) {
|
|
|
53132
53203
|
break;
|
|
53133
53204
|
}
|
|
53134
53205
|
if (done) break;
|
|
53135
|
-
buf +=
|
|
53206
|
+
buf += decoder.decode(value, { stream: true });
|
|
53136
53207
|
buf = buf.replace(/\r\n|\r/g, "\n");
|
|
53137
53208
|
let idx;
|
|
53138
53209
|
while ((idx = buf.indexOf("\n\n")) >= 0) {
|
|
@@ -53779,6 +53850,76 @@ ${FAKE_COMPLETION_HINT}`;
|
|
|
53779
53850
|
return JSON.stringify(obj);
|
|
53780
53851
|
}
|
|
53781
53852
|
|
|
53853
|
+
// src/acp-panel.ts
|
|
53854
|
+
var PANEL_BOX_TOP = "\u256D";
|
|
53855
|
+
var PANEL_BOX_TITLE = "ACP Context Analysis";
|
|
53856
|
+
var PANEL_BOX_FOOTER = "Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.";
|
|
53857
|
+
var PANEL_FALLBACK_HEADER = "\u{1F4CA} ACP status";
|
|
53858
|
+
function isAcpPanelText(text) {
|
|
53859
|
+
const t = text.trim();
|
|
53860
|
+
if (t.length === 0) return false;
|
|
53861
|
+
return isBoxPanel(t) || isFallbackPanel(t);
|
|
53862
|
+
}
|
|
53863
|
+
function isBoxPanel(t) {
|
|
53864
|
+
return t.startsWith(PANEL_BOX_TOP) && t.includes(PANEL_BOX_TITLE) && t.endsWith(PANEL_BOX_FOOTER);
|
|
53865
|
+
}
|
|
53866
|
+
function isFallbackPanel(t) {
|
|
53867
|
+
const lines = t.split("\n");
|
|
53868
|
+
if (lines[0] !== PANEL_FALLBACK_HEADER) return false;
|
|
53869
|
+
for (let i = 1; i < lines.length; i++) {
|
|
53870
|
+
const line = lines[i];
|
|
53871
|
+
if (line.length > 0 && !line.startsWith(" ")) return false;
|
|
53872
|
+
}
|
|
53873
|
+
return true;
|
|
53874
|
+
}
|
|
53875
|
+
function messageText(content) {
|
|
53876
|
+
if (typeof content === "string") return content;
|
|
53877
|
+
if (Array.isArray(content)) {
|
|
53878
|
+
let joined = "";
|
|
53879
|
+
for (const part of content) {
|
|
53880
|
+
const p2 = part;
|
|
53881
|
+
if (p2 === null || typeof p2 !== "object") return void 0;
|
|
53882
|
+
const pt2 = p2.type;
|
|
53883
|
+
if (pt2 !== void 0 && pt2 !== "text" && pt2 !== "input_text") return void 0;
|
|
53884
|
+
if (typeof p2.text === "string") joined += p2.text;
|
|
53885
|
+
}
|
|
53886
|
+
return joined;
|
|
53887
|
+
}
|
|
53888
|
+
return void 0;
|
|
53889
|
+
}
|
|
53890
|
+
function stripAcpPanelMessages(messages) {
|
|
53891
|
+
if (!Array.isArray(messages)) return 0;
|
|
53892
|
+
let stripped = 0;
|
|
53893
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
53894
|
+
const rec = messages[i];
|
|
53895
|
+
if (rec === null || typeof rec !== "object") continue;
|
|
53896
|
+
if (rec.role !== "user") continue;
|
|
53897
|
+
const text = messageText(rec.content);
|
|
53898
|
+
if (text !== void 0 && isAcpPanelText(text)) {
|
|
53899
|
+
messages.splice(i, 1);
|
|
53900
|
+
stripped++;
|
|
53901
|
+
}
|
|
53902
|
+
}
|
|
53903
|
+
return stripped;
|
|
53904
|
+
}
|
|
53905
|
+
function stripAcpPanelResponsesInput(input) {
|
|
53906
|
+
if (!Array.isArray(input)) return 0;
|
|
53907
|
+
let stripped = 0;
|
|
53908
|
+
for (let i = input.length - 1; i >= 0; i--) {
|
|
53909
|
+
const rec = input[i];
|
|
53910
|
+
if (rec === null || typeof rec !== "object") continue;
|
|
53911
|
+
const type = rec.type;
|
|
53912
|
+
if (type !== "message" && type !== void 0) continue;
|
|
53913
|
+
if (rec.role !== "user") continue;
|
|
53914
|
+
const text = messageText(rec.content);
|
|
53915
|
+
if (text !== void 0 && isAcpPanelText(text)) {
|
|
53916
|
+
input.splice(i, 1);
|
|
53917
|
+
stripped++;
|
|
53918
|
+
}
|
|
53919
|
+
}
|
|
53920
|
+
return stripped;
|
|
53921
|
+
}
|
|
53922
|
+
|
|
53782
53923
|
// src/stream-openai.ts
|
|
53783
53924
|
function rewriteOpenaiJsonResponse(body, ctx) {
|
|
53784
53925
|
if (!body || typeof body !== "object") return body;
|
|
@@ -55505,6 +55646,7 @@ function readOmpConfig(ompHome) {
|
|
|
55505
55646
|
}
|
|
55506
55647
|
function parseHermesYaml(text) {
|
|
55507
55648
|
const result = { providers: {} };
|
|
55649
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
55508
55650
|
let mode = "none";
|
|
55509
55651
|
let sectionIndent = -1;
|
|
55510
55652
|
let entryIndent = -1;
|
|
@@ -55549,8 +55691,8 @@ function parseHermesYaml(text) {
|
|
|
55549
55691
|
current = m2 ? m2[1] : null;
|
|
55550
55692
|
if (current && !result.providers[current]) result.providers[current] = {};
|
|
55551
55693
|
} else if (indent > entryIndent && current) {
|
|
55552
|
-
const apiMatch = /^api:\s*(\S+)/.exec(trimmed);
|
|
55553
|
-
if (apiMatch)
|
|
55694
|
+
const apiMatch = /^(base_url|url|api):\s*(\S+)/.exec(trimmed);
|
|
55695
|
+
if (apiMatch) candidates.set(`${current}\0${apiMatch[1]}`, apiMatch[2]);
|
|
55554
55696
|
}
|
|
55555
55697
|
} else {
|
|
55556
55698
|
const dashMatch = /^-\s+(.*)$/.exec(trimmed);
|
|
@@ -55567,6 +55709,10 @@ function parseHermesYaml(text) {
|
|
|
55567
55709
|
}
|
|
55568
55710
|
}
|
|
55569
55711
|
}
|
|
55712
|
+
for (const name of Object.keys(result.providers)) {
|
|
55713
|
+
const pick = candidates.get(`${name}\0base_url`) ?? candidates.get(`${name}\0url`) ?? candidates.get(`${name}\0api`);
|
|
55714
|
+
if (pick !== void 0) result.providers[name].api = pick;
|
|
55715
|
+
}
|
|
55570
55716
|
return result;
|
|
55571
55717
|
}
|
|
55572
55718
|
function readHermesConfig(hermesHome) {
|
|
@@ -56867,6 +57013,16 @@ function resolveUpstream(_opts, reqUrl, req) {
|
|
|
56867
57013
|
}
|
|
56868
57014
|
}
|
|
56869
57015
|
}
|
|
57016
|
+
if (reqUrl.startsWith("http://") || reqUrl.startsWith("https://")) {
|
|
57017
|
+
try {
|
|
57018
|
+
const u2 = new URL(reqUrl);
|
|
57019
|
+
const ownHost = (req?.headers.host ?? "").toLowerCase();
|
|
57020
|
+
if (u2.host.toLowerCase() !== ownHost) {
|
|
57021
|
+
return { upstream: `${u2.protocol}//${u2.host}`, rewrittenUrl: reqUrl, tunnel: true };
|
|
57022
|
+
}
|
|
57023
|
+
} catch {
|
|
57024
|
+
}
|
|
57025
|
+
}
|
|
56870
57026
|
return void 0;
|
|
56871
57027
|
}
|
|
56872
57028
|
async function startServer(opts) {
|
|
@@ -56964,7 +57120,7 @@ Content-Length: ${Buffer.byteLength(body)}\r
|
|
|
56964
57120
|
);
|
|
56965
57121
|
}
|
|
56966
57122
|
if (opts.debug) {
|
|
56967
|
-
log2("info", `[debug] build features: raw-HTTP-capture(on) | remote_compaction_v2-strip(on) | cert-MITM-launcher(on) | strip-acp-summary(on) \u2014 seeing this line confirms the launcher build (not registry 0.1.34)`);
|
|
57123
|
+
log2("info", `[debug] build features: raw-HTTP-capture(${bodyDumpEnabled() ? "on" : "off"}) | remote_compaction_v2-strip(on) | cert-MITM-launcher(on) | strip-acp-summary(on) \u2014 seeing this line confirms the launcher build (not registry 0.1.34)`);
|
|
56968
57124
|
}
|
|
56969
57125
|
};
|
|
56970
57126
|
const attemptListen = (port) => {
|
|
@@ -57604,6 +57760,10 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57604
57760
|
let rebuiltMessages = parsed.messages;
|
|
57605
57761
|
let systemOut = parsed.system;
|
|
57606
57762
|
let toolsOut = parsed.tools;
|
|
57763
|
+
const strippedPanels = stripAcpPanelMessages(parsed.messages);
|
|
57764
|
+
if (strippedPanels > 0) {
|
|
57765
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
57766
|
+
}
|
|
57607
57767
|
try {
|
|
57608
57768
|
const { msgs, cacheControls } = anthropicToCore(parsed);
|
|
57609
57769
|
originalMessages = msgs;
|
|
@@ -57693,6 +57853,10 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
57693
57853
|
const isTitleGen = maxTokens <= 200;
|
|
57694
57854
|
const shouldInject = opts.compress.injectTool && !isTitleGen;
|
|
57695
57855
|
const injectTools = shouldInject && !pluginMode;
|
|
57856
|
+
const strippedPanels = stripAcpPanelMessages(parsed.messages);
|
|
57857
|
+
if (strippedPanels > 0) {
|
|
57858
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
57859
|
+
}
|
|
57696
57860
|
try {
|
|
57697
57861
|
const { msgs, systemText } = openaiToCore(parsed);
|
|
57698
57862
|
openaiSystemText = systemText;
|
|
@@ -57778,6 +57942,10 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57778
57942
|
if (droppedEmpty > 0) {
|
|
57779
57943
|
log2("info", `[${sessionId}] dropped ${droppedEmpty} whitespace-only message item(s) before projection (flattened-turn artifact)`);
|
|
57780
57944
|
}
|
|
57945
|
+
const strippedPanels = stripAcpPanelResponsesInput(parsed.input);
|
|
57946
|
+
if (strippedPanels > 0) {
|
|
57947
|
+
log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
|
|
57948
|
+
}
|
|
57781
57949
|
const shouldInject = opts.compress.injectTool;
|
|
57782
57950
|
const injectTools = shouldInject && !pluginMode;
|
|
57783
57951
|
const isCompactionTrigger = hasCompactionTrigger(parsed.input);
|
|
@@ -58640,10 +58808,10 @@ async function pipeThrough(stream2, res) {
|
|
|
58640
58808
|
}
|
|
58641
58809
|
}
|
|
58642
58810
|
async function dumpStreamToFile(stream2, dir, name) {
|
|
58643
|
-
const { mkdirSync:
|
|
58811
|
+
const { mkdirSync: mkdirSync7, createWriteStream: createWriteStream2 } = await import("fs");
|
|
58644
58812
|
const { join: join4 } = await import("path");
|
|
58645
58813
|
try {
|
|
58646
|
-
|
|
58814
|
+
mkdirSync7(dir, { recursive: true });
|
|
58647
58815
|
const ws2 = createWriteStream2(join4(dir, name));
|
|
58648
58816
|
ws2.on("error", (e) => {
|
|
58649
58817
|
logDumpFailure("SSE stream dump", e);
|
|
@@ -62704,7 +62872,6 @@ function selfDistFile(name) {
|
|
|
62704
62872
|
return path15.join(selfPackageRoot(), "dist", name);
|
|
62705
62873
|
}
|
|
62706
62874
|
var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
|
|
62707
|
-
var LAUNCHER_DEFAULT_PORT = 8787;
|
|
62708
62875
|
var LAUNCH_CLIENTS = ["pi", "codex", "claude", "omp", "opencode", "hermes", "dsh", "pi-test"];
|
|
62709
62876
|
var HEALTH_PATH = "/__bili/health";
|
|
62710
62877
|
var HEALTH_POLL_INTERVAL_MS = 200;
|
|
@@ -62809,8 +62976,16 @@ function discoverRoutes(client, config) {
|
|
|
62809
62976
|
if (url.protocol !== "http:" && url.protocol !== "https:") continue;
|
|
62810
62977
|
if (hermesSeen.has(name)) continue;
|
|
62811
62978
|
hermesSeen.add(name);
|
|
62812
|
-
|
|
62813
|
-
|
|
62979
|
+
if (url.protocol === "https:") {
|
|
62980
|
+
const host = url.hostname.toLowerCase();
|
|
62981
|
+
if (host && !httpsSeen.has(host)) {
|
|
62982
|
+
httpsSeen.add(host);
|
|
62983
|
+
httpsDomains.push(host);
|
|
62984
|
+
}
|
|
62985
|
+
} else if (!rewriteKeys.has(name)) {
|
|
62986
|
+
rewriteKeys.add(name);
|
|
62987
|
+
httpRewrites.push({ key: name, realUpstream: real });
|
|
62988
|
+
}
|
|
62814
62989
|
} catch {
|
|
62815
62990
|
}
|
|
62816
62991
|
}
|
|
@@ -62841,8 +63016,23 @@ function discoverRoutes(client, config) {
|
|
|
62841
63016
|
function discoverDomains(client, config) {
|
|
62842
63017
|
return discoverRoutes(client, config).httpsDomains;
|
|
62843
63018
|
}
|
|
62844
|
-
function buildPiEnv(origin, caPath, baseEnv) {
|
|
62845
|
-
|
|
63019
|
+
function buildPiEnv(origin, caPath, baseEnv, httpRewrites = [], httpsRewrites = []) {
|
|
63020
|
+
const manifest = {};
|
|
63021
|
+
for (const r of httpRewrites) {
|
|
63022
|
+
if (r.key.length === 0 || r.realUpstream.length === 0) continue;
|
|
63023
|
+
manifest[r.key] = wrapUpstream(origin, r.realUpstream);
|
|
63024
|
+
}
|
|
63025
|
+
for (const r of httpsRewrites) {
|
|
63026
|
+
if (r.key.length === 0 || r.realUpstream.length === 0) continue;
|
|
63027
|
+
manifest[r.key] = r.realUpstream;
|
|
63028
|
+
}
|
|
63029
|
+
return {
|
|
63030
|
+
...baseEnv,
|
|
63031
|
+
HTTPS_PROXY: origin,
|
|
63032
|
+
NODE_EXTRA_CA_CERTS: caPath,
|
|
63033
|
+
BILLION_CONTEXT_PROXY: origin,
|
|
63034
|
+
...Object.keys(manifest).length > 0 ? { BILI_PROVIDER_REWRITES: JSON.stringify(manifest) } : {}
|
|
63035
|
+
};
|
|
62846
63036
|
}
|
|
62847
63037
|
function buildCodexEnv(origin, caPath, baseEnv) {
|
|
62848
63038
|
return { ...baseEnv, HTTPS_PROXY: origin, SSL_CERT_FILE: caPath, BILLION_CONTEXT_PROXY: origin };
|
|
@@ -63373,363 +63563,6 @@ function writeOverlayFileAtomic(overlay, fileName, contents) {
|
|
|
63373
63563
|
}
|
|
63374
63564
|
}
|
|
63375
63565
|
}
|
|
63376
|
-
function writePiCompactionDisabledSettings(piHome, overlay) {
|
|
63377
|
-
let settings = {};
|
|
63378
|
-
try {
|
|
63379
|
-
const parsed = JSON.parse(fs12.readFileSync(path15.join(piHome, "settings.json"), "utf8"));
|
|
63380
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
63381
|
-
settings = parsed;
|
|
63382
|
-
}
|
|
63383
|
-
} catch {
|
|
63384
|
-
}
|
|
63385
|
-
const compactionRaw = settings.compaction;
|
|
63386
|
-
const compaction = compactionRaw && typeof compactionRaw === "object" && !Array.isArray(compactionRaw) ? { ...compactionRaw } : {};
|
|
63387
|
-
compaction.enabled = false;
|
|
63388
|
-
settings.compaction = compaction;
|
|
63389
|
-
writeOverlayFileAtomic(overlay, "settings.json", JSON.stringify(settings, null, 2));
|
|
63390
|
-
}
|
|
63391
|
-
function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
|
|
63392
|
-
if (!fs12.existsSync(piHome)) return void 0;
|
|
63393
|
-
const overlay = `${piHome}-bili`;
|
|
63394
|
-
const generated = ["settings.json"];
|
|
63395
|
-
let modelsRoot;
|
|
63396
|
-
try {
|
|
63397
|
-
const parsed = JSON.parse(fs12.readFileSync(path15.join(piHome, "models.json"), "utf8"));
|
|
63398
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
63399
|
-
modelsRoot = parsed;
|
|
63400
|
-
generated.push("models.json");
|
|
63401
|
-
}
|
|
63402
|
-
} catch {
|
|
63403
|
-
}
|
|
63404
|
-
if (!refreshOverlayHome(piHome, overlay, generated)) return void 0;
|
|
63405
|
-
if (modelsRoot) {
|
|
63406
|
-
const providersVal = modelsRoot.providers;
|
|
63407
|
-
if (providersVal && typeof providersVal === "object" && !Array.isArray(providersVal)) {
|
|
63408
|
-
const providers = providersVal;
|
|
63409
|
-
for (const r of httpRewrites) {
|
|
63410
|
-
const prov = providers[r.key];
|
|
63411
|
-
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
63412
|
-
const p2 = prov;
|
|
63413
|
-
const existing = typeof p2.baseUrl === "string" ? p2.baseUrl : r.realUpstream;
|
|
63414
|
-
p2.baseUrl = wrapUpstream(origin, unwrapUpstream2(existing));
|
|
63415
|
-
}
|
|
63416
|
-
}
|
|
63417
|
-
for (const r of httpsRewrites) {
|
|
63418
|
-
const prov = providers[r.key];
|
|
63419
|
-
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
63420
|
-
const p2 = prov;
|
|
63421
|
-
p2.baseUrl = r.realUpstream;
|
|
63422
|
-
}
|
|
63423
|
-
}
|
|
63424
|
-
}
|
|
63425
|
-
writeOverlayFileAtomic(overlay, "models.json", JSON.stringify(modelsRoot));
|
|
63426
|
-
}
|
|
63427
|
-
writePiCompactionDisabledSettings(piHome, overlay);
|
|
63428
|
-
return overlay;
|
|
63429
|
-
}
|
|
63430
|
-
function atomicWriteTextFile(filePath, contents) {
|
|
63431
|
-
const draft = `${filePath}.${process.pid}.bili-tmp`;
|
|
63432
|
-
try {
|
|
63433
|
-
fs12.writeFileSync(draft, contents);
|
|
63434
|
-
fs12.renameSync(draft, filePath);
|
|
63435
|
-
} catch {
|
|
63436
|
-
try {
|
|
63437
|
-
fs12.rmSync(draft, { force: true });
|
|
63438
|
-
} catch {
|
|
63439
|
-
}
|
|
63440
|
-
throw new Error(`bili: could not write ${filePath}`);
|
|
63441
|
-
}
|
|
63442
|
-
}
|
|
63443
|
-
function liveProxyPorts() {
|
|
63444
|
-
const ports = /* @__PURE__ */ new Set();
|
|
63445
|
-
const inst = readProxyInstanceFile();
|
|
63446
|
-
if (isProxyInstanceFile(inst)) {
|
|
63447
|
-
if (isPidAlive(inst.pid)) ports.add(inst.port);
|
|
63448
|
-
} else if (inst) {
|
|
63449
|
-
try {
|
|
63450
|
-
ports.add(new URL(inst.origin).port === "" ? 80 : Number(new URL(inst.origin).port));
|
|
63451
|
-
} catch {
|
|
63452
|
-
}
|
|
63453
|
-
}
|
|
63454
|
-
return ports;
|
|
63455
|
-
}
|
|
63456
|
-
function unpackDeadProxyUrlsInFile(filePath, livePorts) {
|
|
63457
|
-
let txt;
|
|
63458
|
-
try {
|
|
63459
|
-
txt = fs12.readFileSync(filePath, "utf8");
|
|
63460
|
-
} catch {
|
|
63461
|
-
return 0;
|
|
63462
|
-
}
|
|
63463
|
-
const re2 = /https?:\/\/(?:127\.0\.0\.1|localhost|\[::1\]):(\d+)\/bili\/(https?:\/\/\S+)/g;
|
|
63464
|
-
let changed = 0;
|
|
63465
|
-
const out = txt.replace(re2, (full, portStr, raw) => {
|
|
63466
|
-
if (livePorts.has(Number(portStr))) return full;
|
|
63467
|
-
changed += 1;
|
|
63468
|
-
return raw;
|
|
63469
|
-
});
|
|
63470
|
-
if (changed === 0) return 0;
|
|
63471
|
-
try {
|
|
63472
|
-
atomicWriteTextFile(filePath, out);
|
|
63473
|
-
} catch {
|
|
63474
|
-
return 0;
|
|
63475
|
-
}
|
|
63476
|
-
return changed;
|
|
63477
|
-
}
|
|
63478
|
-
function mergeOmpCompactionDisabledYaml(text) {
|
|
63479
|
-
const lines = text.split(/\r?\n/);
|
|
63480
|
-
let compactionLine = -1;
|
|
63481
|
-
for (let i = 0; i < lines.length; i++) {
|
|
63482
|
-
const rawLine = lines[i];
|
|
63483
|
-
const trimmed = rawLine.trim();
|
|
63484
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63485
|
-
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63486
|
-
if (indent === 0 && /^compaction:\s*(#.*)?$/.test(trimmed)) {
|
|
63487
|
-
compactionLine = i;
|
|
63488
|
-
break;
|
|
63489
|
-
}
|
|
63490
|
-
}
|
|
63491
|
-
if (compactionLine === -1) {
|
|
63492
|
-
const base = text === "" || text.endsWith("\n") ? text : `${text}
|
|
63493
|
-
`;
|
|
63494
|
-
return `${base}compaction:
|
|
63495
|
-
enabled: false
|
|
63496
|
-
`;
|
|
63497
|
-
}
|
|
63498
|
-
for (let i = compactionLine + 1; i < lines.length; i++) {
|
|
63499
|
-
const rawLine = lines[i];
|
|
63500
|
-
const trimmed = rawLine.trim();
|
|
63501
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63502
|
-
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63503
|
-
if (indent === 0) break;
|
|
63504
|
-
if (/^enabled:/.test(trimmed)) {
|
|
63505
|
-
const leading = rawLine.slice(0, rawLine.length - rawLine.trimStart().length);
|
|
63506
|
-
const commentMatch = /\s+#.*$/.exec(rawLine);
|
|
63507
|
-
const comment = commentMatch ? commentMatch[0] : "";
|
|
63508
|
-
lines[i] = `${leading}enabled: false${comment}`;
|
|
63509
|
-
return lines.join("\n");
|
|
63510
|
-
}
|
|
63511
|
-
}
|
|
63512
|
-
let childIndent = 2;
|
|
63513
|
-
for (let i = compactionLine + 1; i < lines.length; i++) {
|
|
63514
|
-
const rawLine = lines[i];
|
|
63515
|
-
const trimmed = rawLine.trim();
|
|
63516
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63517
|
-
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63518
|
-
if (indent === 0) break;
|
|
63519
|
-
childIndent = indent;
|
|
63520
|
-
break;
|
|
63521
|
-
}
|
|
63522
|
-
lines.splice(compactionLine + 1, 0, `${" ".repeat(childIndent)}enabled: false`);
|
|
63523
|
-
return lines.join("\n");
|
|
63524
|
-
}
|
|
63525
|
-
function writeOmpCompactionDisabledConfig(ompHome, overlay) {
|
|
63526
|
-
let base;
|
|
63527
|
-
let baseIsJson = false;
|
|
63528
|
-
for (const name of ["config.yml", "config.yaml"]) {
|
|
63529
|
-
try {
|
|
63530
|
-
base = fs12.readFileSync(path15.join(ompHome, name), "utf8");
|
|
63531
|
-
break;
|
|
63532
|
-
} catch {
|
|
63533
|
-
}
|
|
63534
|
-
}
|
|
63535
|
-
if (base === void 0) {
|
|
63536
|
-
try {
|
|
63537
|
-
base = fs12.readFileSync(path15.join(ompHome, "settings.json"), "utf8");
|
|
63538
|
-
baseIsJson = true;
|
|
63539
|
-
} catch {
|
|
63540
|
-
}
|
|
63541
|
-
}
|
|
63542
|
-
let merged;
|
|
63543
|
-
if (base === void 0) {
|
|
63544
|
-
merged = "compaction:\n enabled: false\n";
|
|
63545
|
-
} else if (baseIsJson) {
|
|
63546
|
-
let settings = {};
|
|
63547
|
-
try {
|
|
63548
|
-
const parsed = JSON.parse(base);
|
|
63549
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
63550
|
-
settings = parsed;
|
|
63551
|
-
}
|
|
63552
|
-
} catch {
|
|
63553
|
-
}
|
|
63554
|
-
const compactionRaw = settings.compaction;
|
|
63555
|
-
const compaction = compactionRaw && typeof compactionRaw === "object" && !Array.isArray(compactionRaw) ? { ...compactionRaw } : {};
|
|
63556
|
-
compaction.enabled = false;
|
|
63557
|
-
settings.compaction = compaction;
|
|
63558
|
-
merged = JSON.stringify(settings, null, 2);
|
|
63559
|
-
} else {
|
|
63560
|
-
merged = mergeOmpCompactionDisabledYaml(base);
|
|
63561
|
-
}
|
|
63562
|
-
writeOverlayFileAtomic(overlay, "config.yml", merged);
|
|
63563
|
-
}
|
|
63564
|
-
function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
|
|
63565
|
-
if (!fs12.existsSync(ompHome)) return void 0;
|
|
63566
|
-
const overlay = `${ompHome}-bili`;
|
|
63567
|
-
const generated = ["config.yml"];
|
|
63568
|
-
const modelsPath = path15.join(ompHome, "models.yml");
|
|
63569
|
-
const unpacked = unpackDeadProxyUrlsInFile(modelsPath, liveProxyPorts());
|
|
63570
|
-
if (unpacked > 0) {
|
|
63571
|
-
console.error(`bili: unpacked ${unpacked} dead proxy URL(s) from the real ${modelsPath}`);
|
|
63572
|
-
}
|
|
63573
|
-
let modelsText;
|
|
63574
|
-
try {
|
|
63575
|
-
modelsText = fs12.readFileSync(modelsPath, "utf8");
|
|
63576
|
-
generated.push("models.yml");
|
|
63577
|
-
} catch {
|
|
63578
|
-
}
|
|
63579
|
-
if (!refreshOverlayHome(ompHome, overlay, generated)) return void 0;
|
|
63580
|
-
if (modelsText !== void 0) {
|
|
63581
|
-
const httpMap = new Map(httpRewrites.map((r) => [r.key, wrapUpstream(origin, r.realUpstream)]));
|
|
63582
|
-
const httpsMap = new Map(httpsRewrites.map((r) => [r.key, r.realUpstream]));
|
|
63583
|
-
const lines = modelsText.split(/\r?\n/);
|
|
63584
|
-
let providersIndent = -1;
|
|
63585
|
-
let providerIndent = -1;
|
|
63586
|
-
let currentProvider = null;
|
|
63587
|
-
for (let i = 0; i < lines.length; i++) {
|
|
63588
|
-
const rawLine = lines[i];
|
|
63589
|
-
const trimmed = rawLine.trim();
|
|
63590
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63591
|
-
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63592
|
-
if (providersIndent === -1) {
|
|
63593
|
-
if (/^providers:\s*(#.*)?$/.test(trimmed)) providersIndent = indent;
|
|
63594
|
-
continue;
|
|
63595
|
-
}
|
|
63596
|
-
if (indent <= providersIndent) break;
|
|
63597
|
-
if (providerIndent === -1) providerIndent = indent;
|
|
63598
|
-
if (indent === providerIndent) {
|
|
63599
|
-
const m2 = /^([A-Za-z0-9_.-]+):/.exec(trimmed);
|
|
63600
|
-
currentProvider = m2 ? m2[1] : null;
|
|
63601
|
-
} else if (indent > providerIndent && currentProvider) {
|
|
63602
|
-
const baseMatch = /^(baseUrl:\s*)(\S+)/.exec(trimmed);
|
|
63603
|
-
if (baseMatch) {
|
|
63604
|
-
const target = httpMap.get(currentProvider) ?? httpsMap.get(currentProvider);
|
|
63605
|
-
if (target) {
|
|
63606
|
-
const leading = rawLine.slice(0, rawLine.length - rawLine.trimStart().length);
|
|
63607
|
-
const commentMatch = /\s+#.*$/.exec(rawLine);
|
|
63608
|
-
const comment = commentMatch ? commentMatch[0] : "";
|
|
63609
|
-
lines[i] = `${leading}baseUrl: ${target}${comment}`;
|
|
63610
|
-
}
|
|
63611
|
-
}
|
|
63612
|
-
}
|
|
63613
|
-
}
|
|
63614
|
-
writeOverlayFileAtomic(overlay, "models.yml", lines.join("\n"));
|
|
63615
|
-
}
|
|
63616
|
-
writeOmpCompactionDisabledConfig(ompHome, overlay);
|
|
63617
|
-
return overlay;
|
|
63618
|
-
}
|
|
63619
|
-
function prepareHermesHome(hermesHome, origin, rewrites) {
|
|
63620
|
-
if (rewrites.length === 0) return void 0;
|
|
63621
|
-
const cfgPath = path15.join(hermesHome, "config.yaml");
|
|
63622
|
-
let txt;
|
|
63623
|
-
try {
|
|
63624
|
-
txt = fs12.readFileSync(cfgPath, "utf8");
|
|
63625
|
-
} catch {
|
|
63626
|
-
return void 0;
|
|
63627
|
-
}
|
|
63628
|
-
const wrapSet = new Set(rewrites.map((r) => r.realUpstream));
|
|
63629
|
-
const eol = txt.includes("\r\n") ? "\r\n" : "\n";
|
|
63630
|
-
const lines = txt.split(/\r?\n/);
|
|
63631
|
-
let changed = false;
|
|
63632
|
-
for (let i = 0; i < lines.length; i++) {
|
|
63633
|
-
const rawLine = lines[i];
|
|
63634
|
-
const m2 = /^(\s*(?:api|base_url|url):\s*)(\S+)(\s+#.*)?$/.exec(rawLine);
|
|
63635
|
-
if (!m2) continue;
|
|
63636
|
-
const rawUrl = m2[2].replace(/^["']|["']$/g, "");
|
|
63637
|
-
if (!/^https?:\/\//i.test(rawUrl)) continue;
|
|
63638
|
-
const real = unwrapUpstream2(rawUrl);
|
|
63639
|
-
if (!wrapSet.has(real)) continue;
|
|
63640
|
-
lines[i] = `${m2[1]}${wrapUpstream(origin, real)}${m2[3] ?? ""}`;
|
|
63641
|
-
changed = true;
|
|
63642
|
-
}
|
|
63643
|
-
if (!changed) return void 0;
|
|
63644
|
-
const overlay = `${hermesHome}-bili`;
|
|
63645
|
-
if (!refreshOverlayHome(hermesHome, overlay, "config.yaml")) return void 0;
|
|
63646
|
-
writeOverlayFileAtomic(overlay, "config.yaml", lines.join(eol));
|
|
63647
|
-
return overlay;
|
|
63648
|
-
}
|
|
63649
|
-
function writeHermesIdentityPlugin(hermesHome, overlay, rewrites) {
|
|
63650
|
-
try {
|
|
63651
|
-
if (fs12.existsSync(path15.join(hermesHome, "plugins"))) return false;
|
|
63652
|
-
} catch {
|
|
63653
|
-
return false;
|
|
63654
|
-
}
|
|
63655
|
-
const dir = path15.join("plugins", "model-providers", "bili-session-identity");
|
|
63656
|
-
try {
|
|
63657
|
-
fs12.mkdirSync(path15.join(overlay, dir), { recursive: true });
|
|
63658
|
-
} catch {
|
|
63659
|
-
return false;
|
|
63660
|
-
}
|
|
63661
|
-
const keys = rewrites.map((r) => r.key);
|
|
63662
|
-
const pluginDir = path15.join(overlay, dir);
|
|
63663
|
-
try {
|
|
63664
|
-
fs12.writeFileSync(path15.join(pluginDir, "__init__.py"), hermesIdentityPluginSource(keys));
|
|
63665
|
-
fs12.writeFileSync(path15.join(pluginDir, "plugin.yaml"), [
|
|
63666
|
-
"name: bili-session-identity",
|
|
63667
|
-
"kind: model-provider",
|
|
63668
|
-
"version: 1.0.0",
|
|
63669
|
-
"description: billion-context session identity (installed by `bili hermes` \u2014 safe to delete)",
|
|
63670
|
-
"author: billion-context",
|
|
63671
|
-
""
|
|
63672
|
-
].join("\n"));
|
|
63673
|
-
} catch {
|
|
63674
|
-
return false;
|
|
63675
|
-
}
|
|
63676
|
-
try {
|
|
63677
|
-
return fs12.existsSync(path15.join(overlay, dir, "__init__.py"));
|
|
63678
|
-
} catch {
|
|
63679
|
-
return false;
|
|
63680
|
-
}
|
|
63681
|
-
}
|
|
63682
|
-
function hermesIdentityPluginSource(providerKeys) {
|
|
63683
|
-
return [
|
|
63684
|
-
'"""Installed by `bili hermes` (billion-context) \u2014 safe to delete.',
|
|
63685
|
-
"",
|
|
63686
|
-
"Re-registers hermes's `custom` provider profile (plus a `custom:<name>`",
|
|
63687
|
-
"profile for every provider the proxy fronts) with one addition: the",
|
|
63688
|
-
"REAL hermes session id is sent as `prompt_cache_key` on every request,",
|
|
63689
|
-
"which the billion-context proxy uses as the stable conversation",
|
|
63690
|
-
"identity for its compression sessions. Removing this file restores",
|
|
63691
|
-
'stock behavior (no prompt_cache_key)."""',
|
|
63692
|
-
"from providers import get_provider_profile, register_provider",
|
|
63693
|
-
"from providers.base import ProviderProfile",
|
|
63694
|
-
"",
|
|
63695
|
-
`_PROVIDER_KEYS = ${JSON.stringify(providerKeys)}`,
|
|
63696
|
-
"",
|
|
63697
|
-
'_custom = get_provider_profile("custom")',
|
|
63698
|
-
"_BASE = type(_custom) if _custom is not None else ProviderProfile",
|
|
63699
|
-
"",
|
|
63700
|
-
"",
|
|
63701
|
-
"class _BiliSessionIdentity(_BASE):",
|
|
63702
|
-
" def build_api_kwargs_extras(self, *, session_id=None, **ctx):",
|
|
63703
|
-
" extra_body, top_level = _BASE.build_api_kwargs_extras(",
|
|
63704
|
-
" self, session_id=session_id, **ctx",
|
|
63705
|
-
" )",
|
|
63706
|
-
' sid = str(session_id or "").strip()',
|
|
63707
|
-
" if sid:",
|
|
63708
|
-
' top_level.setdefault("prompt_cache_key", sid[:64])',
|
|
63709
|
-
" return extra_body, top_level",
|
|
63710
|
-
"",
|
|
63711
|
-
"",
|
|
63712
|
-
"def _register(name, template, with_aliases):",
|
|
63713
|
-
" fields = {}",
|
|
63714
|
-
" if template is not None:",
|
|
63715
|
-
" # Aliases are copied ONLY for the canonical custom",
|
|
63716
|
-
" # re-registration: copying them onto custom:<name> entries",
|
|
63717
|
-
" # would steal the aliases (register_provider re-points each",
|
|
63718
|
-
" # alias at the registering name).",
|
|
63719
|
-
' for attr in (("aliases",) if with_aliases else ()) + ("env_vars", "base_url", "default_max_tokens"):',
|
|
63720
|
-
" value = getattr(template, attr, None)",
|
|
63721
|
-
" if value:",
|
|
63722
|
-
" fields[attr] = value",
|
|
63723
|
-
" register_provider(_BiliSessionIdentity(name=name, **fields))",
|
|
63724
|
-
"",
|
|
63725
|
-
"",
|
|
63726
|
-
"if _custom is not None:",
|
|
63727
|
-
' _register("custom", _custom, True)',
|
|
63728
|
-
"for _key in _PROVIDER_KEYS:",
|
|
63729
|
-
' _register("custom:" + _key, _custom, False)',
|
|
63730
|
-
""
|
|
63731
|
-
].join("\n");
|
|
63732
|
-
}
|
|
63733
63566
|
function prepareDshHome(dshHome, origin, rewrites) {
|
|
63734
63567
|
const cfgPath = path15.join(dshHome, "settings.yaml");
|
|
63735
63568
|
let txt;
|
|
@@ -63878,7 +63711,29 @@ async function probeExistingInstance(readInstance, fetchHealthInfo) {
|
|
|
63878
63711
|
if (health.instanceId !== void 0 && health.instanceId !== inst.instanceId) return void 0;
|
|
63879
63712
|
return inst;
|
|
63880
63713
|
}
|
|
63881
|
-
|
|
63714
|
+
function pickEphemeralPort(host = LAUNCHER_DEFAULT_HOST) {
|
|
63715
|
+
return new Promise((resolve, reject) => {
|
|
63716
|
+
const srv = net2.createServer();
|
|
63717
|
+
srv.once("error", reject);
|
|
63718
|
+
srv.listen(0, host, () => {
|
|
63719
|
+
const addr = srv.address();
|
|
63720
|
+
srv.close(() => {
|
|
63721
|
+
if (addr && typeof addr === "object") resolve(addr.port);
|
|
63722
|
+
else reject(new Error("could not allocate a free port"));
|
|
63723
|
+
});
|
|
63724
|
+
});
|
|
63725
|
+
});
|
|
63726
|
+
}
|
|
63727
|
+
var INHERITED_PROXY_VARS = [
|
|
63728
|
+
"http_proxy",
|
|
63729
|
+
"https_proxy",
|
|
63730
|
+
"all_proxy",
|
|
63731
|
+
"HTTP_PROXY",
|
|
63732
|
+
"HTTPS_PROXY",
|
|
63733
|
+
"ALL_PROXY",
|
|
63734
|
+
"no_proxy",
|
|
63735
|
+
"NO_PROXY"
|
|
63736
|
+
];
|
|
63882
63737
|
function stripInheritedProxy(env) {
|
|
63883
63738
|
const cleaned = { ...env };
|
|
63884
63739
|
for (const key of INHERITED_PROXY_VARS) delete cleaned[key];
|
|
@@ -63903,7 +63758,7 @@ async function ensureProxyRunning(opts, deps = {}) {
|
|
|
63903
63758
|
return { origin: existing.origin, port: existing.port, attached: true };
|
|
63904
63759
|
}
|
|
63905
63760
|
const launchToken = randomUUID5();
|
|
63906
|
-
const port = opts.port;
|
|
63761
|
+
const port = opts.port > 0 ? opts.port : await pickEphemeralPort(opts.host);
|
|
63907
63762
|
const script = process.argv[1];
|
|
63908
63763
|
if (!script) throw new Error("bili: cannot resolve launcher script path");
|
|
63909
63764
|
const logPath2 = path15.join(os5.tmpdir(), `bili-proxy-${port}.log`);
|
|
@@ -63912,7 +63767,7 @@ async function ensureProxyRunning(opts, deps = {}) {
|
|
|
63912
63767
|
try {
|
|
63913
63768
|
child = spawnImpl(
|
|
63914
63769
|
process.execPath,
|
|
63915
|
-
[script, ...proxyStartArgs(opts)],
|
|
63770
|
+
[script, ...proxyStartArgs({ ...opts, port })],
|
|
63916
63771
|
{
|
|
63917
63772
|
detached: true,
|
|
63918
63773
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -64019,8 +63874,9 @@ function resolveClientCommand(client, env) {
|
|
|
64019
63874
|
return { command: resolved ?? client, prefixArgs: [] };
|
|
64020
63875
|
}
|
|
64021
63876
|
function parsePort(raw) {
|
|
64022
|
-
|
|
64023
|
-
|
|
63877
|
+
if (!raw || !raw.trim()) return 0;
|
|
63878
|
+
const port = parseInt(raw, 10);
|
|
63879
|
+
if (!Number.isFinite(port) || port < 1 || port > 65535) {
|
|
64024
63880
|
console.error(`bili: invalid --port "${raw}"`);
|
|
64025
63881
|
process.exit(2);
|
|
64026
63882
|
}
|
|
@@ -64031,9 +63887,30 @@ async function runLaunch(params, deps = {}) {
|
|
|
64031
63887
|
const port = parsePort(params.overrides.ACP_PORT ?? process.env.ACP_PORT);
|
|
64032
63888
|
const passthrough = params.overrides.ACP_PASSTHROUGH === "1";
|
|
64033
63889
|
const debug = params.overrides.ACP_DEBUG === "1";
|
|
64034
|
-
const config = loadClientConfig(process.env, process.cwd());
|
|
64035
63890
|
const base = baseClientName(params.client);
|
|
63891
|
+
const discoveryEnv = base === "pi" || base === "omp" ? { ...process.env, PI_CODING_AGENT_DIR: void 0 } : process.env;
|
|
63892
|
+
const config = loadClientConfig(discoveryEnv, process.cwd());
|
|
64036
63893
|
const routes = discoverRoutes(base, config);
|
|
63894
|
+
const piRealHome = resolvePiHome({ ...process.env, PI_CODING_AGENT_DIR: void 0 });
|
|
63895
|
+
const ompRealHome = resolveOmpHome({ ...process.env, PI_CODING_AGENT_DIR: void 0 });
|
|
63896
|
+
if (base === "pi" && (routes.httpRewrites.length > 0 || routes.httpsRewrites.length > 0)) {
|
|
63897
|
+
const piExt = selfDistFile("agent/pi.js");
|
|
63898
|
+
const extAvailable = piExt !== void 0 && fs12.existsSync(piExt) || piPluginInstalled(piRealHome);
|
|
63899
|
+
if (!extAvailable) {
|
|
63900
|
+
throw new Error(
|
|
63901
|
+
"bili: pi needs provider URL rewrites but the bili extension cannot load (dist/agent/pi.js missing and the plugin is not installed in ~/.pi/agent/settings.json) \u2014 reinstall billion-context or run `bili plugin install pi`"
|
|
63902
|
+
);
|
|
63903
|
+
}
|
|
63904
|
+
}
|
|
63905
|
+
if (base === "omp" && routes.httpRewrites.length > 0) {
|
|
63906
|
+
const ompExt = selfDistFile("agent/omp.js");
|
|
63907
|
+
const extAvailable = ompExt !== void 0 && fs12.existsSync(ompExt) || ompPluginLoadedFrom(ompRealHome);
|
|
63908
|
+
if (!extAvailable) {
|
|
63909
|
+
throw new Error(
|
|
63910
|
+
"bili: omp needs provider URL rewrites but the bili extension cannot load (dist/agent/omp.js missing and the plugin is not installed in ~/.omp/agent/config.yml) \u2014 reinstall billion-context or run `bili plugin install omp`"
|
|
63911
|
+
);
|
|
63912
|
+
}
|
|
63913
|
+
}
|
|
64037
63914
|
const biliRoutes = loadRoutes(process.env);
|
|
64038
63915
|
const domains = dedupeInOrder([...routes.httpsDomains, ...params.mitmDomains ?? []]);
|
|
64039
63916
|
const handle2 = await ensureProxyRunning({ host, port, passthrough, debug, mitmDomains: domains, modelWindows: collectModelWindows(config, base) }, deps);
|
|
@@ -64046,10 +63923,7 @@ async function runLaunch(params, deps = {}) {
|
|
|
64046
63923
|
const ca = resolveCaCertPath(process.env);
|
|
64047
63924
|
let env;
|
|
64048
63925
|
let clientArgs = params.clientArgs;
|
|
64049
|
-
let piOverlayHome;
|
|
64050
|
-
let ompOverlayHome;
|
|
64051
63926
|
let opencodeTmpFile;
|
|
64052
|
-
let hermesOverlayHome;
|
|
64053
63927
|
let dshOverlayHome;
|
|
64054
63928
|
const tmpFiles = [];
|
|
64055
63929
|
const directUrl = launcherDirectUrl(process.env);
|
|
@@ -64077,19 +63951,17 @@ async function runLaunch(params, deps = {}) {
|
|
|
64077
63951
|
}
|
|
64078
63952
|
const origin = handle2.origin;
|
|
64079
63953
|
if (base === "pi") {
|
|
64080
|
-
env = buildPiEnv(origin, ca, process.env);
|
|
64081
|
-
|
|
64082
|
-
if (piOverlayHome) env.PI_CODING_AGENT_DIR = piOverlayHome;
|
|
63954
|
+
env = buildPiEnv(origin, ca, process.env, routes.httpRewrites, routes.httpsRewrites);
|
|
63955
|
+
delete env.PI_CODING_AGENT_DIR;
|
|
64083
63956
|
const piExt = selfDistFile("agent/pi.js");
|
|
64084
|
-
if (piExt && fs12.existsSync(piExt) && !piPluginInstalled(
|
|
63957
|
+
if (piExt && fs12.existsSync(piExt) && !piPluginInstalled(piRealHome)) {
|
|
64085
63958
|
clientArgs = ["-e", piExt, ...clientArgs];
|
|
64086
63959
|
}
|
|
64087
63960
|
} else if (base === "omp") {
|
|
64088
|
-
env = buildPiEnv(origin, ca, process.env);
|
|
64089
|
-
|
|
64090
|
-
if (ompOverlayHome) env.PI_CODING_AGENT_DIR = ompOverlayHome;
|
|
63961
|
+
env = buildPiEnv(origin, ca, process.env, routes.httpRewrites);
|
|
63962
|
+
delete env.PI_CODING_AGENT_DIR;
|
|
64091
63963
|
const ompExt = selfDistFile("agent/omp.js");
|
|
64092
|
-
if (ompExt && fs12.existsSync(ompExt) && !ompPluginLoadedFrom(
|
|
63964
|
+
if (ompExt && fs12.existsSync(ompExt) && !ompPluginLoadedFrom(ompRealHome)) {
|
|
64093
63965
|
clientArgs = ["-e", ompExt, ...clientArgs];
|
|
64094
63966
|
}
|
|
64095
63967
|
} else if (base === "opencode") {
|
|
@@ -64099,18 +63971,12 @@ async function runLaunch(params, deps = {}) {
|
|
|
64099
63971
|
opencodeTmpFile = prepareOpencodeHttpRewrite(resolveOpencodeConfigFile(process.env), origin, routes.httpRewrites, routes.httpsRewrites, opencodePluginPath);
|
|
64100
63972
|
if (opencodeTmpFile) env.OPENCODE_CONFIG = opencodeTmpFile;
|
|
64101
63973
|
} else if (base === "hermes") {
|
|
64102
|
-
env =
|
|
64103
|
-
|
|
64104
|
-
|
|
64105
|
-
|
|
64106
|
-
if (!writeHermesIdentityPlugin(resolveHermesHome(process.env), hermesOverlayHome, routes.httpRewrites)) {
|
|
64107
|
-
console.error(
|
|
64108
|
-
"bili: ~/.hermes has its own plugins/ \u2014 skipping the session-identity plugin; hermes requests will be rejected by the proxy without an identity (see #286)."
|
|
64109
|
-
);
|
|
64110
|
-
}
|
|
64111
|
-
} else {
|
|
63974
|
+
env = stripInheritedProxy(process.env);
|
|
63975
|
+
env.HTTPS_PROXY = origin;
|
|
63976
|
+
env.HERMES_CA_BUNDLE = ca;
|
|
63977
|
+
if (routes.httpRewrites.length === 0 && routes.httpsDomains.length === 0) {
|
|
64112
63978
|
console.error(
|
|
64113
|
-
|
|
63979
|
+
"bili: no hermes providers found in ~/.hermes/config.yaml \u2014 traffic will NOT go through the proxy (configure a provider first)."
|
|
64114
63980
|
);
|
|
64115
63981
|
}
|
|
64116
63982
|
} else if (base === "dsh") {
|
|
@@ -64248,7 +64114,7 @@ async function runTestPi(params, deps = {}) {
|
|
|
64248
64114
|
}
|
|
64249
64115
|
|
|
64250
64116
|
// src/export.ts
|
|
64251
|
-
import { mkdirSync as
|
|
64117
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
64252
64118
|
import path16 from "path";
|
|
64253
64119
|
function fmtDate(ms2) {
|
|
64254
64120
|
return ms2 ? new Date(ms2).toISOString().replace("T", " ").slice(0, 19) + " UTC" : "\u2014";
|
|
@@ -64381,8 +64247,8 @@ async function exportSession(selector, opts = {}) {
|
|
|
64381
64247
|
}
|
|
64382
64248
|
const markdown = renderHandoff(matches[0], opts.full ?? false);
|
|
64383
64249
|
if (opts.output) {
|
|
64384
|
-
|
|
64385
|
-
|
|
64250
|
+
mkdirSync6(path16.dirname(path16.resolve(opts.output)), { recursive: true });
|
|
64251
|
+
writeFileSync5(opts.output, markdown, "utf8");
|
|
64386
64252
|
return `written to ${opts.output}`;
|
|
64387
64253
|
}
|
|
64388
64254
|
return markdown;
|
|
@@ -64459,7 +64325,7 @@ Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode / bili h
|
|
|
64459
64325
|
Options (override config file / env):
|
|
64460
64326
|
-F <url> upstream proxy to forward through (gost-style;
|
|
64461
64327
|
http://host:port; must precede the client name)
|
|
64462
|
-
--port <N> listen port (default
|
|
64328
|
+
--port <N> listen port (start: 8787; launcher default: random free port)
|
|
64463
64329
|
--host <ADDR> listen host (default 127.0.0.1)
|
|
64464
64330
|
--mitm-domain <domain> extra MITM domain (repeatable; launcher only)
|
|
64465
64331
|
--config <FILE> path to config JSON (default: XDG location)
|