billion-context 0.1.67 → 0.1.68-pr.360.258

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/index.js CHANGED
@@ -1141,14 +1141,14 @@ var require_util = __commonJS({
1141
1141
  }
1142
1142
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
1143
1143
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
1144
- let path16 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
1144
+ let path17 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
1145
1145
  if (origin[origin.length - 1] === "/") {
1146
1146
  origin = origin.slice(0, origin.length - 1);
1147
1147
  }
1148
- if (path16 && path16[0] !== "/") {
1149
- path16 = `/${path16}`;
1148
+ if (path17 && path17[0] !== "/") {
1149
+ path17 = `/${path17}`;
1150
1150
  }
1151
- return new URL(`${origin}${path16}`);
1151
+ return new URL(`${origin}${path17}`);
1152
1152
  }
1153
1153
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
1154
1154
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -1969,9 +1969,9 @@ var require_diagnostics = __commonJS({
1969
1969
  "undici:client:sendHeaders",
1970
1970
  (evt) => {
1971
1971
  const {
1972
- request: { method, path: path16, origin }
1972
+ request: { method, path: path17, origin }
1973
1973
  } = evt;
1974
- debugLog("sending request to %s %s%s", method, origin, path16);
1974
+ debugLog("sending request to %s %s%s", method, origin, path17);
1975
1975
  }
1976
1976
  );
1977
1977
  }
@@ -1989,14 +1989,14 @@ var require_diagnostics = __commonJS({
1989
1989
  "undici:request:headers",
1990
1990
  (evt) => {
1991
1991
  const {
1992
- request: { method, path: path16, origin },
1992
+ request: { method, path: path17, origin },
1993
1993
  response: { statusCode }
1994
1994
  } = evt;
1995
1995
  debugLog(
1996
1996
  "received response to %s %s%s - HTTP %d",
1997
1997
  method,
1998
1998
  origin,
1999
- path16,
1999
+ path17,
2000
2000
  statusCode
2001
2001
  );
2002
2002
  }
@@ -2005,23 +2005,23 @@ var require_diagnostics = __commonJS({
2005
2005
  "undici:request:trailers",
2006
2006
  (evt) => {
2007
2007
  const {
2008
- request: { method, path: path16, origin }
2008
+ request: { method, path: path17, origin }
2009
2009
  } = evt;
2010
- debugLog("trailers received from %s %s%s", method, origin, path16);
2010
+ debugLog("trailers received from %s %s%s", method, origin, path17);
2011
2011
  }
2012
2012
  );
2013
2013
  diagnosticsChannel.subscribe(
2014
2014
  "undici:request:error",
2015
2015
  (evt) => {
2016
2016
  const {
2017
- request: { method, path: path16, origin },
2017
+ request: { method, path: path17, origin },
2018
2018
  error
2019
2019
  } = evt;
2020
2020
  debugLog(
2021
2021
  "request to %s %s%s errored - %s",
2022
2022
  method,
2023
2023
  origin,
2024
- path16,
2024
+ path17,
2025
2025
  error.message
2026
2026
  );
2027
2027
  }
@@ -2136,7 +2136,7 @@ var require_request = __commonJS({
2136
2136
  var kHandler = /* @__PURE__ */ Symbol("handler");
2137
2137
  var Request = class {
2138
2138
  constructor(origin, {
2139
- path: path16,
2139
+ path: path17,
2140
2140
  method,
2141
2141
  body,
2142
2142
  headers,
@@ -2153,11 +2153,11 @@ var require_request = __commonJS({
2153
2153
  maxRedirections,
2154
2154
  typeOfService
2155
2155
  }, handler) {
2156
- if (typeof path16 !== "string") {
2156
+ if (typeof path17 !== "string") {
2157
2157
  throw new InvalidArgumentError("path must be a string");
2158
- } else if (path16[0] !== "/" && !(path16.startsWith("http://") || path16.startsWith("https://")) && method !== "CONNECT") {
2158
+ } else if (path17[0] !== "/" && !(path17.startsWith("http://") || path17.startsWith("https://")) && method !== "CONNECT") {
2159
2159
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
2160
- } else if (invalidPathRegex.test(path16)) {
2160
+ } else if (invalidPathRegex.test(path17)) {
2161
2161
  throw new InvalidArgumentError("invalid request path");
2162
2162
  }
2163
2163
  if (typeof method !== "string") {
@@ -2232,7 +2232,7 @@ var require_request = __commonJS({
2232
2232
  this.completed = false;
2233
2233
  this.aborted = false;
2234
2234
  this.upgrade = upgrade || null;
2235
- this.path = query ? serializePathWithQuery(path16, query) : path16;
2235
+ this.path = query ? serializePathWithQuery(path17, query) : path17;
2236
2236
  this.origin = origin;
2237
2237
  this.protocol = getProtocolFromUrlString(origin);
2238
2238
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -7415,7 +7415,7 @@ var require_client_h1 = __commonJS({
7415
7415
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
7416
7416
  }
7417
7417
  function writeH1(client, request) {
7418
- const { method, path: path16, host, upgrade, blocking, reset } = request;
7418
+ const { method, path: path17, host, upgrade, blocking, reset } = request;
7419
7419
  let { body, headers, contentLength } = request;
7420
7420
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
7421
7421
  if (util.isFormDataLike(body)) {
@@ -7493,7 +7493,7 @@ var require_client_h1 = __commonJS({
7493
7493
  if (socket.setTypeOfService) {
7494
7494
  socket.setTypeOfService(request.typeOfService);
7495
7495
  }
7496
- let header = `${method} ${path16} HTTP/1.1\r
7496
+ let header = `${method} ${path17} HTTP/1.1\r
7497
7497
  `;
7498
7498
  if (typeof host === "string") {
7499
7499
  header += `host: ${host}\r
@@ -8146,7 +8146,7 @@ var require_client_h2 = __commonJS({
8146
8146
  function writeH2(client, request) {
8147
8147
  const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout];
8148
8148
  const session = client[kHTTP2Session];
8149
- const { method, path: path16, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
8149
+ const { method, path: path17, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
8150
8150
  let { body } = request;
8151
8151
  if (upgrade != null && upgrade !== "websocket") {
8152
8152
  util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -8214,7 +8214,7 @@ var require_client_h2 = __commonJS({
8214
8214
  }
8215
8215
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
8216
8216
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
8217
- headers[HTTP2_HEADER_PATH] = path16;
8217
+ headers[HTTP2_HEADER_PATH] = path17;
8218
8218
  if (protocol === "ws:" || protocol === "wss:") {
8219
8219
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
8220
8220
  } else {
@@ -8255,7 +8255,7 @@ var require_client_h2 = __commonJS({
8255
8255
  stream2.setTimeout(requestTimeout);
8256
8256
  return true;
8257
8257
  }
8258
- headers[HTTP2_HEADER_PATH] = path16;
8258
+ headers[HTTP2_HEADER_PATH] = path17;
8259
8259
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
8260
8260
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
8261
8261
  if (body && typeof body.read === "function") {
@@ -10598,10 +10598,10 @@ var require_proxy_agent = __commonJS({
10598
10598
  };
10599
10599
  const {
10600
10600
  origin,
10601
- path: path16 = "/",
10601
+ path: path17 = "/",
10602
10602
  headers = {}
10603
10603
  } = opts;
10604
- opts.path = origin + path16;
10604
+ opts.path = origin + path17;
10605
10605
  if (!("host" in headers) && !("Host" in headers)) {
10606
10606
  const { host } = new URL(origin);
10607
10607
  headers.host = host;
@@ -12684,20 +12684,20 @@ var require_mock_utils = __commonJS({
12684
12684
  }
12685
12685
  return normalizedQp;
12686
12686
  }
12687
- function safeUrl(path16) {
12688
- if (typeof path16 !== "string") {
12689
- return path16;
12687
+ function safeUrl(path17) {
12688
+ if (typeof path17 !== "string") {
12689
+ return path17;
12690
12690
  }
12691
- const pathSegments = path16.split("?", 3);
12691
+ const pathSegments = path17.split("?", 3);
12692
12692
  if (pathSegments.length !== 2) {
12693
- return path16;
12693
+ return path17;
12694
12694
  }
12695
12695
  const qp = new URLSearchParams(pathSegments.pop());
12696
12696
  qp.sort();
12697
12697
  return [...pathSegments, qp.toString()].join("?");
12698
12698
  }
12699
- function matchKey(mockDispatch2, { path: path16, method, body, headers }) {
12700
- const pathMatch = matchValue(mockDispatch2.path, path16);
12699
+ function matchKey(mockDispatch2, { path: path17, method, body, headers }) {
12700
+ const pathMatch = matchValue(mockDispatch2.path, path17);
12701
12701
  const methodMatch = matchValue(mockDispatch2.method, method);
12702
12702
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
12703
12703
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -12722,8 +12722,8 @@ var require_mock_utils = __commonJS({
12722
12722
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
12723
12723
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
12724
12724
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
12725
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path16, ignoreTrailingSlash }) => {
12726
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path16)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path16), resolvedPath);
12725
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path17, ignoreTrailingSlash }) => {
12726
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path17)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path17), resolvedPath);
12727
12727
  });
12728
12728
  if (matchedMockDispatches.length === 0) {
12729
12729
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -12762,19 +12762,19 @@ var require_mock_utils = __commonJS({
12762
12762
  mockDispatches.splice(index, 1);
12763
12763
  }
12764
12764
  }
12765
- function removeTrailingSlash(path16) {
12766
- while (path16.endsWith("/")) {
12767
- path16 = path16.slice(0, -1);
12765
+ function removeTrailingSlash(path17) {
12766
+ while (path17.endsWith("/")) {
12767
+ path17 = path17.slice(0, -1);
12768
12768
  }
12769
- if (path16.length === 0) {
12770
- path16 = "/";
12769
+ if (path17.length === 0) {
12770
+ path17 = "/";
12771
12771
  }
12772
- return path16;
12772
+ return path17;
12773
12773
  }
12774
12774
  function buildKey(opts) {
12775
- const { path: path16, method, body, headers, query } = opts;
12775
+ const { path: path17, method, body, headers, query } = opts;
12776
12776
  return {
12777
- path: path16,
12777
+ path: path17,
12778
12778
  method,
12779
12779
  body,
12780
12780
  headers,
@@ -13464,10 +13464,10 @@ var require_pending_interceptors_formatter = __commonJS({
13464
13464
  }
13465
13465
  format(pendingInterceptors) {
13466
13466
  const withPrettyHeaders = pendingInterceptors.map(
13467
- ({ method, path: path16, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13467
+ ({ method, path: path17, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13468
13468
  Method: method,
13469
13469
  Origin: origin,
13470
- Path: path16,
13470
+ Path: path17,
13471
13471
  "Status code": statusCode,
13472
13472
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
13473
13473
  Invocations: timesInvoked,
@@ -13549,9 +13549,9 @@ var require_mock_agent = __commonJS({
13549
13549
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
13550
13550
  const dispatchOpts = { ...opts };
13551
13551
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
13552
- const [path16, searchParams] = dispatchOpts.path.split("?");
13552
+ const [path17, searchParams] = dispatchOpts.path.split("?");
13553
13553
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
13554
- dispatchOpts.path = `${path16}?${normalizedSearchParams}`;
13554
+ dispatchOpts.path = `${path17}?${normalizedSearchParams}`;
13555
13555
  }
13556
13556
  return this[kAgent].dispatch(dispatchOpts, handler);
13557
13557
  }
@@ -13952,12 +13952,12 @@ var require_snapshot_recorder = __commonJS({
13952
13952
  * @return {Promise<void>} - Resolves when snapshots are loaded
13953
13953
  */
13954
13954
  async loadSnapshots(filePath) {
13955
- const path16 = filePath || this.#snapshotPath;
13956
- if (!path16) {
13955
+ const path17 = filePath || this.#snapshotPath;
13956
+ if (!path17) {
13957
13957
  throw new InvalidArgumentError("Snapshot path is required");
13958
13958
  }
13959
13959
  try {
13960
- const data = await readFile3(resolve(path16), "utf8");
13960
+ const data = await readFile3(resolve(path17), "utf8");
13961
13961
  const parsed = JSON.parse(data);
13962
13962
  if (Array.isArray(parsed)) {
13963
13963
  this.#snapshots.clear();
@@ -13971,7 +13971,7 @@ var require_snapshot_recorder = __commonJS({
13971
13971
  if (error.code === "ENOENT") {
13972
13972
  this.#snapshots.clear();
13973
13973
  } else {
13974
- throw new UndiciError(`Failed to load snapshots from ${path16}`, { cause: error });
13974
+ throw new UndiciError(`Failed to load snapshots from ${path17}`, { cause: error });
13975
13975
  }
13976
13976
  }
13977
13977
  }
@@ -13982,11 +13982,11 @@ var require_snapshot_recorder = __commonJS({
13982
13982
  * @returns {Promise<void>} - Resolves when snapshots are saved
13983
13983
  */
13984
13984
  async saveSnapshots(filePath) {
13985
- const path16 = filePath || this.#snapshotPath;
13986
- if (!path16) {
13985
+ const path17 = filePath || this.#snapshotPath;
13986
+ if (!path17) {
13987
13987
  throw new InvalidArgumentError("Snapshot path is required");
13988
13988
  }
13989
- const resolvedPath = resolve(path16);
13989
+ const resolvedPath = resolve(path17);
13990
13990
  await mkdir3(dirname5(resolvedPath), { recursive: true });
13991
13991
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
13992
13992
  hash,
@@ -14618,15 +14618,15 @@ var require_redirect_handler = __commonJS({
14618
14618
  return;
14619
14619
  }
14620
14620
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
14621
- const path16 = search ? `${pathname}${search}` : pathname;
14622
- const redirectUrlString = `${origin}${path16}`;
14621
+ const path17 = search ? `${pathname}${search}` : pathname;
14622
+ const redirectUrlString = `${origin}${path17}`;
14623
14623
  for (const historyUrl of this.history) {
14624
14624
  if (historyUrl.toString() === redirectUrlString) {
14625
14625
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
14626
14626
  }
14627
14627
  }
14628
14628
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
14629
- this.opts.path = path16;
14629
+ this.opts.path = path17;
14630
14630
  this.opts.origin = origin;
14631
14631
  this.opts.query = null;
14632
14632
  }
@@ -14903,7 +14903,7 @@ var require_dns = __commonJS({
14903
14903
  "node_modules/undici/lib/interceptor/dns.js"(exports, module) {
14904
14904
  "use strict";
14905
14905
  var { isIP } = __require("net");
14906
- var { lookup } = __require("dns");
14906
+ var { lookup: lookup2 } = __require("dns");
14907
14907
  var DecoratorHandler = require_decorator_handler();
14908
14908
  var { InvalidArgumentError, InformationalError } = require_errors();
14909
14909
  var maxInt = Math.pow(2, 31) - 1;
@@ -15093,7 +15093,7 @@ var require_dns = __commonJS({
15093
15093
  }
15094
15094
  }
15095
15095
  #defaultLookup(origin, opts, cb) {
15096
- lookup(
15096
+ lookup2(
15097
15097
  origin.hostname,
15098
15098
  {
15099
15099
  all: true,
@@ -16395,10 +16395,10 @@ var require_cache_handler = __commonJS({
16395
16395
  }
16396
16396
  return locationUrl.pathname + locationUrl.search;
16397
16397
  }
16398
- function deleteCachedUri(store, cacheKey, path16) {
16398
+ function deleteCachedUri(store, cacheKey, path17) {
16399
16399
  deleteCachedValue(store, {
16400
16400
  ...cacheKey,
16401
- path: path16
16401
+ path: path17
16402
16402
  });
16403
16403
  for (let i = 0; i < util.safeHTTPMethods.length; i++) {
16404
16404
  const method = util.safeHTTPMethods[i];
@@ -16406,7 +16406,7 @@ var require_cache_handler = __commonJS({
16406
16406
  deleteCachedValue(store, {
16407
16407
  ...cacheKey,
16408
16408
  method,
16409
- path: path16
16409
+ path: path17
16410
16410
  });
16411
16411
  }
16412
16412
  }
@@ -16417,9 +16417,9 @@ var require_cache_handler = __commonJS({
16417
16417
  }
16418
16418
  const values = Array.isArray(headerValue3) ? headerValue3 : [headerValue3];
16419
16419
  for (let i = 0; i < values.length; i++) {
16420
- const path16 = getSameOriginPath(cacheKey, values[i]);
16421
- if (path16 !== void 0) {
16422
- deleteCachedUri(store, cacheKey, path16);
16420
+ const path17 = getSameOriginPath(cacheKey, values[i]);
16421
+ if (path17 !== void 0) {
16422
+ deleteCachedUri(store, cacheKey, path17);
16423
16423
  }
16424
16424
  }
16425
16425
  }
@@ -21297,11 +21297,11 @@ var require_fetch = __commonJS({
21297
21297
  function dispatch({ body }) {
21298
21298
  const url = requestCurrentURL(request);
21299
21299
  const agent = fetchParams.controller.dispatcher;
21300
- const path16 = url.pathname + url.search;
21300
+ const path17 = url.pathname + url.search;
21301
21301
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
21302
21302
  return new Promise((resolve, reject) => agent.dispatch(
21303
21303
  {
21304
- path: hasTrailingQuestionMark ? `${path16}?` : path16,
21304
+ path: hasTrailingQuestionMark ? `${path17}?` : path17,
21305
21305
  origin: url.origin,
21306
21306
  method: request.method,
21307
21307
  body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
@@ -22248,9 +22248,9 @@ var require_util4 = __commonJS({
22248
22248
  }
22249
22249
  }
22250
22250
  }
22251
- function validateCookiePath(path16) {
22252
- for (let i = 0; i < path16.length; ++i) {
22253
- const code = path16.charCodeAt(i);
22251
+ function validateCookiePath(path17) {
22252
+ for (let i = 0; i < path17.length; ++i) {
22253
+ const code = path17.charCodeAt(i);
22254
22254
  if (code < 32 || // exclude CTLs (0-31)
22255
22255
  code > 126 || // exclude DEL and non-ascii
22256
22256
  code === 59) {
@@ -25487,11 +25487,11 @@ var require_undici = __commonJS({
25487
25487
  if (typeof opts.path !== "string") {
25488
25488
  throw new InvalidArgumentError("invalid opts.path");
25489
25489
  }
25490
- let path16 = opts.path;
25490
+ let path17 = opts.path;
25491
25491
  if (!opts.path.startsWith("/")) {
25492
- path16 = `/${path16}`;
25492
+ path17 = `/${path17}`;
25493
25493
  }
25494
- url = new URL(util.parseOrigin(url).origin + path16);
25494
+ url = new URL(util.parseOrigin(url).origin + path17);
25495
25495
  } else {
25496
25496
  if (!opts) {
25497
25497
  opts = typeof url === "object" ? url : {};
@@ -47033,9 +47033,6 @@ function stateDir() {
47033
47033
  function defaultLogFile() {
47034
47034
  return path.join(stateDir(), "bili.log");
47035
47035
  }
47036
- function proxyOriginFile() {
47037
- return path.join(stateDir(), "proxy-origin");
47038
- }
47039
47036
  function caDir() {
47040
47037
  return path.join(dataDir(), "ca");
47041
47038
  }
@@ -47622,13 +47619,13 @@ function getUpstreamConnectionStatus() {
47622
47619
  }
47623
47620
 
47624
47621
  // src/config.ts
47625
- function safeReadJson(path16) {
47622
+ function safeReadJson(path17) {
47626
47623
  try {
47627
- const raw = readFileSync(path16, "utf8").replace(/^\uFEFF/, "");
47624
+ const raw = readFileSync(path17, "utf8").replace(/^\uFEFF/, "");
47628
47625
  return JSON.parse(raw);
47629
47626
  } catch (e) {
47630
47627
  if (e.code !== "ENOENT") {
47631
- log("error", `[acp-config] failed to parse ${path16}: ${String(e)}`);
47628
+ log("error", `[acp-config] failed to parse ${path17}: ${String(e)}`);
47632
47629
  }
47633
47630
  return void 0;
47634
47631
  }
@@ -47908,8 +47905,8 @@ function rejectLegacyRoute(key, value) {
47908
47905
 
47909
47906
  // src/server.ts
47910
47907
  import http from "http";
47911
- import fs6 from "fs";
47912
- import { randomUUID as randomUUID3 } from "crypto";
47908
+ import fs7 from "fs";
47909
+ import { randomUUID as randomUUID4 } from "crypto";
47913
47910
 
47914
47911
  // src/compress-settings.ts
47915
47912
  function resolveContextLimitValue(raw, nativeLimit) {
@@ -50158,15 +50155,11 @@ function resolveDecompress(args, ctx) {
50158
50155
  body = view.text;
50159
50156
  count = view.count;
50160
50157
  } else {
50161
- const collected = collectBlockContent(ctx.session.state, block, ctx.messages, { full });
50158
+ const collected = collectBlockContent(ctx.session.state, block, ctx.compressMessages ?? ctx.messages, { full });
50162
50159
  body = collected.text || block.summary;
50163
50160
  count = collected.count;
50164
50161
  }
50165
- if (count > 0 || cached) {
50166
- ctx.session.state = deactivateBlock(ctx.session.state, [blockId]);
50167
- ctx.session.blockContents.delete(blockId);
50168
- }
50169
- const header = `[Restored block ${blockId} \u2014 ${count} item(s)${full ? ", full" : ""}]`;
50162
+ const header = `[Block ${blockId} content \u2014 ${count} item(s)${full ? ", full" : ""}]`;
50170
50163
  const safeBlockId = blockId.replace(/[^a-zA-Z0-9_-]/g, "-");
50171
50164
  const outPath = body.length > 1e4 ? join2(tmpdir(), `acp-decompress-${safeBlockId}-${Date.now()}.txt`) : null;
50172
50165
  if (outPath) {
@@ -51151,6 +51144,140 @@ function reapOrphanBlocks(session, visible, deactivate) {
51151
51144
  return { reaped };
51152
51145
  }
51153
51146
 
51147
+ // src/instance.ts
51148
+ import { randomUUID as randomUUID3 } from "crypto";
51149
+ import fs3 from "fs";
51150
+ import path7 from "path";
51151
+ function isProxyInstanceFile(v2) {
51152
+ return v2 !== void 0 && "instanceId" in v2;
51153
+ }
51154
+ function readProxyInstanceFile(file) {
51155
+ let raw;
51156
+ try {
51157
+ raw = fs3.readFileSync(file ?? instanceFilePath(), "utf8").trim();
51158
+ } catch {
51159
+ return void 0;
51160
+ }
51161
+ if (raw.startsWith("{")) {
51162
+ try {
51163
+ const parsed = JSON.parse(raw);
51164
+ if (typeof parsed.origin === "string" && /^https?:\/\/\S+$/.test(parsed.origin)) {
51165
+ const windows = {};
51166
+ if (parsed.modelWindows && typeof parsed.modelWindows === "object") {
51167
+ for (const [k2, v2] of Object.entries(parsed.modelWindows)) {
51168
+ const n = Number(v2);
51169
+ if (Number.isFinite(n) && n > 0) windows[k2] = n;
51170
+ }
51171
+ }
51172
+ return {
51173
+ origin: parsed.origin,
51174
+ instanceId: typeof parsed.instanceId === "string" ? parsed.instanceId : "",
51175
+ pid: typeof parsed.pid === "number" ? parsed.pid : 0,
51176
+ startedAt: typeof parsed.startedAt === "number" ? parsed.startedAt : 0,
51177
+ host: typeof parsed.host === "string" ? parsed.host : "",
51178
+ port: typeof parsed.port === "number" ? parsed.port : 0,
51179
+ passthrough: Boolean(parsed.passthrough),
51180
+ mitmDomains: Array.isArray(parsed.mitmDomains) ? parsed.mitmDomains.map(String) : [],
51181
+ modelWindows: windows,
51182
+ launchToken: typeof parsed.launchToken === "string" ? parsed.launchToken : void 0
51183
+ };
51184
+ }
51185
+ } catch {
51186
+ }
51187
+ }
51188
+ if (/^https?:\/\/\S+$/.test(raw)) return { origin: raw };
51189
+ return void 0;
51190
+ }
51191
+ function instanceFilePath() {
51192
+ return path7.join(stateDir(), "proxy-origin");
51193
+ }
51194
+ function atomicWriteInstanceFile(info, file) {
51195
+ const filePath = file ?? instanceFilePath();
51196
+ fs3.mkdirSync(path7.dirname(filePath), { recursive: true });
51197
+ const tempPath = `${filePath}.${process.pid}.${randomUUID3()}.tmp`;
51198
+ let descriptor;
51199
+ try {
51200
+ descriptor = fs3.openSync(tempPath, "wx", 420);
51201
+ fs3.writeSync(descriptor, JSON.stringify(info) + "\n", null, "utf8");
51202
+ fs3.fsyncSync(descriptor);
51203
+ fs3.closeSync(descriptor);
51204
+ descriptor = void 0;
51205
+ fs3.renameSync(tempPath, filePath);
51206
+ } catch (error) {
51207
+ if (descriptor !== void 0) {
51208
+ try {
51209
+ fs3.closeSync(descriptor);
51210
+ } catch {
51211
+ }
51212
+ }
51213
+ try {
51214
+ fs3.unlinkSync(tempPath);
51215
+ } catch {
51216
+ }
51217
+ throw error;
51218
+ }
51219
+ }
51220
+ function clearProxyInstanceFile(instanceId, file) {
51221
+ const filePath = file ?? instanceFilePath();
51222
+ const current = readProxyInstanceFile(filePath);
51223
+ if (isProxyInstanceFile(current) && current.instanceId === instanceId) {
51224
+ try {
51225
+ fs3.unlinkSync(filePath);
51226
+ } catch {
51227
+ }
51228
+ }
51229
+ }
51230
+ function isPidAlive(pid) {
51231
+ if (!Number.isInteger(pid) || pid <= 0) return false;
51232
+ try {
51233
+ process.kill(pid, 0);
51234
+ return true;
51235
+ } catch (err2) {
51236
+ return err2.code === "EPERM";
51237
+ }
51238
+ }
51239
+ function registryFilePath() {
51240
+ return path7.join(stateDir(), "instances.json");
51241
+ }
51242
+ function registerInstanceAndWarn(entry, warn) {
51243
+ const file = registryFilePath();
51244
+ const entries = [];
51245
+ try {
51246
+ const parsed = JSON.parse(fs3.readFileSync(file, "utf8"));
51247
+ if (Array.isArray(parsed.instances)) {
51248
+ for (const e of parsed.instances) {
51249
+ if (e && typeof e.instanceId === "string" && e.instanceId !== entry.instanceId && isPidAlive(e.pid)) {
51250
+ entries.push(e);
51251
+ }
51252
+ }
51253
+ }
51254
+ } catch {
51255
+ }
51256
+ for (const other of entries) {
51257
+ warn(
51258
+ `another bili instance is running (pid ${other.pid}, ${other.origin}) \u2014 both processes will write the same sessions directory; stop one to avoid state pollution (#394)`
51259
+ );
51260
+ }
51261
+ entries.push(entry);
51262
+ try {
51263
+ fs3.mkdirSync(path7.dirname(file), { recursive: true });
51264
+ fs3.writeFileSync(file, JSON.stringify({ instances: entries }) + "\n");
51265
+ } catch {
51266
+ }
51267
+ }
51268
+ function unregisterInstance(instanceId) {
51269
+ const file = registryFilePath();
51270
+ try {
51271
+ const parsed = JSON.parse(fs3.readFileSync(file, "utf8"));
51272
+ if (!Array.isArray(parsed.instances)) return;
51273
+ const kept = parsed.instances.filter(
51274
+ (e) => !(e && typeof e.instanceId === "string" && e.instanceId === instanceId) && isPidAlive(e.pid)
51275
+ );
51276
+ fs3.writeFileSync(file, JSON.stringify({ instances: kept }) + "\n");
51277
+ } catch {
51278
+ }
51279
+ }
51280
+
51154
51281
  // src/compress-loop.ts
51155
51282
  function buildVisibilityMarker(toolName, result) {
51156
51283
  const lines = result.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
@@ -51469,11 +51596,11 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
51469
51596
  let newBody = adapter.buildRequest(coreMessages, systemPrompt, requestBody);
51470
51597
  if (process.env.ACP_DUMP_BODY === "1") {
51471
51598
  try {
51472
- const fs11 = await import("fs");
51599
+ const fs12 = await import("fs");
51473
51600
  const dumpDir = process.env.ACP_DUMP_DIR || `${process.env.HOME}/.local/state/billion-context/dumps`;
51474
- fs11.mkdirSync(dumpDir, { recursive: true });
51601
+ fs12.mkdirSync(dumpDir, { recursive: true });
51475
51602
  const sid = ctx.session.id ?? "unknown";
51476
- fs11.writeFileSync(`${dumpDir}/req-${Date.now()}-${sid}-REREQUEST.json`, JSON.stringify(newBody, null, 2));
51603
+ fs12.writeFileSync(`${dumpDir}/req-${Date.now()}-${sid}-REREQUEST.json`, JSON.stringify(newBody, null, 2));
51477
51604
  } catch {
51478
51605
  }
51479
51606
  }
@@ -51591,25 +51718,18 @@ function reserveOutputHeadroom(window2, maxOutput) {
51591
51718
  }
51592
51719
  return window2;
51593
51720
  }
51594
- function hoistMidSystemMessages(messages) {
51595
- let lead = 0;
51596
- while (lead < messages.length && (messages[lead].role === "system" || messages[lead].role === "developer")) lead++;
51597
- if (lead === messages.length) return messages;
51598
- let midCount = 0;
51599
- for (let i = lead; i < messages.length; i++) {
51600
- const r = messages[i].role;
51601
- if (r === "system" || r === "developer") midCount++;
51602
- }
51603
- if (midCount === 0) return messages;
51604
- const head = messages.slice(0, lead);
51605
- const mid = [];
51606
- const rest = [];
51607
- for (let i = lead; i < messages.length; i++) {
51608
- const r = messages[i].role;
51609
- if (r === "system" || r === "developer") mid.push(messages[i]);
51610
- else rest.push(messages[i]);
51611
- }
51612
- return [...head, ...mid, ...rest];
51721
+ function systemToUser(messages) {
51722
+ let hasSys = false;
51723
+ for (const m2 of messages) {
51724
+ if (m2.role === "system" || m2.role === "developer") {
51725
+ hasSys = true;
51726
+ break;
51727
+ }
51728
+ }
51729
+ if (!hasSys) return messages;
51730
+ return messages.map(
51731
+ (m2) => m2.role === "system" || m2.role === "developer" ? { ...m2, role: "user" } : m2
51732
+ );
51613
51733
  }
51614
51734
  function shouldReserveOutputHeadroom(protocol) {
51615
51735
  return protocol !== "anthropic";
@@ -52272,7 +52392,7 @@ function createOpenaiAdapter(requestBody, clientSystem) {
52272
52392
  );
52273
52393
  return {
52274
52394
  buildRequest(coreMessages, systemPrompt, body) {
52275
- const messages = hoistMidSystemMessages(coreToOpenai(coreMessages));
52395
+ const messages = systemToUser(coreToOpenai(coreMessages));
52276
52396
  const withSys = injectOpenaiSystem(messages, [clientSystem, systemPrompt].filter((p2) => typeof p2 === "string" && p2.length > 0));
52277
52397
  return { ...body, messages: withSys };
52278
52398
  },
@@ -53022,6 +53142,65 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
53022
53142
  return current;
53023
53143
  }
53024
53144
 
53145
+ // src/acp-panel.ts
53146
+ var PANEL_BOX_TOP = "\u256D";
53147
+ var PANEL_BOX_TITLE = "ACP Context Analysis";
53148
+ var PANEL_FALLBACK_HEADER = "\u{1F4CA} ACP status";
53149
+ function isAcpPanelText(text) {
53150
+ const t = text.trim();
53151
+ if (t.length === 0) return false;
53152
+ if (t.startsWith(PANEL_BOX_TOP) && t.includes(PANEL_BOX_TITLE)) return true;
53153
+ if (t.startsWith(PANEL_FALLBACK_HEADER)) return true;
53154
+ return false;
53155
+ }
53156
+ function messageText(content) {
53157
+ if (typeof content === "string") return content;
53158
+ if (Array.isArray(content)) {
53159
+ let joined = "";
53160
+ for (const part of content) {
53161
+ const p2 = part;
53162
+ if (p2 === null || typeof p2 !== "object") return void 0;
53163
+ const pt2 = p2.type;
53164
+ if (pt2 !== void 0 && pt2 !== "text" && pt2 !== "input_text" && pt2 !== "output_text") return void 0;
53165
+ if (typeof p2.text === "string") joined += p2.text;
53166
+ }
53167
+ return joined;
53168
+ }
53169
+ return void 0;
53170
+ }
53171
+ function stripAcpPanelMessages(messages) {
53172
+ if (!Array.isArray(messages)) return 0;
53173
+ let stripped = 0;
53174
+ for (let i = messages.length - 1; i >= 0; i--) {
53175
+ const rec = messages[i];
53176
+ if (rec === null || typeof rec !== "object") continue;
53177
+ if (rec.role !== "user") continue;
53178
+ const text = messageText(rec.content);
53179
+ if (text !== void 0 && isAcpPanelText(text)) {
53180
+ messages.splice(i, 1);
53181
+ stripped++;
53182
+ }
53183
+ }
53184
+ return stripped;
53185
+ }
53186
+ function stripAcpPanelResponsesInput(input) {
53187
+ if (!Array.isArray(input)) return 0;
53188
+ let stripped = 0;
53189
+ for (let i = input.length - 1; i >= 0; i--) {
53190
+ const rec = input[i];
53191
+ if (rec === null || typeof rec !== "object") continue;
53192
+ const type = rec.type;
53193
+ if (type !== "message" && type !== void 0) continue;
53194
+ if (rec.role !== "user") continue;
53195
+ const text = messageText(rec.content);
53196
+ if (text !== void 0 && isAcpPanelText(text)) {
53197
+ input.splice(i, 1);
53198
+ stripped++;
53199
+ }
53200
+ }
53201
+ return stripped;
53202
+ }
53203
+
53025
53204
  // src/stream-openai.ts
53026
53205
  function rewriteOpenaiJsonResponse(body, ctx) {
53027
53206
  if (!body || typeof body !== "object") return body;
@@ -53630,13 +53809,13 @@ function buildStatusPanel(input) {
53630
53809
 
53631
53810
  // src/plugin.ts
53632
53811
  import { fileURLToPath as fileURLToPath2 } from "url";
53633
- import fs3 from "fs";
53634
- import path7 from "path";
53812
+ import fs4 from "fs";
53813
+ import path8 from "path";
53635
53814
  var PROXY_VERSION = (() => {
53636
53815
  try {
53637
53816
  const here = fileURLToPath2(import.meta.url);
53638
- const pkg = path7.join(path7.dirname(here), "..", "package.json");
53639
- return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
53817
+ const pkg = path8.join(path8.dirname(here), "..", "package.json");
53818
+ return JSON.parse(fs4.readFileSync(pkg, "utf8")).version ?? "dev";
53640
53819
  } catch {
53641
53820
  return "dev";
53642
53821
  }
@@ -53648,8 +53827,8 @@ var PLUGIN_PROTOCOL_VERSION = 1;
53648
53827
  var VERSION = (() => {
53649
53828
  try {
53650
53829
  const here = fileURLToPath2(import.meta.url);
53651
- const pkg = path7.join(path7.dirname(here), "..", "package.json");
53652
- return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
53830
+ const pkg = path8.join(path8.dirname(here), "..", "package.json");
53831
+ return JSON.parse(fs4.readFileSync(pkg, "utf8")).version ?? "dev";
53653
53832
  } catch {
53654
53833
  return "dev";
53655
53834
  }
@@ -53678,14 +53857,20 @@ function pluginReportedContextWindow(headers) {
53678
53857
  var MAX_PLUGIN_CONVERSATIONS = 1024;
53679
53858
  var conversations = /* @__PURE__ */ new Map();
53680
53859
  var remembered = /* @__PURE__ */ new Map();
53681
- var conversationsFile = () => path7.join(stateDir(), "plugin-conversations.json");
53860
+ var conversationsFile = () => path8.join(stateDir(), "plugin-conversations.json");
53682
53861
  var conversationsSaveTimer;
53862
+ var conversationsDirty = false;
53683
53863
  function writeConversationsFile() {
53864
+ if (!conversationsDirty) return;
53684
53865
  try {
53685
53866
  const obj = {};
53686
53867
  for (const [k2, v2] of conversations) obj[k2] = v2;
53687
- fs3.mkdirSync(stateDir(), { recursive: true });
53688
- fs3.writeFileSync(conversationsFile(), JSON.stringify(obj));
53868
+ fs4.mkdirSync(stateDir(), { recursive: true });
53869
+ const filePath = conversationsFile();
53870
+ const draft = `${filePath}.${process.pid}.bili-tmp`;
53871
+ fs4.writeFileSync(draft, JSON.stringify(obj));
53872
+ fs4.renameSync(draft, filePath);
53873
+ conversationsDirty = false;
53689
53874
  } catch {
53690
53875
  }
53691
53876
  }
@@ -53704,8 +53889,13 @@ function flushConversations() {
53704
53889
  writeConversationsFile();
53705
53890
  }
53706
53891
  function loadConversations() {
53892
+ let raw;
53893
+ try {
53894
+ raw = fs4.readFileSync(conversationsFile(), "utf8");
53895
+ } catch {
53896
+ return;
53897
+ }
53707
53898
  try {
53708
- const raw = fs3.readFileSync(conversationsFile(), "utf8");
53709
53899
  const obj = JSON.parse(raw);
53710
53900
  for (const [k2, v2] of Object.entries(obj)) {
53711
53901
  if (v2 && typeof v2.sessionId === "string" && v2.sessionId.length > 0) {
@@ -53713,11 +53903,18 @@ function loadConversations() {
53713
53903
  }
53714
53904
  }
53715
53905
  } catch {
53906
+ try {
53907
+ fs4.renameSync(conversationsFile(), `${conversationsFile()}.corrupt-${Date.now()}`);
53908
+ } catch {
53909
+ }
53910
+ log("warn", "[plugin] plugin-conversations.json is corrupt \u2014 backed up beside the original, starting an empty routing table");
53716
53911
  }
53912
+ conversationsDirty = false;
53717
53913
  }
53718
53914
  function recordPluginSession(conversationId2, sessionId) {
53719
53915
  conversations.delete(conversationId2);
53720
53916
  conversations.set(conversationId2, { sessionId, lastSeen: Date.now() });
53917
+ conversationsDirty = true;
53721
53918
  if (conversations.size > MAX_PLUGIN_CONVERSATIONS) {
53722
53919
  const oldest = conversations.keys().next().value;
53723
53920
  if (oldest !== void 0) conversations.delete(oldest);
@@ -54167,14 +54364,14 @@ async function pipePluginJson(stream2, res, session, protocol) {
54167
54364
  import tls3 from "tls";
54168
54365
 
54169
54366
  // src/discover.ts
54170
- import fs5 from "fs";
54367
+ import fs6 from "fs";
54171
54368
  import os2 from "os";
54172
- import path9 from "path";
54369
+ import path10 from "path";
54173
54370
 
54174
54371
  // src/client-config.ts
54175
- import fs4 from "fs";
54372
+ import fs5 from "fs";
54176
54373
  import os from "os";
54177
- import path8 from "path";
54374
+ import path9 from "path";
54178
54375
  function toModelWindow(id, contextWindow) {
54179
54376
  return typeof id === "string" && id.length > 0 && typeof contextWindow === "number" && Number.isFinite(contextWindow) && contextWindow > 0 ? { id, contextWindow: Math.floor(contextWindow) } : null;
54180
54377
  }
@@ -54183,7 +54380,7 @@ function nonEmpty2(s3) {
54183
54380
  }
54184
54381
  function readJsonObject(filePath) {
54185
54382
  try {
54186
- const txt = fs4.readFileSync(filePath, "utf8");
54383
+ const txt = fs5.readFileSync(filePath, "utf8");
54187
54384
  const parsed = JSON.parse(txt);
54188
54385
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
54189
54386
  } catch {
@@ -54192,19 +54389,19 @@ function readJsonObject(filePath) {
54192
54389
  }
54193
54390
  function resolvePiHome(env) {
54194
54391
  const h = os.homedir();
54195
- return nonEmpty2(env.PI_CODING_AGENT_DIR) ? env.PI_CODING_AGENT_DIR : nonEmpty2(env.PI_HOME) ? env.PI_HOME : path8.join(h, ".pi", "agent");
54392
+ return nonEmpty2(env.PI_CODING_AGENT_DIR) ? env.PI_CODING_AGENT_DIR : nonEmpty2(env.PI_HOME) ? env.PI_HOME : path9.join(h, ".pi", "agent");
54196
54393
  }
54197
54394
  function resolveOmpHome(env) {
54198
54395
  const h = os.homedir();
54199
- return nonEmpty2(env.PI_CODING_AGENT_DIR) ? env.PI_CODING_AGENT_DIR : path8.join(h, ".omp", "agent");
54396
+ return nonEmpty2(env.PI_CODING_AGENT_DIR) ? env.PI_CODING_AGENT_DIR : path9.join(h, ".omp", "agent");
54200
54397
  }
54201
54398
  function resolveHermesHome(env) {
54202
54399
  const h = os.homedir();
54203
- return nonEmpty2(env.HERMES_HOME) ? env.HERMES_HOME : path8.join(h, ".hermes");
54400
+ return nonEmpty2(env.HERMES_HOME) ? env.HERMES_HOME : path9.join(h, ".hermes");
54204
54401
  }
54205
54402
  function resolveDshHome(env) {
54206
54403
  const h = os.homedir();
54207
- return nonEmpty2(env.DSH_HOME) ? env.DSH_HOME : path8.join(h, ".dsh");
54404
+ return nonEmpty2(env.DSH_HOME) ? env.DSH_HOME : path9.join(h, ".dsh");
54208
54405
  }
54209
54406
  function parseDshSettingsYaml(text) {
54210
54407
  const out = [];
@@ -54223,7 +54420,7 @@ function parseDshSettingsYaml(text) {
54223
54420
  function readDshConfig(dshHome) {
54224
54421
  let text;
54225
54422
  try {
54226
- text = fs4.readFileSync(path8.join(dshHome, "settings.yaml"), "utf8");
54423
+ text = fs5.readFileSync(path9.join(dshHome, "settings.yaml"), "utf8");
54227
54424
  } catch {
54228
54425
  return { baseUrls: [] };
54229
54426
  }
@@ -54231,8 +54428,8 @@ function readDshConfig(dshHome) {
54231
54428
  }
54232
54429
  function readClaudeSettings(homeDir, cwd, env = process.env) {
54233
54430
  const files = [
54234
- path8.join(homeDir, ".claude", "settings.json"),
54235
- path8.join(cwd, ".claude", "settings.json")
54431
+ path9.join(homeDir, ".claude", "settings.json"),
54432
+ path9.join(cwd, ".claude", "settings.json")
54236
54433
  ];
54237
54434
  let anthropicBaseUrl;
54238
54435
  let model;
@@ -54305,17 +54502,17 @@ function parseCodexToml(text) {
54305
54502
  return result;
54306
54503
  }
54307
54504
  function readCodexConfig(codexHome) {
54308
- const cfgPath = path8.join(codexHome, "config.toml");
54505
+ const cfgPath = path9.join(codexHome, "config.toml");
54309
54506
  let text;
54310
54507
  try {
54311
- text = fs4.readFileSync(cfgPath, "utf8");
54508
+ text = fs5.readFileSync(cfgPath, "utf8");
54312
54509
  } catch {
54313
54510
  return { providers: {} };
54314
54511
  }
54315
54512
  return parseCodexToml(text);
54316
54513
  }
54317
54514
  function readPiConfig(piHome) {
54318
- const cfgPath = path8.join(piHome, "models.json");
54515
+ const cfgPath = path9.join(piHome, "models.json");
54319
54516
  const obj = readJsonObject(cfgPath);
54320
54517
  const providers = {};
54321
54518
  const rawProviders = obj?.providers;
@@ -54396,10 +54593,10 @@ function parseOmpYaml(text) {
54396
54593
  return result;
54397
54594
  }
54398
54595
  function readOmpConfig(ompHome) {
54399
- const cfgPath = path8.join(ompHome, "models.yml");
54596
+ const cfgPath = path9.join(ompHome, "models.yml");
54400
54597
  let text;
54401
54598
  try {
54402
- text = fs4.readFileSync(cfgPath, "utf8");
54599
+ text = fs5.readFileSync(cfgPath, "utf8");
54403
54600
  } catch {
54404
54601
  return { providers: {} };
54405
54602
  }
@@ -54472,10 +54669,10 @@ function parseHermesYaml(text) {
54472
54669
  return result;
54473
54670
  }
54474
54671
  function readHermesConfig(hermesHome) {
54475
- const cfgPath = path8.join(hermesHome, "config.yaml");
54672
+ const cfgPath = path9.join(hermesHome, "config.yaml");
54476
54673
  let text;
54477
54674
  try {
54478
- text = fs4.readFileSync(cfgPath, "utf8");
54675
+ text = fs5.readFileSync(cfgPath, "utf8");
54479
54676
  } catch {
54480
54677
  return { providers: {} };
54481
54678
  }
@@ -54483,13 +54680,13 @@ function readHermesConfig(hermesHome) {
54483
54680
  }
54484
54681
  function resolveOpencodeConfigFile(env) {
54485
54682
  if (nonEmpty2(env.OPENCODE_CONFIG)) return env.OPENCODE_CONFIG;
54486
- const xdg2 = nonEmpty2(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path8.join(os.homedir(), ".config");
54487
- return path8.join(xdg2, "opencode", "opencode.json");
54683
+ const xdg2 = nonEmpty2(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path9.join(os.homedir(), ".config");
54684
+ return path9.join(xdg2, "opencode", "opencode.json");
54488
54685
  }
54489
54686
  function readOpencodeConfig(file) {
54490
54687
  let text;
54491
54688
  try {
54492
- text = fs4.readFileSync(file, "utf8");
54689
+ text = fs5.readFileSync(file, "utf8");
54493
54690
  } catch {
54494
54691
  return { providers: {} };
54495
54692
  }
@@ -54546,10 +54743,10 @@ function parseZcodeConfig(obj) {
54546
54743
  return result;
54547
54744
  }
54548
54745
  function readZcodeConfig(zcodeHome) {
54549
- const cfgPath = path8.join(zcodeHome, "v2", "config.json");
54746
+ const cfgPath = path9.join(zcodeHome, "v2", "config.json");
54550
54747
  let txt;
54551
54748
  try {
54552
- txt = fs4.readFileSync(cfgPath, "utf8");
54749
+ txt = fs5.readFileSync(cfgPath, "utf8");
54553
54750
  } catch {
54554
54751
  return { providers: {} };
54555
54752
  }
@@ -54565,10 +54762,10 @@ function loadClientConfig(env, cwd) {
54565
54762
  const home = os.homedir();
54566
54763
  const config = {};
54567
54764
  config.claude = readClaudeSettings(home, cwd, env);
54568
- const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path8.join(home, ".codex");
54765
+ const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path9.join(home, ".codex");
54569
54766
  config.codex = readCodexConfig(codexHome);
54570
54767
  config.pi = readPiConfig(resolvePiHome(env));
54571
- const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path8.join(home, ".zcode");
54768
+ const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path9.join(home, ".zcode");
54572
54769
  config.zcode = readZcodeConfig(zcodeHome);
54573
54770
  config.omp = readOmpConfig(resolveOmpHome(env));
54574
54771
  config.opencode = readOpencodeConfig(resolveOpencodeConfigFile(env));
@@ -54628,21 +54825,21 @@ function extractHttpsHosts(config) {
54628
54825
  }
54629
54826
  function configFilePaths(env) {
54630
54827
  const home = os2.homedir();
54631
- const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path9.join(home, ".codex");
54632
- const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path9.join(home, ".zcode");
54828
+ const codexHome = nonEmpty2(env.CODEX_HOME) ? env.CODEX_HOME : path10.join(home, ".codex");
54829
+ const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path10.join(home, ".zcode");
54633
54830
  return [
54634
- path9.join(home, ".claude", "settings.json"),
54635
- path9.join(process.cwd(), ".claude", "settings.json"),
54636
- path9.join(codexHome, "config.toml"),
54637
- path9.join(resolvePiHome(env), "models.json"),
54638
- path9.join(zcodeHome, "v2", "config.json")
54831
+ path10.join(home, ".claude", "settings.json"),
54832
+ path10.join(process.cwd(), ".claude", "settings.json"),
54833
+ path10.join(codexHome, "config.toml"),
54834
+ path10.join(resolvePiHome(env), "models.json"),
54835
+ path10.join(zcodeHome, "v2", "config.json")
54639
54836
  ];
54640
54837
  }
54641
54838
  function readMtimes(paths) {
54642
54839
  const mtimes = /* @__PURE__ */ new Map();
54643
54840
  for (const p2 of paths) {
54644
54841
  try {
54645
- const st2 = fs5.statSync(p2);
54842
+ const st2 = fs6.statSync(p2);
54646
54843
  mtimes.set(p2, st2.mtimeMs);
54647
54844
  } catch {
54648
54845
  }
@@ -54810,6 +55007,108 @@ function readMitmUpstream(socket) {
54810
55007
  return socket[MITM_UPSTREAM_KEY];
54811
55008
  }
54812
55009
 
55010
+ // src/tunnel-guard.ts
55011
+ import { lookup } from "dns/promises";
55012
+ import { networkInterfaces } from "os";
55013
+ var BILI_TUNNEL_HEADER = "x-bili-tunnel";
55014
+ function parseIpLiteral(s3) {
55015
+ const t = s3.trim().toLowerCase();
55016
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(t)) return t;
55017
+ if (t.includes(":")) return t;
55018
+ return null;
55019
+ }
55020
+ function classifyIp(ip) {
55021
+ const lit = parseIpLiteral(ip);
55022
+ if (!lit) return "public";
55023
+ if (lit.includes(":")) {
55024
+ if (lit === "::1" || lit === "::") return "loopback";
55025
+ const mapped = lit.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
55026
+ if (mapped) return classifyIp(mapped[1]);
55027
+ if (lit.startsWith("fe8") || lit.startsWith("fe9") || lit.startsWith("fea") || lit.startsWith("feb")) return "linkLocal";
55028
+ if (lit.startsWith("fc") || lit.startsWith("fd")) return "private";
55029
+ return "public";
55030
+ }
55031
+ const parts = lit.split(".").map(Number);
55032
+ const [a, b2] = parts;
55033
+ if (a === 127) return "loopback";
55034
+ if (a === 169 && b2 === 254) return "linkLocal";
55035
+ if (a === 10 || a === 0) return "private";
55036
+ if (a === 172 && b2 >= 16 && b2 <= 31) return "private";
55037
+ if (a === 192 && b2 === 168) return "private";
55038
+ if (a === 100 && b2 >= 64 && b2 <= 127) return "private";
55039
+ return "public";
55040
+ }
55041
+ var dnsResolveHost = async (host) => {
55042
+ const res = await lookup(host, { all: true, family: 0 });
55043
+ return res.map((r) => r.address);
55044
+ };
55045
+ var localAddrCache;
55046
+ function localMachineIps() {
55047
+ const now = Date.now();
55048
+ if (!localAddrCache || now - localAddrCache.at > 3e4) {
55049
+ const ips = /* @__PURE__ */ new Set(["127.0.0.1", "::1"]);
55050
+ for (const list of Object.values(networkInterfaces())) {
55051
+ for (const ni2 of list ?? []) {
55052
+ if (ni2.address) ips.add(ni2.address.toLowerCase());
55053
+ }
55054
+ }
55055
+ for (let i = 0; i <= 255; i++) ips.add(`127.0.0.${i}`);
55056
+ localAddrCache = { at: now, ips };
55057
+ }
55058
+ return localAddrCache.ips;
55059
+ }
55060
+ function allowlistHit(host, port, allowlist) {
55061
+ const h = host.toLowerCase();
55062
+ const hp = `${h}:${port}`;
55063
+ return allowlist.some((e) => e === h || e === hp);
55064
+ }
55065
+ async function checkTunnelDestination(origin, ctx) {
55066
+ let u2;
55067
+ try {
55068
+ u2 = new URL(origin);
55069
+ } catch {
55070
+ return { ok: false, code: "unresolvable", message: `invalid tunnel destination ${origin}` };
55071
+ }
55072
+ const host = u2.hostname.replace(/^\[|\]$/g, "").toLowerCase();
55073
+ const port = u2.port ? Number(u2.port) : u2.protocol === "https:" ? 443 : 80;
55074
+ let ips;
55075
+ const literal = parseIpLiteral(host);
55076
+ if (literal) {
55077
+ ips = [literal];
55078
+ } else {
55079
+ try {
55080
+ ips = await (ctx.resolveHost ?? dnsResolveHost)(host);
55081
+ } catch {
55082
+ return { ok: false, code: "unresolvable", message: `cannot resolve tunnel destination ${host}` };
55083
+ }
55084
+ if (ips.length === 0) return { ok: false, code: "unresolvable", message: `no addresses for tunnel destination ${host}` };
55085
+ }
55086
+ if (ctx.selfPort !== void 0 && port === ctx.selfPort) {
55087
+ const mine = (ctx.localIps ?? localMachineIps)();
55088
+ if (ips.some((ip) => mine.has(ip.toLowerCase()) || mine.has(`::ffff:${ip.toLowerCase()}`))) {
55089
+ return { ok: false, code: "self", message: "the bili tunnel may not target the proxy itself" };
55090
+ }
55091
+ }
55092
+ const classes = ips.map((ip) => classifyIp(ip));
55093
+ if (classes.includes("linkLocal")) {
55094
+ return { ok: false, code: "linkLocal", message: "link-local / metadata destinations are blocked from the bili tunnel" };
55095
+ }
55096
+ if (!classes.every((c) => c === "public")) {
55097
+ if (ctx.clientLoopback) return { ok: true };
55098
+ if (allowlistHit(host, port, ctx.allowlist)) return { ok: true };
55099
+ return {
55100
+ ok: false,
55101
+ code: "privateRemote",
55102
+ message: `tunnel destination ${host} resolves to a loopback/private address; remote clients may only reach it via BILI_TUNNEL_ALLOWED_HOSTS`
55103
+ };
55104
+ }
55105
+ return { ok: true };
55106
+ }
55107
+ function tunnelAllowlistFromEnv(env = process.env) {
55108
+ const raw = env.BILI_TUNNEL_ALLOWED_HOSTS ?? "";
55109
+ return raw.split(",").map((s3) => s3.trim().toLowerCase()).filter((s3) => s3.length > 0);
55110
+ }
55111
+
54813
55112
  // src/content-encoding.ts
54814
55113
  import { promisify } from "util";
54815
55114
  import { brotliDecompress, gunzip, inflate, inflateRaw } from "zlib";
@@ -55652,7 +55951,7 @@ function resolveUpstream(_opts, reqUrl, req) {
55652
55951
  if (rest.startsWith("http://") || rest.startsWith("https://")) {
55653
55952
  try {
55654
55953
  const u2 = new URL(rest);
55655
- return { upstream: `${u2.protocol}//${u2.host}`, rewrittenUrl: rest, explicitProtocol };
55954
+ return { upstream: `${u2.protocol}//${u2.host}`, rewrittenUrl: rest, explicitProtocol, tunnel: true };
55656
55955
  } catch {
55657
55956
  }
55658
55957
  }
@@ -55664,17 +55963,20 @@ async function startServer(opts) {
55664
55963
  const core = createCore();
55665
55964
  const config = opts.kernelConfig;
55666
55965
  const log2 = (level, msg) => logMsg(opts, level, msg);
55667
- const instanceId = randomUUID3();
55966
+ const instanceId = randomUUID4();
55967
+ const instanceStartedAt = Date.now();
55668
55968
  await initSessions();
55669
55969
  loadConversations();
55670
55970
  log2("info", `[persist] ${getStore().enabled ? "enabled" : "disabled"}`);
55971
+ const tunnelAllowlist = tunnelAllowlistFromEnv();
55972
+ if (tunnelAllowlist.length > 0) log2("info", `[tunnel] remote-client allowlist: ${tunnelAllowlist.join(", ")}`);
55671
55973
  if (filePath) {
55672
55974
  log2("info", `[log] writing to ${filePath}`);
55673
55975
  }
55674
55976
  void loadRegistry();
55675
55977
  const server = http.createServer(async (req, res) => {
55676
55978
  try {
55677
- await handle(req, res, opts, core, config, log2, instanceId);
55979
+ await handle(req, res, opts, core, config, log2, instanceId, instanceStartedAt);
55678
55980
  } catch (err2) {
55679
55981
  const msg = String(err2);
55680
55982
  log2("error", msg);
@@ -55705,33 +56007,65 @@ Content-Length: ${Buffer.byteLength(body)}\r
55705
56007
  const allowRemoteConnect = opts.host === "0.0.0.0" || opts.host === "::" || !isLoopbackAddress(opts.host);
55706
56008
  setupMitm(server, opts.mitm.domains, (msg) => log2("info", msg), (host) => resolveProxy(opts.routes, opts.proxy, `https://${host}`, opts.proxyFallback), allowRemoteConnect);
55707
56009
  }
55708
- server.listen(opts.port, opts.host, () => {
56010
+ const launchToken = process.env.BILI_LAUNCH_TOKEN?.trim();
56011
+ const MAX_LISTEN_ATTEMPTS = 17;
56012
+ let listenAttempts = 0;
56013
+ let lastTriedPort = opts.port;
56014
+ const announceListening = () => {
56015
+ const actualPort = server.address() === null ? opts.port : server.address().port;
55709
56016
  const nonLoopbackBind = opts.host === "0.0.0.0" || opts.host === "::" || !isLoopbackAddress(opts.host);
55710
56017
  const displayHost = nonLoopbackBind ? opts.host : opts.host === "0.0.0.0" ? "localhost" : opts.host;
56018
+ const originHost = opts.host === "0.0.0.0" || opts.host === "::" || opts.host === "localhost" ? "127.0.0.1" : opts.host.includes(":") && !opts.host.startsWith("[") ? `[${opts.host}]` : opts.host;
56019
+ const origin = `http://${originHost}:${actualPort}`;
55711
56020
  try {
55712
- fs6.mkdirSync(stateDir(), { recursive: true });
55713
- const originHost = opts.host === "0.0.0.0" || opts.host === "::" || opts.host === "localhost" ? "127.0.0.1" : opts.host.includes(":") && !opts.host.startsWith("[") ? `[${opts.host}]` : opts.host;
55714
- fs6.writeFileSync(proxyOriginFile(), `http://${originHost}:${server.address() === null ? opts.port : server.address().port}
55715
- `);
56021
+ fs7.mkdirSync(stateDir(), { recursive: true });
56022
+ atomicWriteInstanceFile({
56023
+ origin,
56024
+ instanceId,
56025
+ pid: process.pid,
56026
+ startedAt: instanceStartedAt,
56027
+ host: opts.host,
56028
+ port: actualPort,
56029
+ passthrough: opts.passthrough,
56030
+ mitmDomains: opts.mitm.enabled ? opts.mitm.domains : [],
56031
+ modelWindows: { ...LAUNCHER_MODEL_WINDOWS },
56032
+ launchToken: launchToken || void 0
56033
+ });
55716
56034
  } catch {
55717
56035
  }
56036
+ registerInstanceAndWarn(
56037
+ { instanceId, pid: process.pid, port: actualPort, origin, startedAt: instanceStartedAt },
56038
+ (msg) => log2("warn", `[instances] ${msg}`)
56039
+ );
55718
56040
  const nOverrides = Object.keys(opts.routes).length;
55719
56041
  log2(
55720
56042
  "info",
55721
- `acp-proxy listening on http://${displayHost}:${opts.port} \u2014 web UI: http://${displayHost}:${opts.port}/__bili/ \u2014 zero-config: prefix any baseURL with http://${displayHost}:${opts.port}/bili/` + (nOverrides ? ` \u2014 context overrides for ${nOverrides} upstream URL(s)` : "") + (opts.mitm.enabled ? ` \u2014 MITM proxy on (whitelist)${opts.mitm.domains.length ? ` +${opts.mitm.domains.join(",")}` : ""}` : "")
56043
+ `acp-proxy listening on http://${displayHost}:${actualPort} \u2014 web UI: http://${displayHost}:${actualPort}/__bili/ \u2014 zero-config: prefix any baseURL with http://${displayHost}:${actualPort}/bili/` + (nOverrides ? ` \u2014 context overrides for ${nOverrides} upstream URL(s)` : "") + (opts.mitm.enabled ? ` \u2014 MITM proxy on (whitelist)${opts.mitm.domains.length ? ` +${opts.mitm.domains.join(",")}` : ""}` : "")
55722
56044
  );
55723
56045
  if (nonLoopbackBind) {
55724
56046
  log2(
55725
56047
  "warn",
55726
- `[security] bound to ${opts.host} \u2014 proxy endpoints (/bili/, CONNECT for whitelisted model hosts) are reachable from the network with NO authentication; /__bili/ management endpoints stay loopback-only. Restrict access with a firewall on untrusted networks. Remote agents: point baseURL at http://<this-host>:${opts.port}/bili/`
56048
+ `[security] bound to ${opts.host} \u2014 proxy endpoints (/bili/, CONNECT for whitelisted model hosts) are reachable from the network with NO authentication; /__bili/ management endpoints stay loopback-only. Restrict access with a firewall on untrusted networks. Remote agents: point baseURL at http://<this-host>:${actualPort}/bili/`
55727
56049
  );
55728
56050
  }
55729
56051
  if (opts.debug) {
55730
56052
  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)`);
55731
56053
  }
55732
- });
56054
+ };
56055
+ const attemptListen = (port) => {
56056
+ lastTriedPort = port;
56057
+ server.listen(port, opts.host, announceListening);
56058
+ };
56059
+ attemptListen(opts.port);
55733
56060
  server.on("error", (err2) => {
55734
- const hint = err2.code === "EADDRINUSE" ? ` \u2014 port ${opts.port} is already in use. Stop the other process or use --port <N>.` : err2.code === "EACCES" ? ` \u2014 port ${opts.port} requires privileges. Use a port >= 1024.` : "";
56061
+ if (err2.code === "EADDRINUSE" && launchToken && listenAttempts < MAX_LISTEN_ATTEMPTS) {
56062
+ listenAttempts += 1;
56063
+ const next = listenAttempts === MAX_LISTEN_ATTEMPTS ? 0 : lastTriedPort + 1;
56064
+ log2("warn", `port ${lastTriedPort} busy \u2014 ${next === 0 ? "retrying on an ephemeral port" : `retrying on port ${next}`}`);
56065
+ attemptListen(next);
56066
+ return;
56067
+ }
56068
+ const hint = err2.code === "EADDRINUSE" ? ` \u2014 port ${lastTriedPort} is already in use. Stop the other process or use --port <N>.` : err2.code === "EACCES" ? ` \u2014 port ${lastTriedPort} requires privileges. Use a port >= 1024.` : "";
55735
56069
  log2("error", `listen failed: ${err2.code ?? ""} ${err2.message}${hint}`);
55736
56070
  shuttingDown = true;
55737
56071
  server.close();
@@ -55748,24 +56082,24 @@ Content-Length: ${Buffer.byteLength(body)}\r
55748
56082
  log2("error", `unhandledRejection: ${String(reason)}`);
55749
56083
  });
55750
56084
  let shuttingDown = false;
56085
+ const finishShutdown = () => {
56086
+ clearProxyInstanceFile(instanceId);
56087
+ unregisterInstance(instanceId);
56088
+ closeLogger();
56089
+ process.exit(0);
56090
+ };
55751
56091
  const shutdown = (sig) => {
55752
56092
  if (shuttingDown) return;
55753
56093
  shuttingDown = true;
55754
56094
  log2("info", `${sig} received \u2014 flushing sessions\u2026`);
55755
56095
  server.close(() => {
55756
56096
  flushConversations();
55757
- void flushAllSessions().finally(() => {
55758
- closeLogger();
55759
- process.exit(0);
55760
- });
56097
+ void flushAllSessions().finally(finishShutdown);
55761
56098
  });
55762
56099
  setTimeout(() => {
55763
56100
  log2("warn", "shutdown grace window elapsed; forcing exit");
55764
56101
  flushConversations();
55765
- void flushAllSessions().finally(() => {
55766
- closeLogger();
55767
- process.exit(0);
55768
- });
56102
+ void flushAllSessions().finally(finishShutdown);
55769
56103
  }, 1e4).unref?.();
55770
56104
  };
55771
56105
  process.on("SIGTERM", () => shutdown("SIGTERM"));
@@ -55773,6 +56107,13 @@ Content-Length: ${Buffer.byteLength(body)}\r
55773
56107
  if (process.platform === "win32") {
55774
56108
  process.on("SIGBREAK", () => shutdown("SIGBREAK"));
55775
56109
  }
56110
+ const parentPid = Number.parseInt(process.env.BILI_PARENT_PID ?? "", 10);
56111
+ if (Number.isInteger(parentPid) && parentPid > 0 && parentPid !== process.pid) {
56112
+ const watcher = setInterval(() => {
56113
+ if (!isPidAlive(parentPid)) shutdown(`parent-gone (pid ${parentPid})`);
56114
+ }, 2e3);
56115
+ watcher.unref?.();
56116
+ }
55776
56117
  return server;
55777
56118
  }
55778
56119
  function isTrustedAdminOrigin(origin, host, trustedHosts) {
@@ -55799,8 +56140,13 @@ function adminTrustedHosts(bindHost, port) {
55799
56140
  }
55800
56141
  return set;
55801
56142
  }
55802
- async function handle(req, res, opts, core, config, log2, instanceId) {
56143
+ async function handle(req, res, opts, core, config, log2, instanceId, instanceStartedAt) {
55803
56144
  const isAdminPath = req.url === "/__bili/" || req.url?.startsWith("/__bili/") || req.url === "/__acp/" || req.url?.startsWith("/__acp/");
56145
+ if (isAdminPath && headerValue2(req, BILI_TUNNEL_HEADER) !== void 0) {
56146
+ res.writeHead(403, { "content-type": "application/json" });
56147
+ res.end(JSON.stringify({ error: "management endpoints are not reachable through the bili tunnel" }));
56148
+ return;
56149
+ }
55804
56150
  if (isAdminPath && !isLoopbackAddress(req.socket.remoteAddress)) {
55805
56151
  res.writeHead(403, { "content-type": "application/json" });
55806
56152
  res.end(JSON.stringify({ error: "management endpoints are loopback-only; access denied for " + (req.socket.remoteAddress ?? "unknown") }));
@@ -55825,7 +56171,7 @@ async function handle(req, res, opts, core, config, log2, instanceId) {
55825
56171
  }
55826
56172
  if (req.method === "GET" && req.url === "/__bili/health") {
55827
56173
  res.writeHead(200, { "content-type": "application/json" });
55828
- res.end(JSON.stringify({ ok: true, upstream: opts.upstream }));
56174
+ res.end(JSON.stringify({ ok: true, upstream: opts.upstream, instanceId, pid: process.pid, startedAt: instanceStartedAt }));
55829
56175
  return;
55830
56176
  }
55831
56177
  if (req.method === "GET" && req.url === "/__bili/") {
@@ -55946,6 +56292,19 @@ async function handle(req, res, opts, core, config, log2, instanceId) {
55946
56292
  urlPath = url.split("?", 2)[0];
55947
56293
  responsesCompact = urlPath.endsWith("/responses/compact");
55948
56294
  route = resolveUpstream(opts, req.url ?? "", req);
56295
+ if (route?.tunnel) {
56296
+ const verdict = await checkTunnelDestination(route.upstream, {
56297
+ selfPort: req.socket.localPort ?? void 0,
56298
+ clientLoopback: isLoopbackAddress(req.socket.remoteAddress),
56299
+ allowlist: tunnelAllowlistFromEnv()
56300
+ });
56301
+ if (!verdict.ok) {
56302
+ log2("warn", `[tunnel] denied ${maskUrlsInText(route.upstream)}: ${verdict.message}`);
56303
+ res.writeHead(403, { "content-type": "application/json" });
56304
+ res.end(JSON.stringify({ error: verdict.message, code: "tunnel_destination_denied", detail: verdict.code }));
56305
+ return;
56306
+ }
56307
+ }
55949
56308
  upstreamOrigin = route ? route.upstream : /^https?:\/\//i.test(url) ? new URL(url).origin : opts.upstream;
55950
56309
  protocol = route?.explicitProtocol ?? (req.method === "POST" && bodyBuffer.length > 0 ? urlPath.endsWith("/chat/completions") ? "openai" : urlPath.endsWith("/v1/messages") || urlPath.endsWith("/messages") ? "anthropic" : urlPath.endsWith("/responses") || responsesCompact ? "responses" : null : null);
55951
56310
  if (protocol !== null && bodyBuffer.length > 0) {
@@ -55989,14 +56348,14 @@ async function handle(req, res, opts, core, config, log2, instanceId) {
55989
56348
  try {
55990
56349
  const rawDir = process.env.ACP_RAW_DUMP_DIR || `${stateDir()}/raw`;
55991
56350
  try {
55992
- fs6.mkdirSync(rawDir, { recursive: true });
56351
+ fs7.mkdirSync(rawDir, { recursive: true });
55993
56352
  } catch {
55994
56353
  }
55995
56354
  const hdrs = maskHeadersForLog(
55996
56355
  Object.fromEntries(Object.entries(req.headers).map(([k2, v2]) => [k2, Array.isArray(v2) ? v2.join(",") : String(v2)]))
55997
56356
  );
55998
56357
  const hdrText = Object.entries(hdrs).map(([k2, v2]) => `${k2}: ${v2}`).join("\n");
55999
- fs6.writeFileSync(`${rawDir}/${Date.now()}-INCOMING.txt`, `${req.method} ${maskUrlsInText(req.url ?? "")}
56358
+ fs7.writeFileSync(`${rawDir}/${Date.now()}-INCOMING.txt`, `${req.method} ${maskUrlsInText(req.url ?? "")}
56000
56359
  ${hdrText}
56001
56360
 
56002
56361
  ${bodyBuffer.toString("utf8")}`);
@@ -56262,6 +56621,10 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
56262
56621
  let rebuiltMessages = parsed.messages;
56263
56622
  let systemOut = parsed.system;
56264
56623
  let toolsOut = parsed.tools;
56624
+ const strippedPanels = stripAcpPanelMessages(parsed.messages);
56625
+ if (strippedPanels > 0) {
56626
+ log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
56627
+ }
56265
56628
  try {
56266
56629
  const { msgs, cacheControls } = anthropicToCore(parsed);
56267
56630
  originalMessages = msgs;
@@ -56286,7 +56649,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
56286
56649
  if (injectTools) {
56287
56650
  toolsOut = injectTool(parsed.tools);
56288
56651
  }
56289
- if (opts.compress.injectNudge && turn.nudge?.shouldInject) {
56652
+ if (opts.compress.injectNudge && !pluginMode && turn.nudge?.shouldInject) {
56290
56653
  try {
56291
56654
  const rendered = renderNudgeText(turn.nudge, prompts);
56292
56655
  if (rendered.text) {
@@ -56319,6 +56682,10 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
56319
56682
  const isTitleGen = maxTokens <= 200;
56320
56683
  const shouldInject = opts.compress.injectTool && !isTitleGen;
56321
56684
  const injectTools = shouldInject && !pluginMode;
56685
+ const strippedPanels = stripAcpPanelMessages(parsed.messages);
56686
+ if (strippedPanels > 0) {
56687
+ log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
56688
+ }
56322
56689
  try {
56323
56690
  const { msgs, systemText } = openaiToCore(parsed);
56324
56691
  openaiSystemText = systemText;
@@ -56338,7 +56705,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
56338
56705
  log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
56339
56706
  processedMessages = stripKernelSummaries(turn.messages, turn.state);
56340
56707
  reapOrphanBlocks(session, msgs, deactivateBlock);
56341
- rebuiltMessages = hoistMidSystemMessages(coreToOpenai(processedMessages));
56708
+ rebuiltMessages = systemToUser(coreToOpenai(processedMessages));
56342
56709
  const sysParts = [];
56343
56710
  if (systemText) sysParts.push(systemText);
56344
56711
  if (shouldInject) sysParts.push(buildCompressSystemPrompt(prompts));
@@ -56346,7 +56713,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
56346
56713
  if (injectTools) {
56347
56714
  toolsOut = injectOpenaiTool(parsed.tools);
56348
56715
  }
56349
- if (opts.compress.injectNudge && turn.nudge?.shouldInject && shouldInject) {
56716
+ if (opts.compress.injectNudge && !pluginMode && turn.nudge?.shouldInject && shouldInject) {
56350
56717
  try {
56351
56718
  const rendered = renderNudgeText(turn.nudge, prompts);
56352
56719
  if (rendered.text) {
@@ -56400,6 +56767,10 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
56400
56767
  if (droppedEmpty > 0) {
56401
56768
  log2("info", `[${sessionId}] dropped ${droppedEmpty} whitespace-only message item(s) before projection (flattened-turn artifact)`);
56402
56769
  }
56770
+ const strippedPanels = stripAcpPanelResponsesInput(parsed.input);
56771
+ if (strippedPanels > 0) {
56772
+ log2("info", `[${sessionId}] stripped ${strippedPanels} ACP panel message(s) before projection (UI-only, issue #359)`);
56773
+ }
56403
56774
  const shouldInject = opts.compress.injectTool;
56404
56775
  const injectTools = shouldInject && !pluginMode;
56405
56776
  const isCompactionTrigger = hasCompactionTrigger(parsed.input);
@@ -56440,7 +56811,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
56440
56811
  const devContent = [...projection.systemParts, ...forgedSummaries].join("\n\n---\n\n");
56441
56812
  rebuiltInput = injectResponsesDeveloperMessage(rebuiltInput, devContent);
56442
56813
  }
56443
- if (opts.compress.injectNudge && turn.nudge?.shouldInject && shouldInject && !isCompactionTrigger) {
56814
+ if (opts.compress.injectNudge && !pluginMode && turn.nudge?.shouldInject && shouldInject && !isCompactionTrigger) {
56444
56815
  try {
56445
56816
  const rendered = renderNudgeText(turn.nudge, prompts);
56446
56817
  if (rendered.text) {
@@ -56675,6 +57046,7 @@ function buildForwardTarget(req, opts, route, affinity, hopMarker) {
56675
57046
  headers[k2] = Array.isArray(v2) ? v2.join(", ") : v2;
56676
57047
  }
56677
57048
  if (hopMarker !== void 0) headers[BILI_HOP_HEADER] = hopMarker;
57049
+ if (route?.tunnel) headers[BILI_TUNNEL_HEADER] = "1";
56678
57050
  headers["host"] = new URL(upstreamUrl).host;
56679
57051
  const betaKey = Object.keys(headers).find((h) => h.toLowerCase() === "x-codex-beta-features");
56680
57052
  if (betaKey) {
@@ -56786,16 +57158,16 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
56786
57158
  if (bodyDumpEnabled() && process.env.ACP_DUMP_REQ !== "0") {
56787
57159
  const dumpDir = process.env.ACP_DUMP_DIR || `${stateDir()}/dumps`;
56788
57160
  try {
56789
- fs6.mkdirSync(dumpDir, { recursive: true });
57161
+ fs7.mkdirSync(dumpDir, { recursive: true });
56790
57162
  } catch {
56791
57163
  }
56792
57164
  const sid = prepared?.session.id ?? "unknown";
56793
57165
  const out = `${dumpDir}/req-${Date.now()}-${safeSessionId(sid)}.json`;
56794
57166
  try {
56795
57167
  const pretty = JSON.stringify(JSON.parse(body), null, 2);
56796
- fs6.writeFileSync(out, pretty);
57168
+ fs7.writeFileSync(out, pretty);
56797
57169
  } catch {
56798
- fs6.writeFileSync(out, body);
57170
+ fs7.writeFileSync(out, body);
56799
57171
  }
56800
57172
  log2("info", `[debug] forwarded body written to ${out}`);
56801
57173
  }
@@ -56815,7 +57187,7 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
56815
57187
  const rawBase = bodyDumpEnabled() ? (() => {
56816
57188
  try {
56817
57189
  const rawDir = process.env.ACP_RAW_DUMP_DIR || `${stateDir()}/raw`;
56818
- fs6.mkdirSync(rawDir, { recursive: true });
57190
+ fs7.mkdirSync(rawDir, { recursive: true });
56819
57191
  return `${rawDir}/${Date.now()}-${safeSessionId(prepared?.session.id)}`;
56820
57192
  } catch {
56821
57193
  return "";
@@ -56826,7 +57198,7 @@ async function forward(req, res, opts, body, prepared, core, config, log2, route
56826
57198
  const hdrText = Object.entries(maskHeadersForLog(headers)).map(([k2, v2]) => `${k2}: ${v2}`).join("\n");
56827
57199
  const bodyText = req.method === "GET" || req.method === "HEAD" ? "" : typeof body === "string" ? body : Buffer.from(body).toString("utf8");
56828
57200
  const reqPath = `${rawBase}-REQ.txt`;
56829
- fs6.writeFileSync(reqPath, `${req.method ?? "POST"} ${maskUrlForLog(upstreamUrl)}
57201
+ fs7.writeFileSync(reqPath, `${req.method ?? "POST"} ${maskUrlForLog(upstreamUrl)}
56830
57202
  ${hdrText}
56831
57203
 
56832
57204
  ${bodyText}`);
@@ -56876,7 +57248,7 @@ ${bodyText}`);
56876
57248
  try {
56877
57249
  const hdrText = Object.entries(maskHeadersForLog(respHeaders)).map(([k2, v2]) => `${k2}: ${v2}`).join("\n");
56878
57250
  const resPath = `${rawBase}-RES.txt`;
56879
- fs6.writeFileSync(resPath, `${upstream.status}
57251
+ fs7.writeFileSync(resPath, `${upstream.status}
56880
57252
  ${hdrText}
56881
57253
  `);
56882
57254
  log2("info", `[debug] RAW response dump: ${resPath}`);
@@ -59175,7 +59547,7 @@ var hr = /* @__PURE__ */ Symbol("entry");
59175
59547
  var cs = /* @__PURE__ */ Symbol("entryOpt");
59176
59548
  var ui = /* @__PURE__ */ Symbol("writeEntryClass");
59177
59549
  var lr = /* @__PURE__ */ Symbol("write");
59178
- var fs7 = /* @__PURE__ */ Symbol("ondrain");
59550
+ var fs8 = /* @__PURE__ */ Symbol("ondrain");
59179
59551
  var wt = class extends A {
59180
59552
  sync = false;
59181
59553
  opt;
@@ -59209,8 +59581,8 @@ var wt = class extends A {
59209
59581
  if ((t.gzip ? 1 : 0) + (t.brotli ? 1 : 0) + (t.zstd ? 1 : 0) > 1) throw new TypeError("gzip, brotli, zstd are mutually exclusive");
59210
59582
  if (t.gzip && (typeof t.gzip != "object" && (t.gzip = {}), this.portable && (t.gzip.portable = true), this.zip = new ze(t.gzip)), t.brotli && (typeof t.brotli != "object" && (t.brotli = {}), this.zip = new We(t.brotli)), t.zstd && (typeof t.zstd != "object" && (t.zstd = {}), this.zip = new Ye(t.zstd)), !this.zip) throw new Error("impossible");
59211
59583
  let e = this.zip;
59212
- e.on("data", (i) => super.write(i)), e.on("end", () => super.end()), e.on("drain", () => this[fs7]()), this.on("resume", () => e.resume());
59213
- } else this.on("drain", this[fs7]);
59584
+ e.on("data", (i) => super.write(i)), e.on("end", () => super.end()), e.on("drain", () => this[fs8]()), this.on("resume", () => e.resume());
59585
+ } else this.on("drain", this[fs8]);
59214
59586
  this.noDirRecurse = !!t.noDirRecurse, this.follow = !!t.follow, this.noMtime = !!t.noMtime, t.mtime && (this.mtime = t.mtime), this.filter = typeof t.filter == "function" ? t.filter : () => true, this[W] = new hi(), this[G] = 0, this.jobs = Number(t.jobs) || 4, this[Ee] = false, this[me] = false;
59215
59587
  }
59216
59588
  [lr](t) {
@@ -59323,7 +59695,7 @@ var wt = class extends A {
59323
59695
  this.emit("error", e);
59324
59696
  }
59325
59697
  }
59326
- [fs7]() {
59698
+ [fs8]() {
59327
59699
  this[Et] && this[Et].entry && this[Et].entry.resume();
59328
59700
  }
59329
59701
  [di](t) {
@@ -60208,12 +60580,12 @@ var To = (s3) => {
60208
60580
  };
60209
60581
 
60210
60582
  // src/update.ts
60211
- import path10 from "path";
60583
+ import path11 from "path";
60212
60584
  import { fileURLToPath as fileURLToPath3 } from "url";
60213
60585
  var REGISTRY_BASE = "https://registry.npmjs.org";
60214
60586
  var CHECK_INTERVAL_MS = 3 * 60 * 1e3;
60215
- var THROTTLE_FILE = path10.join(cacheDir(), ".update-check");
60216
- var LOCK_FILE = path10.join(cacheDir(), ".update-lock");
60587
+ var THROTTLE_FILE = path11.join(cacheDir(), ".update-check");
60588
+ var LOCK_FILE = path11.join(cacheDir(), ".update-lock");
60217
60589
  var LOCK_MAX_AGE_MS = 30 * 60 * 1e3;
60218
60590
  function shouldStealLock(holderAlive, ageMs) {
60219
60591
  return !holderAlive || ageMs >= LOCK_MAX_AGE_MS;
@@ -60248,27 +60620,27 @@ async function readLastCheck() {
60248
60620
  }
60249
60621
  async function writeLastCheck(ts2) {
60250
60622
  try {
60251
- await mkdir2(path10.dirname(THROTTLE_FILE), { recursive: true });
60623
+ await mkdir2(path11.dirname(THROTTLE_FILE), { recursive: true });
60252
60624
  await writeFile2(THROTTLE_FILE, String(ts2), "utf-8");
60253
60625
  } catch {
60254
60626
  }
60255
60627
  }
60256
60628
  async function findInstallDir(packageName) {
60257
- let dir = path10.dirname(fileURLToPath3(import.meta.url));
60629
+ let dir = path11.dirname(fileURLToPath3(import.meta.url));
60258
60630
  for (; ; ) {
60259
60631
  try {
60260
- const pkg = JSON.parse(await readFile2(path10.join(dir, "package.json"), "utf-8"));
60632
+ const pkg = JSON.parse(await readFile2(path11.join(dir, "package.json"), "utf-8"));
60261
60633
  if (pkg.name === packageName) return dir;
60262
60634
  } catch {
60263
60635
  }
60264
- const parent = path10.dirname(dir);
60636
+ const parent = path11.dirname(dir);
60265
60637
  if (parent === dir) return void 0;
60266
60638
  dir = parent;
60267
60639
  }
60268
60640
  }
60269
60641
  async function readDiskVersion(installDir) {
60270
60642
  try {
60271
- const pkg = JSON.parse(await readFile2(path10.join(installDir, "package.json"), "utf-8"));
60643
+ const pkg = JSON.parse(await readFile2(path11.join(installDir, "package.json"), "utf-8"));
60272
60644
  return pkg.version;
60273
60645
  } catch {
60274
60646
  return void 0;
@@ -60305,13 +60677,13 @@ async function syntaxCheckEntry(entryAbs) {
60305
60677
  } catch (e) {
60306
60678
  return `entry unreadable: ${String(e)}`;
60307
60679
  }
60308
- const tmpCheck = path10.join(cacheDir(), ".update-syntax-check.mjs");
60680
+ const tmpCheck = path11.join(cacheDir(), ".update-syntax-check.mjs");
60309
60681
  try {
60310
60682
  await mkdir2(cacheDir(), { recursive: true });
60311
60683
  await writeFile2(tmpCheck, source);
60312
60684
  const r = await runNodeCheck(tmpCheck);
60313
60685
  if (r.code !== 0) {
60314
- return `entry does not parse (${path10.basename(entryAbs)}): ${r.stderr.split("\n").filter(Boolean).slice(0, 3).join(" | ").slice(0, 300)}`;
60686
+ return `entry does not parse (${path11.basename(entryAbs)}): ${r.stderr.split("\n").filter(Boolean).slice(0, 3).join(" | ").slice(0, 300)}`;
60315
60687
  }
60316
60688
  return null;
60317
60689
  } finally {
@@ -60324,7 +60696,7 @@ async function syntaxCheckEntry(entryAbs) {
60324
60696
  async function verifyEntries(dir, label) {
60325
60697
  let pkg;
60326
60698
  try {
60327
- pkg = JSON.parse(await readFile2(path10.join(dir, "package.json"), "utf-8"));
60699
+ pkg = JSON.parse(await readFile2(path11.join(dir, "package.json"), "utf-8"));
60328
60700
  } catch (e) {
60329
60701
  return `${label}: package.json unreadable: ${String(e)}`;
60330
60702
  }
@@ -60334,11 +60706,11 @@ async function verifyEntries(dir, label) {
60334
60706
  }
60335
60707
  for (const rel2 of entries) {
60336
60708
  try {
60337
- await access(path10.join(dir, rel2));
60709
+ await access(path11.join(dir, rel2));
60338
60710
  } catch {
60339
60711
  return `${label}: entry missing: ${rel2}`;
60340
60712
  }
60341
- const reason = await syntaxCheckEntry(path10.join(dir, rel2));
60713
+ const reason = await syntaxCheckEntry(path11.join(dir, rel2));
60342
60714
  if (reason) return `${label}: ${reason}`;
60343
60715
  }
60344
60716
  return null;
@@ -60543,14 +60915,14 @@ async function installViaTarball(version2, tarballUrl, installDir, integrity, sh
60543
60915
  if (!v2.ok) {
60544
60916
  return { ok: false, error: `tarball integrity verification failed: ${v2.error}` };
60545
60917
  }
60546
- const tmpFile = path10.join(cacheDir(), `.update-${version2}.tgz`);
60918
+ const tmpFile = path11.join(cacheDir(), `.update-${version2}.tgz`);
60547
60919
  try {
60548
60920
  await mkdir2(cacheDir(), { recursive: true });
60549
60921
  await writeFile2(tmpFile, tgzBuffer);
60550
60922
  } catch (e) {
60551
60923
  return { ok: false, error: `failed to write temp file ${tmpFile}: ${String(e)}` };
60552
60924
  }
60553
- const stagingDir = path10.join(cacheDir(), `.update-staging-${version2}`);
60925
+ const stagingDir = path11.join(cacheDir(), `.update-staging-${version2}`);
60554
60926
  try {
60555
60927
  await rm2(stagingDir, { recursive: true, force: true });
60556
60928
  await mkdir2(stagingDir, { recursive: true });
@@ -60572,7 +60944,7 @@ async function installViaTarball(version2, tarballUrl, installDir, integrity, sh
60572
60944
  } finally {
60573
60945
  await rm2(tmpFile, { force: true });
60574
60946
  }
60575
- const backupDir = path10.join(cacheDir(), `.update-backup-${version2}`);
60947
+ const backupDir = path11.join(cacheDir(), `.update-backup-${version2}`);
60576
60948
  try {
60577
60949
  await rm2(backupDir, { recursive: true, force: true });
60578
60950
  await cp(installDir, backupDir, { recursive: true, force: true });
@@ -60628,14 +61000,14 @@ function startAutoUpdate(opts) {
60628
61000
  }
60629
61001
 
60630
61002
  // src/mcp.ts
60631
- import fs8 from "fs";
60632
- import path11 from "path";
61003
+ import fs9 from "fs";
61004
+ import path12 from "path";
60633
61005
  import { fileURLToPath as fileURLToPath4 } from "url";
60634
61006
  var VERSION2 = (() => {
60635
61007
  try {
60636
61008
  const here = fileURLToPath4(import.meta.url);
60637
- const pkg = path11.join(path11.dirname(here), "..", "package.json");
60638
- return JSON.parse(fs8.readFileSync(pkg, "utf8")).version ?? "dev";
61009
+ const pkg = path12.join(path12.dirname(here), "..", "package.json");
61010
+ return JSON.parse(fs9.readFileSync(pkg, "utf8")).version ?? "dev";
60639
61011
  } catch {
60640
61012
  return "dev";
60641
61013
  }
@@ -60644,11 +61016,8 @@ var DEFAULT_PROXY_ORIGIN = "http://127.0.0.1:8787";
60644
61016
  function resolveProxyOrigin() {
60645
61017
  const fromEnv = process.env.BILI_MCP_PROXY?.trim();
60646
61018
  if (fromEnv && fromEnv.length > 0) return fromEnv;
60647
- try {
60648
- const discovered = fs8.readFileSync(proxyOriginFile(), "utf8").trim();
60649
- if (/^https?:\/\/\S+$/.test(discovered)) return discovered;
60650
- } catch {
60651
- }
61019
+ const discovered = readProxyInstanceFile();
61020
+ if (discovered && /^https?:\/\/\S+$/.test(discovered.origin)) return discovered.origin;
60652
61021
  return DEFAULT_PROXY_ORIGIN;
60653
61022
  }
60654
61023
  var TOOL_TIMEOUT_MS = 6e4;
@@ -60807,30 +61176,42 @@ if (process.argv[1] && /(?:^|[\\/])mcp\.(?:ts|js)$/.test(process.argv[1])) {
60807
61176
  }
60808
61177
 
60809
61178
  // src/plugin-install.ts
60810
- import fs9 from "fs";
60811
- import path12 from "path";
61179
+ import fs10 from "fs";
61180
+ import path13 from "path";
60812
61181
  import os4 from "os";
60813
61182
  import { execFileSync as execFileSync2 } from "child_process";
60814
61183
  import { fileURLToPath as fileURLToPath5 } from "url";
61184
+ function proxyOriginForInstall() {
61185
+ const fromEnv = process.env.BILI_MCP_PROXY?.trim();
61186
+ if (fromEnv && fromEnv.length > 0) return fromEnv;
61187
+ const inst = readProxyInstanceFile();
61188
+ if (inst === void 0) {
61189
+ throw new Error("no bili proxy origin found \u2014 start bili first (`bili start` or `bili <client>`), then retry, or set BILI_MCP_PROXY explicitly");
61190
+ }
61191
+ if (isProxyInstanceFile(inst) && !isPidAlive(inst.pid)) {
61192
+ throw new Error(`the recorded bili proxy (pid ${inst.pid}, ${inst.origin}) is not running \u2014 start bili and retry so a dead origin is not frozen into the client config`);
61193
+ }
61194
+ return inst.origin;
61195
+ }
60815
61196
  var PLUGIN_AGENTS = ["pi", "omp", "claude", "codex", "opencode"];
60816
61197
  function selfPackageRoot() {
60817
61198
  const here = fileURLToPath5(import.meta.url);
60818
- return path12.resolve(path12.dirname(here), "..");
61199
+ return path13.resolve(path13.dirname(here), "..");
60819
61200
  }
60820
61201
  function homeFile(rel2, envOverride) {
60821
61202
  const raw = (envOverride !== void 0 ? process.env[envOverride] : void 0)?.trim();
60822
61203
  const base = raw && raw.length > 0 ? raw : os4.homedir();
60823
- return path12.join(base, rel2);
61204
+ return path13.join(base, rel2);
60824
61205
  }
60825
61206
  function backupOnce(file) {
60826
- if (fs9.existsSync(file) && !fs9.existsSync(`${file}.bili-bak`)) {
60827
- fs9.copyFileSync(file, `${file}.bili-bak`);
61207
+ if (fs10.existsSync(file) && !fs10.existsSync(`${file}.bili-bak`)) {
61208
+ fs10.copyFileSync(file, `${file}.bili-bak`);
60828
61209
  }
60829
61210
  }
60830
61211
  function readJson(file) {
60831
61212
  let text;
60832
61213
  try {
60833
- text = fs9.readFileSync(file, "utf8");
61214
+ text = fs10.readFileSync(file, "utf8");
60834
61215
  } catch (err2) {
60835
61216
  if (err2.code === "ENOENT") return {};
60836
61217
  throw err2;
@@ -60839,7 +61220,7 @@ function readJson(file) {
60839
61220
  try {
60840
61221
  parsed = JSON.parse(text);
60841
61222
  } catch (err2) {
60842
- throw new Error(`${file}: not valid JSON (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 fix it or restore ${path12.basename(file)}.bili-bak first; refusing to overwrite`);
61223
+ throw new Error(`${file}: not valid JSON (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 fix it or restore ${path13.basename(file)}.bili-bak first; refusing to overwrite`);
60843
61224
  }
60844
61225
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
60845
61226
  throw new Error(`${file}: expected a JSON object at top level, refusing to overwrite`);
@@ -60847,18 +61228,18 @@ function readJson(file) {
60847
61228
  return parsed;
60848
61229
  }
60849
61230
  function writeJson(file, data) {
60850
- fs9.mkdirSync(path12.dirname(file), { recursive: true });
61231
+ fs10.mkdirSync(path13.dirname(file), { recursive: true });
60851
61232
  backupOnce(file);
60852
- fs9.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
61233
+ fs10.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
60853
61234
  }
60854
61235
  function requireDistFile(file) {
60855
- if (!fs9.existsSync(file)) {
61236
+ if (!fs10.existsSync(file)) {
60856
61237
  process.stderr.write(`bili plugin: warning: ${file} does not exist yet (run \`npm run build\` in ${selfPackageRoot()}) \u2014 the entry will be dead until built
60857
61238
  `);
60858
61239
  }
60859
61240
  }
60860
61241
  function piSettingsFile() {
60861
- return path12.join(resolvePiHome(process.env), "settings.json");
61242
+ return path13.join(resolvePiHome(process.env), "settings.json");
60862
61243
  }
60863
61244
  function isPiEntry(entry, root) {
60864
61245
  return entry === root || /^npm:billion-context(-pi)?(@|$)/.test(entry) || /(^|[/\\])node_modules[/\\]billion-context(-pi)?([\/\\]|$)/.test(entry) || /(^|[/\\])billion-context(-pi)?$/.test(entry);
@@ -60895,35 +61276,80 @@ function piStatus() {
60895
61276
  const list = Array.isArray(packages) ? packages.map(String) : [];
60896
61277
  return list.some((p2) => p2 === root) ? "installed" : "not installed";
60897
61278
  }
61279
+ var OMP_ENTRY_RE = /[\\/]dist[\\/]agent[\\/]omp\.js$/;
61280
+ function ompExtensionItemLines(text) {
61281
+ const lines = text.split("\n");
61282
+ let keyIdx = -1;
61283
+ for (let i = 0; i < lines.length; i++) {
61284
+ if (/^extensions:(\s+(#.*)?)?$/.test(lines[i])) {
61285
+ if (keyIdx !== -1) return [];
61286
+ keyIdx = i;
61287
+ }
61288
+ }
61289
+ if (keyIdx === -1) return [];
61290
+ const items = [];
61291
+ for (let i = keyIdx + 1; i < lines.length; i++) {
61292
+ const t = lines[i].trimStart();
61293
+ if (t === "" || t.startsWith("#")) continue;
61294
+ if (t === "-" || t.startsWith("- ")) items.push(i);
61295
+ else break;
61296
+ }
61297
+ return items;
61298
+ }
60898
61299
  function ompConfigFile() {
60899
61300
  const raw = process.env.PI_CODING_AGENT_DIR?.trim();
60900
- if (raw && raw.length > 0) return path12.join(raw, "config.yml");
60901
- return path12.join(os4.homedir(), ".omp", "agent", "config.yml");
61301
+ if (raw && raw.length > 0) {
61302
+ if (raw.endsWith("-bili") && raw.length > "-bili".length) {
61303
+ const realHome = raw.slice(0, -"-bili".length);
61304
+ process.stderr.write(
61305
+ `bili plugin: PI_CODING_AGENT_DIR points at the bili overlay ${raw} \u2014 operating on the real omp home ${realHome} instead
61306
+ `
61307
+ );
61308
+ return path13.join(realHome, "config.yml");
61309
+ }
61310
+ return path13.join(raw, "config.yml");
61311
+ }
61312
+ return path13.join(os4.homedir(), ".omp", "agent", "config.yml");
60902
61313
  }
60903
61314
  function ompExtensionPath() {
60904
- return path12.join(selfPackageRoot(), "dist", "agent", "omp.js");
61315
+ return path13.join(selfPackageRoot(), "dist", "agent", "omp.js");
60905
61316
  }
60906
61317
  function ompEntryValue(line) {
60907
61318
  return line.replace(/#.*$/, "").trim().replace(/^-\s*/, "").replace(/^["']|["']$/g, "").trim();
60908
61319
  }
61320
+ function ompBlockLoaded(text) {
61321
+ const lines = text.split("\n");
61322
+ return ompExtensionItemLines(text).some((i) => {
61323
+ const v2 = ompEntryValue(lines[i]);
61324
+ return OMP_ENTRY_RE.test(v2) && fs10.existsSync(v2);
61325
+ });
61326
+ }
60909
61327
  function ompRemove() {
60910
61328
  const file = ompConfigFile();
60911
- const entry = ompExtensionPath();
60912
- if (!fs9.existsSync(file)) return `omp: not installed (${file})`;
60913
- const text = fs9.readFileSync(file, "utf8");
60914
- const cleaned = text.split("\n").filter((line) => ompEntryValue(line) !== entry).join("\n");
60915
- if (cleaned === text) return `omp: not installed (${file})`;
61329
+ if (!fs10.existsSync(file)) return `omp: not installed (${file})`;
61330
+ const text = fs10.readFileSync(file, "utf8");
61331
+ const lines = text.split("\n");
61332
+ const drop = new Set(
61333
+ ompExtensionItemLines(text).filter((i) => OMP_ENTRY_RE.test(ompEntryValue(lines[i])))
61334
+ );
61335
+ if (drop.size === 0) return `omp: not installed (${file})`;
61336
+ const cleaned = lines.filter((_2, i) => !drop.has(i)).join("\n");
60916
61337
  backupOnce(file);
60917
- fs9.writeFileSync(file, cleaned);
61338
+ fs10.writeFileSync(file, cleaned);
60918
61339
  return `omp: removed from ${file}`;
60919
61340
  }
60920
61341
  function ompInstall() {
60921
61342
  const file = ompConfigFile();
60922
61343
  const entry = ompExtensionPath();
60923
61344
  requireDistFile(entry);
60924
- fs9.mkdirSync(path12.dirname(file), { recursive: true });
60925
- const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
60926
- if (text.split("\n").some((line) => ompEntryValue(line) === entry)) return `omp: already installed (${file})`;
61345
+ fs10.mkdirSync(path13.dirname(file), { recursive: true });
61346
+ let text = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "";
61347
+ if (ompBlockLoaded(text)) return `omp: already installed (${file})`;
61348
+ {
61349
+ const lines = text.split("\n");
61350
+ const stale = new Set(ompExtensionItemLines(text).filter((i) => ompEntryValue(lines[i]) === entry));
61351
+ if (stale.size > 0) text = lines.filter((_2, i) => !stale.has(i)).join("\n");
61352
+ }
60927
61353
  const keyCount = (text.match(/^extensions:/gm) ?? []).length;
60928
61354
  if (keyCount > 1) throw new Error(`${file}: multiple \`extensions:\` keys \u2014 fix the file first, refusing to edit`);
60929
61355
  if (/^extensions:\s*\S/m.test(text) && !/^extensions:\s*$/m.test(text)) {
@@ -60953,26 +61379,31 @@ ${tail}`;
60953
61379
  - ${entry}
60954
61380
  `;
60955
61381
  }
60956
- const occurrences = out.split("\n").filter((line) => ompEntryValue(line) === entry).length;
61382
+ const outLines = out.split("\n");
61383
+ const occurrences = ompExtensionItemLines(out).filter((i) => ompEntryValue(outLines[i]) === entry).length;
60957
61384
  if (occurrences !== 1) {
60958
61385
  throw new Error(`${file}: edit would leave ${occurrences} copies of the entry \u2014 aborting without writing`);
60959
61386
  }
60960
61387
  backupOnce(file);
60961
- fs9.writeFileSync(file, out);
61388
+ fs10.writeFileSync(file, out);
60962
61389
  return `omp: installed -> ${file} extensions += ${entry}`;
60963
61390
  }
60964
61391
  function ompStatus() {
60965
61392
  const file = ompConfigFile();
60966
- const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
60967
- return text.split("\n").some((line) => ompEntryValue(line) === ompExtensionPath()) ? "installed" : "not installed";
61393
+ const text = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "";
61394
+ const lines = text.split("\n");
61395
+ let broken = false;
61396
+ for (const i of ompExtensionItemLines(text)) {
61397
+ const v2 = ompEntryValue(lines[i]);
61398
+ if (!OMP_ENTRY_RE.test(v2)) continue;
61399
+ if (fs10.existsSync(v2)) return "installed";
61400
+ broken = true;
61401
+ }
61402
+ return broken ? "broken" : "not installed";
60968
61403
  }
60969
61404
  function ompPluginLoadedFrom(ompHome) {
60970
61405
  try {
60971
- const text = fs9.readFileSync(path12.join(ompHome, "config.yml"), "utf8");
60972
- return text.split("\n").some((line) => {
60973
- const v2 = ompEntryValue(line);
60974
- return /[\\/]dist[\\/]agent[\\/]omp\.js$/.test(v2) && fs9.existsSync(v2);
60975
- });
61406
+ return ompBlockLoaded(fs10.readFileSync(path13.join(ompHome, "config.yml"), "utf8"));
60976
61407
  } catch {
60977
61408
  return false;
60978
61409
  }
@@ -60983,11 +61414,11 @@ function claudeMcpJson() {
60983
61414
  }
60984
61415
  function claudeInstall() {
60985
61416
  const root = selfPackageRoot();
60986
- const mcpJs = path12.join(root, "dist", "mcp.js");
61417
+ const mcpJs = path13.join(root, "dist", "mcp.js");
60987
61418
  requireDistFile(mcpJs);
60988
61419
  const claude = process.env.CLAUDE?.trim() || "claude";
60989
61420
  try {
60990
- execFileSync2(claude, ["mcp", "add", "bili", "--scope", "user", "-e", `BILI_MCP_PROXY=${resolveProxyOrigin()}`, "--", process.execPath, mcpJs], { stdio: ["ignore", "pipe", "pipe"], timeout: CLAUDE_EXEC_TIMEOUT_MS });
61421
+ execFileSync2(claude, ["mcp", "add", "bili", "--scope", "user", "-e", `BILI_MCP_PROXY=${proxyOriginForInstall()}`, "--", process.execPath, mcpJs], { stdio: ["ignore", "pipe", "pipe"], timeout: CLAUDE_EXEC_TIMEOUT_MS });
60991
61422
  return `claude: installed via \`claude mcp add\` (user scope) -> ${claudeMcpJson()}`;
60992
61423
  } catch (err2) {
60993
61424
  const stderr = err2 instanceof Error && "stderr" in err2 ? String(err2.stderr ?? "") : "";
@@ -61010,38 +61441,38 @@ function claudeStatus() {
61010
61441
  }
61011
61442
  function codexToml() {
61012
61443
  const raw = process.env.CODEX_HOME?.trim();
61013
- if (raw && raw.length > 0) return path12.join(raw, "config.toml");
61444
+ if (raw && raw.length > 0) return path13.join(raw, "config.toml");
61014
61445
  return homeFile(".codex/config.toml");
61015
61446
  }
61016
61447
  function codexBlock() {
61017
61448
  return `
61018
61449
  [mcp_servers.bili]
61019
61450
  command = ${JSON.stringify(process.execPath)}
61020
- args = [${JSON.stringify(path12.join(selfPackageRoot(), "dist", "mcp.js"))}]
61021
- env = { BILI_MCP_PROXY = ${JSON.stringify(resolveProxyOrigin())} }
61451
+ args = [${JSON.stringify(path13.join(selfPackageRoot(), "dist", "mcp.js"))}]
61452
+ env = { BILI_MCP_PROXY = ${JSON.stringify(proxyOriginForInstall())} }
61022
61453
  `;
61023
61454
  }
61024
61455
  function codexInstall() {
61025
61456
  const file = codexToml();
61026
- const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
61457
+ const text = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "";
61027
61458
  const existing = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
61028
61459
  if (existing !== null) {
61029
61460
  const block = text.slice(existing.index, text.indexOf("\n[", existing.index + 1) === -1 ? void 0 : text.indexOf("\n[", existing.index + 1));
61030
- if (block.includes(`BILI_MCP_PROXY = ${JSON.stringify(resolveProxyOrigin())}`)) return `codex: already installed (${file})`;
61461
+ if (block.includes(`BILI_MCP_PROXY = ${JSON.stringify(proxyOriginForInstall())}`)) return `codex: already installed (${file})`;
61031
61462
  const refreshed = text.slice(0, existing.index) + codexBlock().replace(/^\n/, "") + text.slice(existing.index + block.length);
61032
61463
  backupOnce(file);
61033
- fs9.writeFileSync(file, refreshed);
61464
+ fs10.writeFileSync(file, refreshed);
61034
61465
  return `codex: refreshed proxy origin -> ${file} [mcp_servers.bili]`;
61035
61466
  }
61036
- fs9.mkdirSync(path12.dirname(file), { recursive: true });
61467
+ fs10.mkdirSync(path13.dirname(file), { recursive: true });
61037
61468
  backupOnce(file);
61038
- fs9.writeFileSync(file, text + (text.endsWith("\n") || text.length === 0 ? "" : "\n") + codexBlock());
61469
+ fs10.writeFileSync(file, text + (text.endsWith("\n") || text.length === 0 ? "" : "\n") + codexBlock());
61039
61470
  return `codex: installed -> ${file} [mcp_servers.bili]`;
61040
61471
  }
61041
61472
  function codexRemove() {
61042
61473
  const file = codexToml();
61043
- if (!fs9.existsSync(file)) return `codex: not installed (${file})`;
61044
- const text = fs9.readFileSync(file, "utf8");
61474
+ if (!fs10.existsSync(file)) return `codex: not installed (${file})`;
61475
+ const text = fs10.readFileSync(file, "utf8");
61045
61476
  const start = (() => {
61046
61477
  const m2 = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
61047
61478
  return m2 === null ? -1 : m2.index;
@@ -61054,28 +61485,28 @@ function codexRemove() {
61054
61485
  const end = nextTable >= 0 ? start + firstNewline + 1 + nextTable : text.length;
61055
61486
  const cleaned = (text.slice(0, lineStart).replace(/\n+$/, "\n") + text.slice(end)).replace(/^\n+/, "");
61056
61487
  backupOnce(file);
61057
- fs9.writeFileSync(file, cleaned);
61488
+ fs10.writeFileSync(file, cleaned);
61058
61489
  return `codex: removed from ${file}`;
61059
61490
  }
61060
61491
  function codexStatus() {
61061
- const text = fs9.existsSync(codexToml()) ? fs9.readFileSync(codexToml(), "utf8") : "";
61492
+ const text = fs10.existsSync(codexToml()) ? fs10.readFileSync(codexToml(), "utf8") : "";
61062
61493
  return /^\[mcp_servers\.bili\]\s*$/m.test(text) ? "installed" : "not installed";
61063
61494
  }
61064
61495
  function opencodeJson() {
61065
61496
  const raw = process.env.OPENCODE_CONFIG?.trim();
61066
61497
  if (raw && raw.length > 0) return raw;
61067
61498
  const xdg2 = process.env.XDG_CONFIG_HOME?.trim();
61068
- if (xdg2 && xdg2.length > 0) return path12.join(xdg2, "opencode/opencode.json");
61069
- return path12.join(os4.homedir(), ".config", "opencode", "opencode.json");
61499
+ if (xdg2 && xdg2.length > 0) return path13.join(xdg2, "opencode/opencode.json");
61500
+ return path13.join(os4.homedir(), ".config", "opencode", "opencode.json");
61070
61501
  }
61071
61502
  function opencodeInstall() {
61072
61503
  const file = opencodeJson();
61073
- const mcpJs = path12.join(selfPackageRoot(), "dist", "mcp.js");
61504
+ const mcpJs = path13.join(selfPackageRoot(), "dist", "mcp.js");
61074
61505
  requireDistFile(mcpJs);
61075
61506
  const data = readJson(file);
61076
61507
  const mcp = data.mcp ?? {};
61077
61508
  if ("bili" in mcp) return `opencode: already installed (${file})`;
61078
- mcp.bili = { type: "local", command: [process.execPath, mcpJs], environment: { BILI_MCP_PROXY: resolveProxyOrigin() }, enabled: true };
61509
+ mcp.bili = { type: "local", command: [process.execPath, mcpJs], environment: { BILI_MCP_PROXY: proxyOriginForInstall() }, enabled: true };
61079
61510
  data.mcp = mcp;
61080
61511
  writeJson(file, data);
61081
61512
  return `opencode: installed -> ${file} mcp.bili`;
@@ -61121,15 +61552,15 @@ function pluginStatusAll() {
61121
61552
  }
61122
61553
 
61123
61554
  // src/launcher.ts
61124
- import { randomUUID as randomUUID4 } from "crypto";
61125
- import fs10 from "fs";
61555
+ import { randomUUID as randomUUID5 } from "crypto";
61556
+ import fs11 from "fs";
61126
61557
  import net2 from "net";
61127
61558
  import os5 from "os";
61128
- import path13 from "path";
61559
+ import path14 from "path";
61129
61560
  import { pathToFileURL } from "url";
61130
61561
  import { spawn } from "child_process";
61131
61562
  function selfDistFile(name) {
61132
- return path13.join(selfPackageRoot(), "dist", name);
61563
+ return path14.join(selfPackageRoot(), "dist", name);
61133
61564
  }
61134
61565
  var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
61135
61566
  var LAUNCHER_DEFAULT_PORT = 8787;
@@ -61165,12 +61596,12 @@ function unwrapUpstream2(url) {
61165
61596
  return idx >= 0 ? url.slice(idx + "/bili/".length) : url;
61166
61597
  }
61167
61598
  function resolveCaCertPath(env) {
61168
- const base = env.XDG_DATA_HOME || path13.join(os5.homedir(), ".local/share");
61169
- return path13.join(base, "billion-context", "ca", "root-ca.pem");
61599
+ const base = env.XDG_DATA_HOME || path14.join(os5.homedir(), ".local/share");
61600
+ return path14.join(base, "billion-context", "ca", "root-ca.pem");
61170
61601
  }
61171
61602
  function resolveCombinedCaPath(env) {
61172
- const base = env.XDG_DATA_HOME || path13.join(os5.homedir(), ".local/share");
61173
- return path13.join(base, "billion-context", "ca", "combined-ca.pem");
61603
+ const base = env.XDG_DATA_HOME || path14.join(os5.homedir(), ".local/share");
61604
+ return path14.join(base, "billion-context", "ca", "combined-ca.pem");
61174
61605
  }
61175
61606
  function discoverRoutes(client, config) {
61176
61607
  const httpsDomains = [];
@@ -61403,12 +61834,12 @@ function buildCodexMcpArgs(origin, conversationId2) {
61403
61834
  ];
61404
61835
  }
61405
61836
  function overlayLockPath(overlay) {
61406
- return path13.join(overlay, ".bili-launch.pid");
61837
+ return path14.join(overlay, ".bili-launch.pid");
61407
61838
  }
61408
61839
  function livePidHoldsOverlay(overlay) {
61409
61840
  let raw;
61410
61841
  try {
61411
- raw = fs10.readFileSync(overlayLockPath(overlay), "utf8");
61842
+ raw = fs11.readFileSync(overlayLockPath(overlay), "utf8");
61412
61843
  } catch {
61413
61844
  return void 0;
61414
61845
  }
@@ -61422,10 +61853,10 @@ function livePidHoldsOverlay(overlay) {
61422
61853
  return pid;
61423
61854
  }
61424
61855
  function linkOverlayEntry(realHome, overlay, entry) {
61425
- const target = path13.join(realHome, entry);
61426
- const link = path13.join(overlay, entry);
61856
+ const target = path14.join(realHome, entry);
61857
+ const link = path14.join(overlay, entry);
61427
61858
  try {
61428
- fs10.symlinkSync(target, link);
61859
+ fs11.symlinkSync(target, link);
61429
61860
  return true;
61430
61861
  } catch (err2) {
61431
61862
  const code = err2.code;
@@ -61433,24 +61864,24 @@ function linkOverlayEntry(realHome, overlay, entry) {
61433
61864
  }
61434
61865
  let st2;
61435
61866
  try {
61436
- st2 = fs10.lstatSync(target);
61867
+ st2 = fs11.lstatSync(target);
61437
61868
  } catch {
61438
61869
  return false;
61439
61870
  }
61440
61871
  if (st2.isDirectory()) {
61441
61872
  try {
61442
- fs10.symlinkSync(target, link, "junction");
61873
+ fs11.symlinkSync(target, link, "junction");
61443
61874
  return true;
61444
61875
  } catch {
61445
61876
  return false;
61446
61877
  }
61447
61878
  }
61448
61879
  try {
61449
- fs10.linkSync(target, link);
61880
+ fs11.linkSync(target, link);
61450
61881
  return true;
61451
61882
  } catch {
61452
61883
  try {
61453
- fs10.copyFileSync(target, link);
61884
+ fs11.copyFileSync(target, link);
61454
61885
  return true;
61455
61886
  } catch {
61456
61887
  return false;
@@ -61460,7 +61891,7 @@ function linkOverlayEntry(realHome, overlay, entry) {
61460
61891
  function isWriteThroughHardlink(overlayPath, realPath, st2) {
61461
61892
  if (st2.isDirectory() || st2.isSymbolicLink() || st2.nlink <= 1) return false;
61462
61893
  try {
61463
- const realSt = fs10.lstatSync(realPath);
61894
+ const realSt = fs11.lstatSync(realPath);
61464
61895
  return st2.dev === realSt.dev && st2.ino === realSt.ino;
61465
61896
  } catch {
61466
61897
  return false;
@@ -61472,7 +61903,7 @@ function sqliteSetMembers(base) {
61472
61903
  function mergeSqliteSet(overlay, realHome, base) {
61473
61904
  const members = sqliteSetMembers(base).filter((m2) => {
61474
61905
  try {
61475
- return fs10.lstatSync(path13.join(overlay, m2)).isFile();
61906
+ return fs11.lstatSync(path14.join(overlay, m2)).isFile();
61476
61907
  } catch {
61477
61908
  return false;
61478
61909
  }
@@ -61490,44 +61921,44 @@ function mergeSqliteSet(overlay, realHome, base) {
61490
61921
  };
61491
61922
  try {
61492
61923
  for (const m2 of members) {
61493
- const src = path13.join(overlay, m2);
61494
- const dst = path13.join(realHome, m2);
61924
+ const src = path14.join(overlay, m2);
61925
+ const dst = path14.join(realHome, m2);
61495
61926
  let dstStat;
61496
61927
  try {
61497
- dstStat = fs10.lstatSync(dst);
61928
+ dstStat = fs11.lstatSync(dst);
61498
61929
  } catch {
61499
61930
  }
61500
61931
  if (dstStat && dstStat.isDirectory()) {
61501
61932
  rollback();
61502
61933
  return false;
61503
61934
  }
61504
- const srcStat = fs10.lstatSync(src);
61935
+ const srcStat = fs11.lstatSync(src);
61505
61936
  if (dstStat && dstStat.mtimeMs >= srcStat.mtimeMs) {
61506
61937
  try {
61507
- fs10.renameSync(src, `${dst}.bili-conflict`);
61938
+ fs11.renameSync(src, `${dst}.bili-conflict`);
61508
61939
  } catch {
61509
61940
  rollback();
61510
61941
  return false;
61511
61942
  }
61512
- undo.push(() => fs10.renameSync(`${dst}.bili-conflict`, src));
61943
+ undo.push(() => fs11.renameSync(`${dst}.bili-conflict`, src));
61513
61944
  continue;
61514
61945
  }
61515
61946
  if (dstStat) {
61516
61947
  try {
61517
- fs10.renameSync(dst, `${dst}.bili-conflict`);
61948
+ fs11.renameSync(dst, `${dst}.bili-conflict`);
61518
61949
  } catch {
61519
61950
  rollback();
61520
61951
  return false;
61521
61952
  }
61522
- undo.push(() => fs10.renameSync(`${dst}.bili-conflict`, dst));
61953
+ undo.push(() => fs11.renameSync(`${dst}.bili-conflict`, dst));
61523
61954
  }
61524
61955
  try {
61525
- fs10.renameSync(src, dst);
61956
+ fs11.renameSync(src, dst);
61526
61957
  } catch {
61527
61958
  rollback();
61528
61959
  return false;
61529
61960
  }
61530
- undo.push(() => fs10.renameSync(dst, src));
61961
+ undo.push(() => fs11.renameSync(dst, src));
61531
61962
  }
61532
61963
  return true;
61533
61964
  } catch {
@@ -61537,7 +61968,7 @@ function mergeSqliteSet(overlay, realHome, base) {
61537
61968
  }
61538
61969
  function refreshOverlayHome(realHome, overlay, generatedFile) {
61539
61970
  try {
61540
- fs10.mkdirSync(overlay, { recursive: true });
61971
+ fs11.mkdirSync(overlay, { recursive: true });
61541
61972
  } catch {
61542
61973
  return false;
61543
61974
  }
@@ -61548,19 +61979,19 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61548
61979
  );
61549
61980
  }
61550
61981
  try {
61551
- fs10.writeFileSync(overlayLockPath(overlay), `${process.pid}
61982
+ fs11.writeFileSync(overlayLockPath(overlay), `${process.pid}
61552
61983
  `);
61553
61984
  } catch {
61554
61985
  }
61555
61986
  const realEntries = /* @__PURE__ */ new Set();
61556
61987
  try {
61557
- for (const entry of fs10.readdirSync(realHome)) realEntries.add(entry);
61988
+ for (const entry of fs11.readdirSync(realHome)) realEntries.add(entry);
61558
61989
  } catch {
61559
61990
  }
61560
61991
  try {
61561
61992
  let overlayEntries;
61562
61993
  try {
61563
- overlayEntries = fs10.readdirSync(overlay);
61994
+ overlayEntries = fs11.readdirSync(overlay);
61564
61995
  } catch {
61565
61996
  overlayEntries = [];
61566
61997
  }
@@ -61571,10 +62002,10 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61571
62002
  if (!members.some((m2) => m2 !== entry && overlayEntries.includes(m2))) continue;
61572
62003
  let mainSt;
61573
62004
  try {
61574
- mainSt = fs10.lstatSync(path13.join(overlay, entry));
62005
+ mainSt = fs11.lstatSync(path14.join(overlay, entry));
61575
62006
  } catch {
61576
62007
  }
61577
- const keepSidecars = mainSt !== void 0 && isWriteThroughHardlink(path13.join(overlay, entry), path13.join(realHome, entry), mainSt);
62008
+ const keepSidecars = mainSt !== void 0 && isWriteThroughHardlink(path14.join(overlay, entry), path14.join(realHome, entry), mainSt);
61578
62009
  dbSets.push({ base: entry, keepSidecars });
61579
62010
  }
61580
62011
  const skipEntries = /* @__PURE__ */ new Set();
@@ -61585,10 +62016,10 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61585
62016
  }
61586
62017
  for (const entry of overlayEntries) {
61587
62018
  if (entry === generatedFile) continue;
61588
- const overlayPath = path13.join(overlay, entry);
62019
+ const overlayPath = path14.join(overlay, entry);
61589
62020
  if (entry.startsWith(`.${generatedFile}.`) && entry.endsWith(".tmp")) {
61590
62021
  try {
61591
- fs10.unlinkSync(overlayPath);
62022
+ fs11.unlinkSync(overlayPath);
61592
62023
  } catch {
61593
62024
  }
61594
62025
  continue;
@@ -61596,33 +62027,33 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61596
62027
  if (skipEntries.has(entry)) continue;
61597
62028
  let st2;
61598
62029
  try {
61599
- st2 = fs10.lstatSync(overlayPath);
62030
+ st2 = fs11.lstatSync(overlayPath);
61600
62031
  } catch {
61601
62032
  continue;
61602
62033
  }
61603
62034
  if (st2.isSymbolicLink()) {
61604
62035
  let target;
61605
62036
  try {
61606
- target = fs10.readlinkSync(overlayPath);
62037
+ target = fs11.readlinkSync(overlayPath);
61607
62038
  } catch {
61608
62039
  }
61609
- const wanted = realEntries.has(entry) ? path13.join(realHome, entry) : void 0;
62040
+ const wanted = realEntries.has(entry) ? path14.join(realHome, entry) : void 0;
61610
62041
  if (!wanted || target !== wanted) {
61611
62042
  try {
61612
- fs10.unlinkSync(overlayPath);
62043
+ fs11.unlinkSync(overlayPath);
61613
62044
  } catch {
61614
62045
  }
61615
62046
  }
61616
62047
  } else if (realEntries.has(entry)) {
61617
- const realPath = path13.join(realHome, entry);
62048
+ const realPath = path14.join(realHome, entry);
61618
62049
  if (isWriteThroughHardlink(overlayPath, realPath, st2)) {
61619
62050
  try {
61620
- fs10.unlinkSync(overlayPath);
62051
+ fs11.unlinkSync(overlayPath);
61621
62052
  } catch {
61622
62053
  }
61623
- } else if (mergeOverlayEntry(overlayPath, realPath)) {
62054
+ } else if (mergeOverlayEntry(overlayPath, realPath, generatedFile)) {
61624
62055
  try {
61625
- fs10.rmSync(overlayPath, { recursive: true, force: true });
62056
+ fs11.rmSync(overlayPath, { recursive: true, force: true });
61626
62057
  } catch {
61627
62058
  }
61628
62059
  } else {
@@ -61644,10 +62075,10 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61644
62075
  for (const entry of realEntries) {
61645
62076
  if (entry === generatedFile) continue;
61646
62077
  total += 1;
61647
- const overlayPath = path13.join(overlay, entry);
62078
+ const overlayPath = path14.join(overlay, entry);
61648
62079
  let present = false;
61649
62080
  try {
61650
- fs10.lstatSync(overlayPath);
62081
+ fs11.lstatSync(overlayPath);
61651
62082
  present = true;
61652
62083
  } catch {
61653
62084
  }
@@ -61676,47 +62107,48 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
61676
62107
  }
61677
62108
  return true;
61678
62109
  }
61679
- function mergeOverlayEntry(src, dst) {
62110
+ function mergeOverlayEntry(src, dst, excludedName) {
61680
62111
  let st2;
61681
62112
  try {
61682
- st2 = fs10.lstatSync(src);
62113
+ st2 = fs11.lstatSync(src);
61683
62114
  } catch {
61684
62115
  return true;
61685
62116
  }
61686
62117
  let dstStat;
61687
62118
  try {
61688
- dstStat = fs10.lstatSync(dst);
62119
+ dstStat = fs11.lstatSync(dst);
61689
62120
  } catch {
61690
62121
  }
61691
62122
  if (st2.isDirectory()) {
61692
62123
  if (dstStat && !dstStat.isDirectory()) {
61693
62124
  try {
61694
- fs10.renameSync(dst, `${dst}.bili-conflict`);
62125
+ fs11.renameSync(dst, `${dst}.bili-conflict`);
61695
62126
  dstStat = void 0;
61696
62127
  } catch {
61697
62128
  return false;
61698
62129
  }
61699
62130
  }
61700
62131
  try {
61701
- fs10.mkdirSync(dst, { recursive: true });
62132
+ fs11.mkdirSync(dst, { recursive: true });
61702
62133
  } catch {
61703
62134
  return false;
61704
62135
  }
61705
62136
  let entries;
61706
62137
  try {
61707
- entries = fs10.readdirSync(src);
62138
+ entries = fs11.readdirSync(src);
61708
62139
  } catch {
61709
62140
  return false;
61710
62141
  }
61711
62142
  let ok = true;
61712
62143
  for (const entry of entries) {
61713
- if (!mergeOverlayEntry(path13.join(src, entry), path13.join(dst, entry))) ok = false;
62144
+ if (excludedName !== void 0 && entry === excludedName) continue;
62145
+ if (!mergeOverlayEntry(path14.join(src, entry), path14.join(dst, entry), excludedName)) ok = false;
61714
62146
  }
61715
62147
  return ok;
61716
62148
  }
61717
62149
  if (dstStat && dstStat.isDirectory()) {
61718
62150
  try {
61719
- fs10.renameSync(src, `${dst}.bili-conflict`);
62151
+ fs11.renameSync(src, `${dst}.bili-conflict`);
61720
62152
  return true;
61721
62153
  } catch {
61722
62154
  return false;
@@ -61725,13 +62157,13 @@ function mergeOverlayEntry(src, dst) {
61725
62157
  if (st2.isSymbolicLink()) {
61726
62158
  if (dstStat) {
61727
62159
  try {
61728
- fs10.unlinkSync(src);
62160
+ fs11.unlinkSync(src);
61729
62161
  } catch {
61730
62162
  }
61731
62163
  return true;
61732
62164
  }
61733
62165
  try {
61734
- fs10.renameSync(src, dst);
62166
+ fs11.renameSync(src, dst);
61735
62167
  } catch {
61736
62168
  return false;
61737
62169
  }
@@ -61739,7 +62171,7 @@ function mergeOverlayEntry(src, dst) {
61739
62171
  }
61740
62172
  if (dstStat && dstStat.mtimeMs >= st2.mtimeMs) {
61741
62173
  try {
61742
- fs10.renameSync(src, `${dst}.bili-conflict`);
62174
+ fs11.renameSync(src, `${dst}.bili-conflict`);
61743
62175
  return true;
61744
62176
  } catch {
61745
62177
  return false;
@@ -61747,13 +62179,13 @@ function mergeOverlayEntry(src, dst) {
61747
62179
  }
61748
62180
  if (dstStat) {
61749
62181
  try {
61750
- fs10.renameSync(dst, `${dst}.bili-conflict`);
62182
+ fs11.renameSync(dst, `${dst}.bili-conflict`);
61751
62183
  } catch {
61752
62184
  return false;
61753
62185
  }
61754
62186
  }
61755
62187
  try {
61756
- fs10.renameSync(src, dst);
62188
+ fs11.renameSync(src, dst);
61757
62189
  return true;
61758
62190
  } catch {
61759
62191
  return false;
@@ -61763,7 +62195,7 @@ function piPluginInstalled(piHome) {
61763
62195
  const root = selfPackageRoot();
61764
62196
  if (!root) return false;
61765
62197
  try {
61766
- const parsed = JSON.parse(fs10.readFileSync(path13.join(piHome, "settings.json"), "utf8"));
62198
+ const parsed = JSON.parse(fs11.readFileSync(path14.join(piHome, "settings.json"), "utf8"));
61767
62199
  const list = Array.isArray(parsed.packages) ? parsed.packages.map(String) : [];
61768
62200
  return list.some((p2) => isBiliPiEntry(p2, root));
61769
62201
  } catch {
@@ -61771,23 +62203,23 @@ function piPluginInstalled(piHome) {
61771
62203
  }
61772
62204
  }
61773
62205
  function writeOverlayFileAtomic(overlay, fileName, contents) {
61774
- const draft = path13.join(overlay, `.${fileName}.${process.pid}.tmp`);
62206
+ const draft = path14.join(overlay, `.${fileName}.${process.pid}.tmp`);
61775
62207
  try {
61776
- fs10.writeFileSync(draft, contents);
61777
- fs10.renameSync(draft, path13.join(overlay, fileName));
62208
+ fs11.writeFileSync(draft, contents);
62209
+ fs11.renameSync(draft, path14.join(overlay, fileName));
61778
62210
  } catch {
61779
62211
  try {
61780
- fs10.rmSync(draft, { force: true });
62212
+ fs11.rmSync(draft, { force: true });
61781
62213
  } catch {
61782
62214
  }
61783
62215
  }
61784
62216
  }
61785
62217
  function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
61786
62218
  if (httpRewrites.length === 0 && httpsRewrites.length === 0) return void 0;
61787
- const modelsPath = path13.join(piHome, "models.json");
62219
+ const modelsPath = path14.join(piHome, "models.json");
61788
62220
  let txt;
61789
62221
  try {
61790
- txt = fs10.readFileSync(modelsPath, "utf8");
62222
+ txt = fs11.readFileSync(modelsPath, "utf8");
61791
62223
  } catch {
61792
62224
  return void 0;
61793
62225
  }
@@ -61823,12 +62255,64 @@ function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
61823
62255
  writeOverlayFileAtomic(overlay, "models.json", JSON.stringify(root));
61824
62256
  return overlay;
61825
62257
  }
62258
+ function atomicWriteTextFile(filePath, contents) {
62259
+ const draft = `${filePath}.${process.pid}.bili-tmp`;
62260
+ try {
62261
+ fs11.writeFileSync(draft, contents);
62262
+ fs11.renameSync(draft, filePath);
62263
+ } catch {
62264
+ try {
62265
+ fs11.rmSync(draft, { force: true });
62266
+ } catch {
62267
+ }
62268
+ throw new Error(`bili: could not write ${filePath}`);
62269
+ }
62270
+ }
62271
+ function liveProxyPorts() {
62272
+ const ports = /* @__PURE__ */ new Set();
62273
+ const inst = readProxyInstanceFile();
62274
+ if (isProxyInstanceFile(inst)) {
62275
+ if (isPidAlive(inst.pid)) ports.add(inst.port);
62276
+ } else if (inst) {
62277
+ try {
62278
+ ports.add(new URL(inst.origin).port === "" ? 80 : Number(new URL(inst.origin).port));
62279
+ } catch {
62280
+ }
62281
+ }
62282
+ return ports;
62283
+ }
62284
+ function unpackDeadProxyUrlsInFile(filePath, livePorts) {
62285
+ let txt;
62286
+ try {
62287
+ txt = fs11.readFileSync(filePath, "utf8");
62288
+ } catch {
62289
+ return 0;
62290
+ }
62291
+ const re2 = /https?:\/\/(?:127\.0\.0\.1|localhost|\[::1\]):(\d+)\/bili\/(https?:\/\/\S+)/g;
62292
+ let changed = 0;
62293
+ const out = txt.replace(re2, (full, portStr, raw) => {
62294
+ if (livePorts.has(Number(portStr))) return full;
62295
+ changed += 1;
62296
+ return raw;
62297
+ });
62298
+ if (changed === 0) return 0;
62299
+ try {
62300
+ atomicWriteTextFile(filePath, out);
62301
+ } catch {
62302
+ return 0;
62303
+ }
62304
+ return changed;
62305
+ }
61826
62306
  function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
62307
+ const modelsPath = path14.join(ompHome, "models.yml");
62308
+ const unpacked = unpackDeadProxyUrlsInFile(modelsPath, liveProxyPorts());
62309
+ if (unpacked > 0) {
62310
+ console.error(`bili: unpacked ${unpacked} dead proxy URL(s) from the real ${modelsPath}`);
62311
+ }
61827
62312
  if (httpRewrites.length === 0 && httpsRewrites.length === 0) return void 0;
61828
- const modelsPath = path13.join(ompHome, "models.yml");
61829
62313
  let txt;
61830
62314
  try {
61831
- txt = fs10.readFileSync(modelsPath, "utf8");
62315
+ txt = fs11.readFileSync(modelsPath, "utf8");
61832
62316
  } catch {
61833
62317
  return void 0;
61834
62318
  }
@@ -61872,10 +62356,10 @@ function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
61872
62356
  }
61873
62357
  function prepareHermesHome(hermesHome, origin, rewrites) {
61874
62358
  if (rewrites.length === 0) return void 0;
61875
- const cfgPath = path13.join(hermesHome, "config.yaml");
62359
+ const cfgPath = path14.join(hermesHome, "config.yaml");
61876
62360
  let txt;
61877
62361
  try {
61878
- txt = fs10.readFileSync(cfgPath, "utf8");
62362
+ txt = fs11.readFileSync(cfgPath, "utf8");
61879
62363
  } catch {
61880
62364
  return void 0;
61881
62365
  }
@@ -61902,21 +62386,21 @@ function prepareHermesHome(hermesHome, origin, rewrites) {
61902
62386
  }
61903
62387
  function writeHermesIdentityPlugin(hermesHome, overlay, rewrites) {
61904
62388
  try {
61905
- if (fs10.existsSync(path13.join(hermesHome, "plugins"))) return false;
62389
+ if (fs11.existsSync(path14.join(hermesHome, "plugins"))) return false;
61906
62390
  } catch {
61907
62391
  return false;
61908
62392
  }
61909
- const dir = path13.join("plugins", "model-providers", "bili-session-identity");
62393
+ const dir = path14.join("plugins", "model-providers", "bili-session-identity");
61910
62394
  try {
61911
- fs10.mkdirSync(path13.join(overlay, dir), { recursive: true });
62395
+ fs11.mkdirSync(path14.join(overlay, dir), { recursive: true });
61912
62396
  } catch {
61913
62397
  return false;
61914
62398
  }
61915
62399
  const keys = rewrites.map((r) => r.key);
61916
- const pluginDir = path13.join(overlay, dir);
62400
+ const pluginDir = path14.join(overlay, dir);
61917
62401
  try {
61918
- fs10.writeFileSync(path13.join(pluginDir, "__init__.py"), hermesIdentityPluginSource(keys));
61919
- fs10.writeFileSync(path13.join(pluginDir, "plugin.yaml"), [
62402
+ fs11.writeFileSync(path14.join(pluginDir, "__init__.py"), hermesIdentityPluginSource(keys));
62403
+ fs11.writeFileSync(path14.join(pluginDir, "plugin.yaml"), [
61920
62404
  "name: bili-session-identity",
61921
62405
  "kind: model-provider",
61922
62406
  "version: 1.0.0",
@@ -61928,7 +62412,7 @@ function writeHermesIdentityPlugin(hermesHome, overlay, rewrites) {
61928
62412
  return false;
61929
62413
  }
61930
62414
  try {
61931
- return fs10.existsSync(path13.join(overlay, dir, "__init__.py"));
62415
+ return fs11.existsSync(path14.join(overlay, dir, "__init__.py"));
61932
62416
  } catch {
61933
62417
  return false;
61934
62418
  }
@@ -61985,10 +62469,10 @@ function hermesIdentityPluginSource(providerKeys) {
61985
62469
  ].join("\n");
61986
62470
  }
61987
62471
  function prepareDshHome(dshHome, origin, rewrites) {
61988
- const cfgPath = path13.join(dshHome, "settings.yaml");
62472
+ const cfgPath = path14.join(dshHome, "settings.yaml");
61989
62473
  let txt;
61990
62474
  try {
61991
- txt = fs10.readFileSync(cfgPath, "utf8");
62475
+ txt = fs11.readFileSync(cfgPath, "utf8");
61992
62476
  } catch {
61993
62477
  return void 0;
61994
62478
  }
@@ -62016,16 +62500,16 @@ function writeDshAcpPatch(dshHome) {
62016
62500
  const pluginUrl = pathToFileURL(selfDistFile("agent/dsh-acp.js")).href;
62017
62501
  const dir = `${dshHome}-bili`;
62018
62502
  try {
62019
- fs10.mkdirSync(dir, { recursive: true });
62503
+ fs11.mkdirSync(dir, { recursive: true });
62020
62504
  } catch {
62021
62505
  return void 0;
62022
62506
  }
62023
62507
  writeOverlayFileAtomic(dir, ".bili-acp.patch.yml", `- insert:
62024
62508
  - name: ${pluginUrl}
62025
62509
  `);
62026
- const file = path13.join(dir, ".bili-acp.patch.yml");
62510
+ const file = path14.join(dir, ".bili-acp.patch.yml");
62027
62511
  try {
62028
- return fs10.existsSync(file) ? file : void 0;
62512
+ return fs11.existsSync(file) ? file : void 0;
62029
62513
  } catch {
62030
62514
  return void 0;
62031
62515
  }
@@ -62040,7 +62524,7 @@ function prepareOpencodeHttpRewrite(configFile2, origin, httpRewrites, httpsRewr
62040
62524
  if (httpRewrites.length === 0 && httpsRewrites.length === 0 && !pluginPath) return void 0;
62041
62525
  let root = {};
62042
62526
  try {
62043
- const txt = fs10.readFileSync(configFile2, "utf8");
62527
+ const txt = fs11.readFileSync(configFile2, "utf8");
62044
62528
  const parsed = JSON.parse(txt);
62045
62529
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
62046
62530
  root = { ...parsed };
@@ -62068,9 +62552,9 @@ function prepareOpencodeHttpRewrite(configFile2, origin, httpRewrites, httpsRewr
62068
62552
  if (!plugins.includes(pluginPath)) plugins.push(pluginPath);
62069
62553
  root.plugin = plugins;
62070
62554
  }
62071
- const tmp = fs10.mkdtempSync(path13.join(os5.tmpdir(), "bili-opencode-"));
62072
- const tmpFile = path13.join(tmp, "opencode.json");
62073
- fs10.writeFileSync(tmpFile, JSON.stringify(root));
62555
+ const tmp = fs11.mkdtempSync(path14.join(os5.tmpdir(), "bili-opencode-"));
62556
+ const tmpFile = path14.join(tmp, "opencode.json");
62557
+ fs11.writeFileSync(tmpFile, JSON.stringify(root));
62074
62558
  return tmpFile;
62075
62559
  }
62076
62560
  function dedupeInOrder(list) {
@@ -62104,27 +62588,33 @@ async function probeHealth(origin, fetchImpl) {
62104
62588
  return false;
62105
62589
  }
62106
62590
  }
62107
- function findFreePort(preferred, host = LAUNCHER_DEFAULT_HOST) {
62108
- const tryBind = (port) => new Promise((resolve) => {
62109
- const srv = net2.createServer();
62110
- srv.once("error", () => resolve(false));
62111
- srv.once("listening", () => srv.close(() => resolve(true)));
62112
- srv.listen(port, host);
62113
- });
62114
- return tryBind(preferred).then((free) => {
62115
- if (free) return preferred;
62116
- return new Promise((resolve, reject) => {
62117
- const srv = net2.createServer();
62118
- srv.once("error", reject);
62119
- srv.listen(0, host, () => {
62120
- const addr = srv.address();
62121
- srv.close(() => {
62122
- if (addr && typeof addr === "object") resolve(addr.port);
62123
- else reject(new Error("could not allocate a free port"));
62124
- });
62125
- });
62126
- });
62127
- });
62591
+ async function fetchHealthInfoDefault(origin) {
62592
+ try {
62593
+ const res = await fetch(healthUrl(origin), { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
62594
+ if (!res.ok) return void 0;
62595
+ const data = await res.json();
62596
+ return { ok: Boolean(data.ok), instanceId: typeof data.instanceId === "string" ? data.instanceId : void 0 };
62597
+ } catch {
62598
+ return void 0;
62599
+ }
62600
+ }
62601
+ function instanceCompatible(inst, opts) {
62602
+ if (inst.host !== opts.host || inst.passthrough !== opts.passthrough) return false;
62603
+ const wantDomains = opts.mitmDomains ?? [];
62604
+ if (inst.mitmDomains.length !== wantDomains.length || inst.mitmDomains.some((d, i) => d !== wantDomains[i])) return false;
62605
+ const wantWindows = opts.modelWindows ?? {};
62606
+ const keys = Object.keys(wantWindows);
62607
+ if (Object.keys(inst.modelWindows).length !== keys.length) return false;
62608
+ return keys.every((k2) => inst.modelWindows[k2] === wantWindows[k2]);
62609
+ }
62610
+ async function probeExistingInstance(readInstance, fetchHealthInfo) {
62611
+ const inst = readInstance();
62612
+ if (!isProxyInstanceFile(inst)) return void 0;
62613
+ if (!isPidAlive(inst.pid)) return void 0;
62614
+ const health = await fetchHealthInfo(inst.origin);
62615
+ if (!health || !health.ok) return void 0;
62616
+ if (health.instanceId !== void 0 && health.instanceId !== inst.instanceId) return void 0;
62617
+ return inst;
62128
62618
  }
62129
62619
  var INHERITED_PROXY_VARS = ["http_proxy", "https_proxy", "all_proxy", "HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"];
62130
62620
  function stripInheritedProxy(env) {
@@ -62140,25 +62630,34 @@ function proxyStartArgs(opts) {
62140
62630
  }
62141
62631
  async function ensureProxyRunning(opts, deps = {}) {
62142
62632
  const fetchImpl = deps.fetchImpl ?? defaultFetch;
62633
+ const fetchHealthInfo = deps.fetchHealthInfo ?? fetchHealthInfoDefault;
62634
+ const readInstance = deps.readInstanceFile ?? readProxyInstanceFile;
62143
62635
  const spawnImpl = deps.spawnImpl ?? spawn;
62144
62636
  const now = deps.now ?? Date.now;
62145
62637
  const sleepImpl = deps.sleep ?? ((ms2) => new Promise((r) => setTimeout(r, ms2)));
62146
- const port = await findFreePort(opts.port, opts.host);
62147
- const spawnedOrigin = proxyOrigin(opts.host, port);
62638
+ const existing = await probeExistingInstance(readInstance, fetchHealthInfo);
62639
+ if (existing && instanceCompatible(existing, opts)) {
62640
+ console.error(`bili: attaching to running proxy at ${existing.origin} (pid ${existing.pid})`);
62641
+ return { origin: existing.origin, port: existing.port, attached: true };
62642
+ }
62643
+ const launchToken = randomUUID5();
62644
+ const port = opts.port;
62148
62645
  const script = process.argv[1];
62149
62646
  if (!script) throw new Error("bili: cannot resolve launcher script path");
62150
- const logPath2 = path13.join(os5.tmpdir(), `bili-proxy-${port}.log`);
62151
- const logFd = fs10.openSync(logPath2, "a");
62647
+ const logPath2 = path14.join(os5.tmpdir(), `bili-proxy-${port}.log`);
62648
+ const logFd = fs11.openSync(logPath2, "a");
62152
62649
  let child;
62153
62650
  try {
62154
62651
  child = spawnImpl(
62155
62652
  process.execPath,
62156
- [script, ...proxyStartArgs({ ...opts, port, debug: true })],
62653
+ [script, ...proxyStartArgs(opts)],
62157
62654
  {
62158
62655
  detached: true,
62159
62656
  stdio: ["ignore", logFd, logFd],
62160
62657
  env: {
62161
62658
  ...stripInheritedProxy(process.env),
62659
+ BILI_LAUNCH_TOKEN: launchToken,
62660
+ BILI_PARENT_PID: String(process.pid),
62162
62661
  ...opts.mitmDomains && opts.mitmDomains.length ? { BILI_MITM_DOMAINS: opts.mitmDomains.join(",") } : {},
62163
62662
  ...opts.modelWindows && Object.keys(opts.modelWindows).length > 0 ? { BILI_LAUNCHER_MODEL_WINDOWS: JSON.stringify(opts.modelWindows) } : {}
62164
62663
  }
@@ -62166,7 +62665,7 @@ async function ensureProxyRunning(opts, deps = {}) {
62166
62665
  );
62167
62666
  } finally {
62168
62667
  try {
62169
- fs10.closeSync(logFd);
62668
+ fs11.closeSync(logFd);
62170
62669
  } catch {
62171
62670
  }
62172
62671
  }
@@ -62177,16 +62676,28 @@ async function ensureProxyRunning(opts, deps = {}) {
62177
62676
  const deadline = now() + SPAWN_WAIT_MS;
62178
62677
  while (now() < deadline) {
62179
62678
  await sleepImpl(HEALTH_POLL_INTERVAL_MS);
62180
- if (await probeHealth(spawnedOrigin, fetchImpl)) {
62181
- return { origin: spawnedOrigin, port, child, logPath: logPath2 };
62679
+ const inst = readInstance();
62680
+ if (isProxyInstanceFile(inst) && inst.launchToken === launchToken) {
62681
+ if (await probeHealth(inst.origin, fetchImpl)) {
62682
+ return { origin: inst.origin, port: inst.port, child, logPath: logPath2 };
62683
+ }
62684
+ continue;
62685
+ }
62686
+ const stale = !isProxyInstanceFile(inst) || !isPidAlive(inst.pid);
62687
+ if (stale && await probeHealth(proxyOrigin(opts.host, port), fetchImpl)) {
62688
+ return { origin: proxyOrigin(opts.host, port), port, child, logPath: logPath2 };
62182
62689
  }
62183
62690
  }
62184
- throw new Error(`bili: proxy did not become healthy at ${spawnedOrigin} within ${SPAWN_WAIT_MS}ms`);
62691
+ throw new Error(`bili: proxy did not become healthy within ${SPAWN_WAIT_MS}ms (log: ${logPath2})`);
62185
62692
  }
62186
62693
  function stopProxy(handle2) {
62694
+ if (handle2.attached) return;
62187
62695
  const child = handle2.child;
62188
62696
  if (!child || child.pid === void 0) return;
62189
- if (process.platform !== "win32" && child.pid > 0) {
62697
+ if (process.platform === "win32") {
62698
+ return;
62699
+ }
62700
+ if (child.pid > 0) {
62190
62701
  try {
62191
62702
  process.kill(-child.pid);
62192
62703
  } catch {
@@ -62213,12 +62724,12 @@ var PATH_EXTS = process.platform === "win32" ? [".cmd", ".bat", ".exe", ""] : ["
62213
62724
  function resolveOnPath(name, env) {
62214
62725
  const p2 = env.PATH;
62215
62726
  if (!p2) return void 0;
62216
- for (const dir of p2.split(path13.delimiter)) {
62727
+ for (const dir of p2.split(path14.delimiter)) {
62217
62728
  if (!dir) continue;
62218
62729
  for (const ext of PATH_EXTS) {
62219
- const f2 = path13.join(dir, name + ext);
62730
+ const f2 = path14.join(dir, name + ext);
62220
62731
  try {
62221
- if (fs10.existsSync(f2) && fs10.statSync(f2).isFile()) return f2;
62732
+ if (fs11.existsSync(f2) && fs11.statSync(f2).isFile()) return f2;
62222
62733
  } catch {
62223
62734
  }
62224
62735
  }
@@ -62236,7 +62747,7 @@ function resolveClientCommand(client, env) {
62236
62747
  if (piBin) return { command: piBin, prefixArgs: [] };
62237
62748
  const piResolved = resolveOnPath("pi", env);
62238
62749
  if (piResolved) return { command: piResolved, prefixArgs: [] };
62239
- const cli = path13.join(
62750
+ const cli = path14.join(
62240
62751
  os5.homedir(),
62241
62752
  ".pi/agent/npm/node_modules/@earendil-works/pi-coding-agent/dist/cli.js"
62242
62753
  );
@@ -62308,7 +62819,7 @@ async function runLaunch(params, deps = {}) {
62308
62819
  piOverlayHome = preparePiHttpRewrite(resolvePiHome(process.env), origin, routes.httpRewrites, routes.httpsRewrites);
62309
62820
  if (piOverlayHome) env.PI_CODING_AGENT_DIR = piOverlayHome;
62310
62821
  const piExt = selfDistFile("agent/pi.js");
62311
- if (piExt && fs10.existsSync(piExt) && !piPluginInstalled(resolvePiHome(process.env))) {
62822
+ if (piExt && fs11.existsSync(piExt) && !piPluginInstalled(resolvePiHome(process.env))) {
62312
62823
  clientArgs = ["-e", piExt, ...clientArgs];
62313
62824
  }
62314
62825
  } else if (base === "omp") {
@@ -62316,13 +62827,13 @@ async function runLaunch(params, deps = {}) {
62316
62827
  ompOverlayHome = prepareOmpHttpRewrite(resolveOmpHome(process.env), origin, routes.httpRewrites, routes.httpsRewrites);
62317
62828
  if (ompOverlayHome) env.PI_CODING_AGENT_DIR = ompOverlayHome;
62318
62829
  const ompExt = selfDistFile("agent/omp.js");
62319
- if (ompExt && fs10.existsSync(ompExt) && !ompPluginLoadedFrom(resolveOmpHome(process.env))) {
62830
+ if (ompExt && fs11.existsSync(ompExt) && !ompPluginLoadedFrom(resolveOmpHome(process.env))) {
62320
62831
  clientArgs = ["-e", ompExt, ...clientArgs];
62321
62832
  }
62322
62833
  } else if (base === "opencode") {
62323
62834
  env = { ...process.env, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: ca, BILLION_CONTEXT_PROXY: origin };
62324
62835
  const opencodePlugin = selfDistFile("agent/opencode.js");
62325
- const opencodePluginPath = opencodePlugin && fs10.existsSync(opencodePlugin) ? opencodePlugin : void 0;
62836
+ const opencodePluginPath = opencodePlugin && fs11.existsSync(opencodePlugin) ? opencodePlugin : void 0;
62326
62837
  opencodeTmpFile = prepareOpencodeHttpRewrite(resolveOpencodeConfigFile(process.env), origin, routes.httpRewrites, routes.httpsRewrites, opencodePluginPath);
62327
62838
  if (opencodeTmpFile) env.OPENCODE_CONFIG = opencodeTmpFile;
62328
62839
  } else if (base === "hermes") {
@@ -62360,7 +62871,7 @@ async function runLaunch(params, deps = {}) {
62360
62871
  const dshAcpPatch = writeDshAcpPatch(dshHomeDir);
62361
62872
  if (dshAcpPatch) clientArgs = dshArgsWithPatch(clientArgs, dshAcpPatch);
62362
62873
  } else if (base === "codex") {
62363
- const codexConversationId = injectMcp ? randomUUID4() : void 0;
62874
+ const codexConversationId = injectMcp ? randomUUID5() : void 0;
62364
62875
  if (directUrl) {
62365
62876
  env = { ...process.env, BILLION_CONTEXT_PROXY: origin };
62366
62877
  if (codexConversationId) clientArgs = [...buildCodexMcpArgs(origin, codexConversationId), ...clientArgs];
@@ -62395,8 +62906,8 @@ async function runLaunch(params, deps = {}) {
62395
62906
  console.error(`bili: claude budget aligned \u2014 CLAUDE_CODE_AUTO_COMPACT_WINDOW=${claudeBudget.CLAUDE_CODE_AUTO_COMPACT_WINDOW}`);
62396
62907
  }
62397
62908
  if (injectMcp) {
62398
- const mcpFile = path13.join(os5.tmpdir(), `bili-mcp-${Date.now()}.json`);
62399
- fs10.writeFileSync(mcpFile, JSON.stringify(buildMcpConfig(origin)));
62909
+ const mcpFile = path14.join(os5.tmpdir(), `bili-mcp-${Date.now()}.json`);
62910
+ fs11.writeFileSync(mcpFile, JSON.stringify(buildMcpConfig(origin)));
62400
62911
  tmpFiles.push(mcpFile);
62401
62912
  clientArgs = ["--mcp-config", mcpFile, ...clientArgs];
62402
62913
  }
@@ -62415,13 +62926,13 @@ async function runLaunch(params, deps = {}) {
62415
62926
  stopProxy(handle2);
62416
62927
  if (opencodeTmpFile) {
62417
62928
  try {
62418
- fs10.rmSync(path13.dirname(opencodeTmpFile), { recursive: true, force: true });
62929
+ fs11.rmSync(path14.dirname(opencodeTmpFile), { recursive: true, force: true });
62419
62930
  } catch {
62420
62931
  }
62421
62932
  }
62422
62933
  for (const f2 of tmpFiles) {
62423
62934
  try {
62424
- fs10.rmSync(f2, { force: true });
62935
+ fs11.rmSync(f2, { force: true });
62425
62936
  } catch {
62426
62937
  }
62427
62938
  }
@@ -62447,8 +62958,8 @@ async function runTestPi(params, deps = {}) {
62447
62958
  }
62448
62959
  const ca = resolveCaCertPath(process.env);
62449
62960
  const env = buildPiEnv(handle2.origin, ca, process.env);
62450
- const sessionDir = path13.join(os5.tmpdir(), `bili-pi-test-${Date.now()}`);
62451
- fs10.mkdirSync(sessionDir, { recursive: true });
62961
+ const sessionDir = path14.join(os5.tmpdir(), `bili-pi-test-${Date.now()}`);
62962
+ fs11.mkdirSync(sessionDir, { recursive: true });
62452
62963
  const args = [
62453
62964
  "-p",
62454
62965
  "--no-session",
@@ -62476,7 +62987,7 @@ async function runTestPi(params, deps = {}) {
62476
62987
 
62477
62988
  // src/export.ts
62478
62989
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
62479
- import path14 from "path";
62990
+ import path15 from "path";
62480
62991
  function fmtDate(ms2) {
62481
62992
  return ms2 ? new Date(ms2).toISOString().replace("T", " ").slice(0, 19) + " UTC" : "\u2014";
62482
62993
  }
@@ -62608,7 +63119,7 @@ async function exportSession(selector, opts = {}) {
62608
63119
  }
62609
63120
  const markdown = renderHandoff(matches[0], opts.full ?? false);
62610
63121
  if (opts.output) {
62611
- mkdirSync5(path14.dirname(path14.resolve(opts.output)), { recursive: true });
63122
+ mkdirSync5(path15.dirname(path15.resolve(opts.output)), { recursive: true });
62612
63123
  writeFileSync4(opts.output, markdown, "utf8");
62613
63124
  return `written to ${opts.output}`;
62614
63125
  }
@@ -62618,11 +63129,11 @@ async function exportSession(selector, opts = {}) {
62618
63129
  // src/cli.ts
62619
63130
  import { readFileSync as readFileSync4 } from "fs";
62620
63131
  import { fileURLToPath as fileURLToPath6 } from "url";
62621
- import path15 from "path";
63132
+ import path16 from "path";
62622
63133
  var VERSION3 = (() => {
62623
63134
  try {
62624
63135
  const here = fileURLToPath6(import.meta.url);
62625
- const pkg = path15.join(path15.dirname(here), "..", "package.json");
63136
+ const pkg = path16.join(path16.dirname(here), "..", "package.json");
62626
63137
  return JSON.parse(readFileSync4(pkg, "utf8")).version ?? "dev";
62627
63138
  } catch {
62628
63139
  return "dev";
@@ -62631,7 +63142,7 @@ var VERSION3 = (() => {
62631
63142
  var PACKAGE_NAME = (() => {
62632
63143
  try {
62633
63144
  const here = fileURLToPath6(import.meta.url);
62634
- const pkg = path15.join(path15.dirname(here), "..", "package.json");
63145
+ const pkg = path16.join(path16.dirname(here), "..", "package.json");
62635
63146
  return JSON.parse(readFileSync4(pkg, "utf8")).name ?? "billion-context";
62636
63147
  } catch {
62637
63148
  return "billion-context";