billion-context 0.1.44 → 0.1.45

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 path14 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
1144
+ let path15 = 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 (path14 && path14[0] !== "/") {
1149
- path14 = `/${path14}`;
1148
+ if (path15 && path15[0] !== "/") {
1149
+ path15 = `/${path15}`;
1150
1150
  }
1151
- return new URL(`${origin}${path14}`);
1151
+ return new URL(`${origin}${path15}`);
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: path14, origin }
1972
+ request: { method, path: path15, origin }
1973
1973
  } = evt;
1974
- debugLog("sending request to %s %s%s", method, origin, path14);
1974
+ debugLog("sending request to %s %s%s", method, origin, path15);
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: path14, origin },
1992
+ request: { method, path: path15, 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
- path14,
1999
+ path15,
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: path14, origin }
2008
+ request: { method, path: path15, origin }
2009
2009
  } = evt;
2010
- debugLog("trailers received from %s %s%s", method, origin, path14);
2010
+ debugLog("trailers received from %s %s%s", method, origin, path15);
2011
2011
  }
2012
2012
  );
2013
2013
  diagnosticsChannel.subscribe(
2014
2014
  "undici:request:error",
2015
2015
  (evt) => {
2016
2016
  const {
2017
- request: { method, path: path14, origin },
2017
+ request: { method, path: path15, 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
- path14,
2024
+ path15,
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: path14,
2139
+ path: path15,
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 path14 !== "string") {
2156
+ if (typeof path15 !== "string") {
2157
2157
  throw new InvalidArgumentError("path must be a string");
2158
- } else if (path14[0] !== "/" && !(path14.startsWith("http://") || path14.startsWith("https://")) && method !== "CONNECT") {
2158
+ } else if (path15[0] !== "/" && !(path15.startsWith("http://") || path15.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(path14)) {
2160
+ } else if (invalidPathRegex.test(path15)) {
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(path14, query) : path14;
2235
+ this.path = query ? serializePathWithQuery(path15, query) : path15;
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: path14, host, upgrade, blocking, reset } = request;
7418
+ const { method, path: path15, 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} ${path14} HTTP/1.1\r
7496
+ let header = `${method} ${path15} 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: path14, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
8149
+ const { method, path: path15, 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] = path14;
8217
+ headers[HTTP2_HEADER_PATH] = path15;
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] = path14;
8258
+ headers[HTTP2_HEADER_PATH] = path15;
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: path14 = "/",
10601
+ path: path15 = "/",
10602
10602
  headers = {}
10603
10603
  } = opts;
10604
- opts.path = origin + path14;
10604
+ opts.path = origin + path15;
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(path14) {
12688
- if (typeof path14 !== "string") {
12689
- return path14;
12687
+ function safeUrl(path15) {
12688
+ if (typeof path15 !== "string") {
12689
+ return path15;
12690
12690
  }
12691
- const pathSegments = path14.split("?", 3);
12691
+ const pathSegments = path15.split("?", 3);
12692
12692
  if (pathSegments.length !== 2) {
12693
- return path14;
12693
+ return path15;
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: path14, method, body, headers }) {
12700
- const pathMatch = matchValue(mockDispatch2.path, path14);
12699
+ function matchKey(mockDispatch2, { path: path15, method, body, headers }) {
12700
+ const pathMatch = matchValue(mockDispatch2.path, path15);
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: path14, ignoreTrailingSlash }) => {
12726
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path14)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path14), resolvedPath);
12725
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path15, ignoreTrailingSlash }) => {
12726
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path15)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path15), 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(path14) {
12766
- while (path14.endsWith("/")) {
12767
- path14 = path14.slice(0, -1);
12765
+ function removeTrailingSlash(path15) {
12766
+ while (path15.endsWith("/")) {
12767
+ path15 = path15.slice(0, -1);
12768
12768
  }
12769
- if (path14.length === 0) {
12770
- path14 = "/";
12769
+ if (path15.length === 0) {
12770
+ path15 = "/";
12771
12771
  }
12772
- return path14;
12772
+ return path15;
12773
12773
  }
12774
12774
  function buildKey(opts) {
12775
- const { path: path14, method, body, headers, query } = opts;
12775
+ const { path: path15, method, body, headers, query } = opts;
12776
12776
  return {
12777
- path: path14,
12777
+ path: path15,
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: path14, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13467
+ ({ method, path: path15, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
13468
13468
  Method: method,
13469
13469
  Origin: origin,
13470
- Path: path14,
13470
+ Path: path15,
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 [path14, searchParams] = dispatchOpts.path.split("?");
13552
+ const [path15, searchParams] = dispatchOpts.path.split("?");
13553
13553
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
13554
- dispatchOpts.path = `${path14}?${normalizedSearchParams}`;
13554
+ dispatchOpts.path = `${path15}?${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 path14 = filePath || this.#snapshotPath;
13956
- if (!path14) {
13955
+ const path15 = filePath || this.#snapshotPath;
13956
+ if (!path15) {
13957
13957
  throw new InvalidArgumentError("Snapshot path is required");
13958
13958
  }
13959
13959
  try {
13960
- const data = await readFile3(resolve(path14), "utf8");
13960
+ const data = await readFile3(resolve(path15), "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 ${path14}`, { cause: error });
13974
+ throw new UndiciError(`Failed to load snapshots from ${path15}`, { 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 path14 = filePath || this.#snapshotPath;
13986
- if (!path14) {
13985
+ const path15 = filePath || this.#snapshotPath;
13986
+ if (!path15) {
13987
13987
  throw new InvalidArgumentError("Snapshot path is required");
13988
13988
  }
13989
- const resolvedPath = resolve(path14);
13989
+ const resolvedPath = resolve(path15);
13990
13990
  await mkdir3(dirname6(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 path14 = search ? `${pathname}${search}` : pathname;
14622
- const redirectUrlString = `${origin}${path14}`;
14621
+ const path15 = search ? `${pathname}${search}` : pathname;
14622
+ const redirectUrlString = `${origin}${path15}`;
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 = path14;
14629
+ this.opts.path = path15;
14630
14630
  this.opts.origin = origin;
14631
14631
  this.opts.query = null;
14632
14632
  }
@@ -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, path14) {
16398
+ function deleteCachedUri(store, cacheKey, path15) {
16399
16399
  deleteCachedValue(store, {
16400
16400
  ...cacheKey,
16401
- path: path14
16401
+ path: path15
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: path14
16409
+ path: path15
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 path14 = getSameOriginPath(cacheKey, values[i]);
16421
- if (path14 !== void 0) {
16422
- deleteCachedUri(store, cacheKey, path14);
16420
+ const path15 = getSameOriginPath(cacheKey, values[i]);
16421
+ if (path15 !== void 0) {
16422
+ deleteCachedUri(store, cacheKey, path15);
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 path14 = url.pathname + url.search;
21300
+ const path15 = 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 ? `${path14}?` : path14,
21304
+ path: hasTrailingQuestionMark ? `${path15}?` : path15,
21305
21305
  origin: url.origin,
21306
21306
  method: request.method,
21307
21307
  body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
@@ -21851,8 +21851,8 @@ var require_cache3 = __commonJS({
21851
21851
  * @returns {requestResponseList}
21852
21852
  */
21853
21853
  #batchCacheOperations(operations) {
21854
- const cache3 = this.#relevantRequestResponseList;
21855
- const backupCache = [...cache3];
21854
+ const cache4 = this.#relevantRequestResponseList;
21855
+ const backupCache = [...cache4];
21856
21856
  const addedItems = [];
21857
21857
  const resultList = [];
21858
21858
  try {
@@ -21879,9 +21879,9 @@ var require_cache3 = __commonJS({
21879
21879
  return [];
21880
21880
  }
21881
21881
  for (const requestResponse of requestResponses) {
21882
- const idx = cache3.indexOf(requestResponse);
21882
+ const idx = cache4.indexOf(requestResponse);
21883
21883
  assert(idx !== -1);
21884
- cache3.splice(idx, 1);
21884
+ cache4.splice(idx, 1);
21885
21885
  }
21886
21886
  } else if (operation.type === "put") {
21887
21887
  if (operation.response == null) {
@@ -21911,11 +21911,11 @@ var require_cache3 = __commonJS({
21911
21911
  }
21912
21912
  requestResponses = this.#queryCache(operation.request);
21913
21913
  for (const requestResponse of requestResponses) {
21914
- const idx = cache3.indexOf(requestResponse);
21914
+ const idx = cache4.indexOf(requestResponse);
21915
21915
  assert(idx !== -1);
21916
- cache3.splice(idx, 1);
21916
+ cache4.splice(idx, 1);
21917
21917
  }
21918
- cache3.push([operation.request, operation.response]);
21918
+ cache4.push([operation.request, operation.response]);
21919
21919
  addedItems.push([operation.request, operation.response]);
21920
21920
  }
21921
21921
  resultList.push([operation.request, operation.response]);
@@ -22092,13 +22092,13 @@ var require_cachestorage = __commonJS({
22092
22092
  if (options.cacheName != null) {
22093
22093
  if (this.#caches.has(options.cacheName)) {
22094
22094
  const cacheList = this.#caches.get(options.cacheName);
22095
- const cache3 = new Cache(kConstruct, cacheList);
22096
- return await cache3.match(request, options);
22095
+ const cache4 = new Cache(kConstruct, cacheList);
22096
+ return await cache4.match(request, options);
22097
22097
  }
22098
22098
  } else {
22099
22099
  for (const cacheList of this.#caches.values()) {
22100
- const cache3 = new Cache(kConstruct, cacheList);
22101
- const response = await cache3.match(request, options);
22100
+ const cache4 = new Cache(kConstruct, cacheList);
22101
+ const response = await cache4.match(request, options);
22102
22102
  if (response !== void 0) {
22103
22103
  return response;
22104
22104
  }
@@ -22128,12 +22128,12 @@ var require_cachestorage = __commonJS({
22128
22128
  webidl.argumentLengthCheck(arguments, 1, prefix);
22129
22129
  cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName");
22130
22130
  if (this.#caches.has(cacheName)) {
22131
- const cache4 = this.#caches.get(cacheName);
22132
- return new Cache(kConstruct, cache4);
22131
+ const cache5 = this.#caches.get(cacheName);
22132
+ return new Cache(kConstruct, cache5);
22133
22133
  }
22134
- const cache3 = [];
22135
- this.#caches.set(cacheName, cache3);
22136
- return new Cache(kConstruct, cache3);
22134
+ const cache4 = [];
22135
+ this.#caches.set(cacheName, cache4);
22136
+ return new Cache(kConstruct, cache4);
22137
22137
  }
22138
22138
  /**
22139
22139
  * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete
@@ -22248,9 +22248,9 @@ var require_util4 = __commonJS({
22248
22248
  }
22249
22249
  }
22250
22250
  }
22251
- function validateCookiePath(path14) {
22252
- for (let i = 0; i < path14.length; ++i) {
22253
- const code = path14.charCodeAt(i);
22251
+ function validateCookiePath(path15) {
22252
+ for (let i = 0; i < path15.length; ++i) {
22253
+ const code = path15.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 path14 = opts.path;
25490
+ let path15 = opts.path;
25491
25491
  if (!opts.path.startsWith("/")) {
25492
- path14 = `/${path14}`;
25492
+ path15 = `/${path15}`;
25493
25493
  }
25494
- url = new URL(util.parseOrigin(url).origin + path14);
25494
+ url = new URL(util.parseOrigin(url).origin + path15);
25495
25495
  } else {
25496
25496
  if (!opts) {
25497
25497
  opts = typeof url === "object" ? url : {};
@@ -39943,20 +39943,20 @@ var require_tls = __commonJS({
39943
39943
  }
39944
39944
  return !c.fail;
39945
39945
  };
39946
- tls4.createSessionCache = function(cache3, capacity) {
39946
+ tls4.createSessionCache = function(cache4, capacity) {
39947
39947
  var rval = null;
39948
- if (cache3 && cache3.getSession && cache3.setSession && cache3.order) {
39949
- rval = cache3;
39948
+ if (cache4 && cache4.getSession && cache4.setSession && cache4.order) {
39949
+ rval = cache4;
39950
39950
  } else {
39951
39951
  rval = {};
39952
- rval.cache = cache3 || {};
39952
+ rval.cache = cache4 || {};
39953
39953
  rval.capacity = Math.max(capacity || 100, 1);
39954
39954
  rval.order = [];
39955
- for (var key2 in cache3) {
39955
+ for (var key2 in cache4) {
39956
39956
  if (rval.order.length <= capacity) {
39957
39957
  rval.order.push(key2);
39958
39958
  } else {
39959
- delete cache3[key2];
39959
+ delete cache4[key2];
39960
39960
  }
39961
39961
  }
39962
39962
  rval.getSession = function(sessionId) {
@@ -43868,8 +43868,13 @@ function resolveBoundaries(input) {
43868
43868
  input.messages.forEach(
43869
43869
  (message, index) => indexByRawId.set(message.id, index)
43870
43870
  );
43871
- let startIndex = resolveAnchorIndex(start, input.state, indexByRawId, "start");
43872
- let endIndex = resolveAnchorIndex(end, input.state, indexByRawId, "end");
43871
+ let snappedBoundaries = [];
43872
+ const startAnchor = resolveAnchorIndex(start, input.state, indexByRawId, "start");
43873
+ if (startAnchor.snapped) snappedBoundaries.push(startAnchor.snapped);
43874
+ const endAnchor = resolveAnchorIndex(end, input.state, indexByRawId, "end");
43875
+ if (endAnchor.snapped) snappedBoundaries.push(endAnchor.snapped);
43876
+ let startIndex = startAnchor.index;
43877
+ let endIndex = endAnchor.index;
43873
43878
  if (startIndex > endIndex) {
43874
43879
  [startIndex, endIndex] = [endIndex, startIndex];
43875
43880
  }
@@ -43897,7 +43902,8 @@ function resolveBoundaries(input) {
43897
43902
  messageIds,
43898
43903
  nestedBlockIds,
43899
43904
  boundaryKind,
43900
- protectedGaps
43905
+ protectedGaps,
43906
+ snappedBoundaries
43901
43907
  };
43902
43908
  }
43903
43909
  function resolveAnchorIndex(boundary, state, indexByRawId, endpoint) {
@@ -43912,14 +43918,21 @@ function resolveAnchorIndex(boundary, state, indexByRawId, endpoint) {
43912
43918
  );
43913
43919
  }
43914
43920
  const index = indexByRawId.get(rawId);
43915
- if (index === void 0) {
43916
- throw new BoundaryNotFoundError(
43917
- "consumed",
43918
- endpoint,
43919
- `${label}="${boundary.raw}" not found in visible context (likely consumed by an existing block).`
43920
- );
43921
+ if (index !== void 0) {
43922
+ return { index, snapped: null };
43923
+ }
43924
+ const owner2 = activeOwnerAnchor(state, [rawId], indexByRawId);
43925
+ if (owner2 !== null) {
43926
+ return {
43927
+ index: owner2,
43928
+ snapped: `${label}="${boundary.raw}" refers to a message already compressed into an active block \u2014 anchored to that block's summary instead.`
43929
+ };
43921
43930
  }
43922
- return index;
43931
+ throw new BoundaryNotFoundError(
43932
+ "consumed",
43933
+ endpoint,
43934
+ `${label}="${boundary.raw}" not found in visible context (likely consumed by an existing block).`
43935
+ );
43923
43936
  }
43924
43937
  const block = blockById(state, `b${boundary.numericId}`);
43925
43938
  if (!block) {
@@ -43929,6 +43942,19 @@ function resolveAnchorIndex(boundary, state, indexByRawId, endpoint) {
43929
43942
  `${label}="b${boundary.numericId}" does not exist in this session (typo or wrong session) \u2014 run acp_status for current refs.`
43930
43943
  );
43931
43944
  }
43945
+ if (block.active) {
43946
+ const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);
43947
+ if (anchor !== null) {
43948
+ return { index: anchor, snapped: null };
43949
+ }
43950
+ }
43951
+ const owner = activeOwnerAnchor(state, block.effectiveMessageIds, indexByRawId);
43952
+ if (owner !== null) {
43953
+ return {
43954
+ index: owner,
43955
+ snapped: `${label}="b${boundary.numericId}" was consumed by a higher-tier block \u2014 anchored to the active block covering its content instead.`
43956
+ };
43957
+ }
43932
43958
  if (!block.active) {
43933
43959
  throw new BoundaryNotFoundError(
43934
43960
  "consumed",
@@ -43936,15 +43962,26 @@ function resolveAnchorIndex(boundary, state, indexByRawId, endpoint) {
43936
43962
  `${label}="b${boundary.numericId}" not found in visible context (block distilled/consumed by a higher-tier block).`
43937
43963
  );
43938
43964
  }
43939
- const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);
43940
- if (anchor === null) {
43941
- throw new BoundaryNotFoundError(
43942
- "consumed",
43943
- endpoint,
43944
- `${label}="b${boundary.numericId}" not found in visible context (block messages consumed by a higher-tier block).`
43945
- );
43965
+ throw new BoundaryNotFoundError(
43966
+ "consumed",
43967
+ endpoint,
43968
+ `${label}="b${boundary.numericId}" not found in visible context (block messages consumed by a higher-tier block).`
43969
+ );
43970
+ }
43971
+ function activeOwnerAnchor(state, ownedIds, indexByRawId) {
43972
+ if (ownedIds.length === 0) return null;
43973
+ const owned = new Set(ownedIds);
43974
+ let best = null;
43975
+ for (const block of state.blocks) {
43976
+ if (!block.active) continue;
43977
+ const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);
43978
+ if (anchor === null) continue;
43979
+ const ownsContent = block.effectiveMessageIds.some((id) => owned.has(id));
43980
+ if (ownsContent && (best === null || anchor < best)) {
43981
+ best = anchor;
43982
+ }
43946
43983
  }
43947
- return anchor;
43984
+ return best;
43948
43985
  }
43949
43986
  function formatPaddedRef(index) {
43950
43987
  return `m${String(index).padStart(5, "0")}`;
@@ -44010,7 +44047,7 @@ function truncateLargeToolOutputs(messages, tokenCount, config, countTokens, opt
44010
44047
  );
44011
44048
  return { messages: updated, truncatedCount, savedTokens };
44012
44049
  }
44013
- var KEEP_LAST_ORPHANED = 0;
44050
+ var KEEP_LAST_ORPHANED = 2;
44014
44051
  function rangeKey(startRef, endRef) {
44015
44052
  return `${startRef}::${endRef}`;
44016
44053
  }
@@ -44565,6 +44602,10 @@ function runPipeline(nodes, initial, ctx) {
44565
44602
  function rangeError(spec, message) {
44566
44603
  return `range ${spec.startRef}..${spec.endRef}: ${message}`;
44567
44604
  }
44605
+ function numericBlockId(id) {
44606
+ const parsed = /^b(\d+)$/.exec(id);
44607
+ return parsed ? Number(parsed[1]) : 0;
44608
+ }
44568
44609
  function createCore(ports = {}) {
44569
44610
  const countTokens = ports.countTokens ?? defaultCountTokens;
44570
44611
  function applyCompression(input) {
@@ -44610,6 +44651,12 @@ function createCore(ports = {}) {
44610
44651
  }
44611
44652
  }
44612
44653
  }
44654
+ let resolvableCount = 0;
44655
+ let unknownCount = 0;
44656
+ for (const resolution of classifications.values()) {
44657
+ if (resolution.status === "ok") resolvableCount++;
44658
+ else if (resolution.status === "unknown") unknownCount++;
44659
+ }
44613
44660
  const rangeIndexSets = [];
44614
44661
  for (const [spec, resolution] of classifications) {
44615
44662
  if (resolution.status !== "ok") continue;
@@ -44654,7 +44701,9 @@ function createCore(ports = {}) {
44654
44701
  }
44655
44702
  }
44656
44703
  if (!hasBlockBoundaryRange && totalRangeChars < input.config.compress.minCompressRange) {
44657
- const gateMessage = consumedRanges.length > 0 ? `Requested range(s) already compressed (e.g. ${consumedRanges[0].startRef}..${consumedRanges[0].endRef}); remaining compressible content ${totalRangeChars} chars < min ${input.config.compress.minCompressRange}. Nothing to do \u2014 run acp_status to see current compressible ranges.` : `Total compressible content too small (${totalRangeChars} chars across ${countedRanges} range(s), min ${input.config.compress.minCompressRange}). Combine more messages into your range(s) to meet the threshold.`;
44704
+ const live = activeBlocks(state).map((b2) => b2.blockId).sort((x, y) => numericBlockId(x) - numericBlockId(y));
44705
+ const liveHint = live.length > 0 ? ` Current active blocks span ${live[0]}..${live[live.length - 1]} \u2014 retry with startId/endId set to active block IDs in that span.` : "";
44706
+ const gateMessage = resolvableCount === 0 && consumedRanges.length === 0 && unknownCount > 0 ? `None of the ${input.ranges.length} requested range(s) resolved \u2014 every ref failed with "does not exist in this session". Refs recorded before an earlier compress are stale: each successful compress renumbers the remaining refs. Run acp_status, then re-issue the compress in the same turn using only the refs it reports.` : consumedRanges.length > 0 ? `Requested range(s) already compressed (e.g. ${consumedRanges[0].startRef}..${consumedRanges[0].endRef}); remaining compressible content ${totalRangeChars} chars < min ${input.config.compress.minCompressRange}. Nothing to do.${liveHint}` : `Total compressible content too small (${totalRangeChars} chars across ${countedRanges} range(s), min ${input.config.compress.minCompressRange}). Combine more messages into your range(s) to meet the threshold.`;
44658
44707
  return {
44659
44708
  state: input.state,
44660
44709
  result: {
@@ -44680,6 +44729,7 @@ function createCore(ports = {}) {
44680
44729
  errors.push(rangeError(spec, resolution.error.message));
44681
44730
  continue;
44682
44731
  }
44732
+ warnings.push(...resolution.resolved.snappedBoundaries);
44683
44733
  try {
44684
44734
  const outcome = applySingleRange({
44685
44735
  spec,
@@ -45919,24 +45969,6 @@ function renderCompressedDrilldown(blocks, state, sort, limit, countTokens) {
45919
45969
  }
45920
45970
  return lines.join("\n");
45921
45971
  }
45922
- var substringAlgorithm = {
45923
- name: "substring",
45924
- description: "Exact substring counting (original baseline). Predictable, no normalization.",
45925
- score(docs, query) {
45926
- const terms = query.toLowerCase().trim().split(/\s+/).filter((t) => t.length > 0);
45927
- if (terms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));
45928
- return docs.map((d) => {
45929
- const haystack = d.text.toLowerCase();
45930
- let score = 0;
45931
- for (const term of terms) score += countOccurrences2(haystack, term);
45932
- return { ref: d.ref, score };
45933
- });
45934
- }
45935
- };
45936
- function countOccurrences2(haystack, needle) {
45937
- if (!needle) return 0;
45938
- return haystack.split(needle).length - 1;
45939
- }
45940
45972
  function stem(word) {
45941
45973
  let w2 = word;
45942
45974
  if (w2.length <= 3) return w2;
@@ -45955,8 +45987,17 @@ function stem(word) {
45955
45987
  return w2;
45956
45988
  }
45957
45989
  var CJK = /[\u3400-\u9fff\uf900-\ufaff\u3040-\u30ff\uac00-\ud7af]/;
45958
- var CJK_RUN = new RegExp(`${CJK.source}+`, "g");
45959
45990
  var LATIN_WORD = /[a-z][a-z0-9_]*[a-z0-9]|[a-z0-9]/g;
45991
+ var cjkSegmenter = new Intl.Segmenter("zh", { granularity: "word" });
45992
+ function cjkRunTokens(segs) {
45993
+ const words = segs.filter((w2) => w2.length >= 2);
45994
+ if (words.length > 0) return words;
45995
+ const run = segs.join("");
45996
+ const out = [];
45997
+ for (let i = 0; i < run.length - 1; i++) out.push(run.slice(i, i + 2));
45998
+ for (const ch of run) out.push(ch);
45999
+ return out;
46000
+ }
45960
46001
  function tokenize(text, opts = {}) {
45961
46002
  const lower = text.toLowerCase();
45962
46003
  const tokens = [];
@@ -45967,15 +46008,23 @@ function tokenize(text, opts = {}) {
45967
46008
  tokens.push(w2);
45968
46009
  }
45969
46010
  }
45970
- const cjkRuns = lower.match(CJK_RUN) ?? [];
45971
- for (const run of cjkRuns) {
45972
- if (run.length === 1) {
45973
- tokens.push(run);
45974
- } else {
45975
- for (let i = 0; i < run.length - 1; i++) tokens.push(run.slice(i, i + 2));
45976
- for (const ch of run) tokens.push(ch);
46011
+ if (!CJK.test(lower)) return tokens;
46012
+ const runSegs = [];
46013
+ let cur = null;
46014
+ for (const s3 of cjkSegmenter.segment(lower)) {
46015
+ const t = s3.segment;
46016
+ if (t.length === 0) continue;
46017
+ if (CJK.test(t)) {
46018
+ (cur ??= []).push(t);
46019
+ } else if (cur) {
46020
+ runSegs.push(cur);
46021
+ cur = null;
45977
46022
  }
45978
46023
  }
46024
+ if (cur) runSegs.push(cur);
46025
+ for (const segs of runSegs) {
46026
+ tokens.push(...cjkRunTokens(segs));
46027
+ }
45979
46028
  return tokens;
45980
46029
  }
45981
46030
  function charBigrams(text) {
@@ -45991,6 +46040,50 @@ function tfMap(text, stem2) {
45991
46040
  for (const t of tokenize(text, { stem: stem2 })) m2.set(t, (m2.get(t) ?? 0) + 1);
45992
46041
  return m2;
45993
46042
  }
46043
+ var DEFAULT_CAP_CHARS = 8 * 1024 * 1024;
46044
+ var capChars = DEFAULT_CAP_CHARS;
46045
+ var cache = /* @__PURE__ */ new Map();
46046
+ var cachedChars = 0;
46047
+ function build(text) {
46048
+ const tf = tfMap(text, true);
46049
+ let len = 0;
46050
+ for (const v2 of tf.values()) len += v2;
46051
+ const lower = text.toLowerCase();
46052
+ return { tf, len, lower, grams: new Set(charBigrams(lower)) };
46053
+ }
46054
+ function docFeatures(text) {
46055
+ const hit = cache.get(text);
46056
+ if (hit) return hit;
46057
+ const f2 = build(text);
46058
+ if (text.length > 0 && text.length <= capChars) {
46059
+ while (cachedChars + text.length > capChars && cache.size > 0) {
46060
+ const k2 = cache.keys().next().value;
46061
+ cachedChars -= k2.length;
46062
+ cache.delete(k2);
46063
+ }
46064
+ cache.set(text, f2);
46065
+ cachedChars += text.length;
46066
+ }
46067
+ return f2;
46068
+ }
46069
+ var substringAlgorithm = {
46070
+ name: "substring",
46071
+ description: "Exact substring counting (original baseline). Predictable, no normalization.",
46072
+ score(docs, query) {
46073
+ const terms = query.toLowerCase().trim().split(/\s+/).filter((t) => t.length > 0);
46074
+ if (terms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));
46075
+ return docs.map((d) => {
46076
+ const haystack = docFeatures(d.text).lower;
46077
+ let score = 0;
46078
+ for (const term of terms) score += countOccurrences2(haystack, term);
46079
+ return { ref: d.ref, score };
46080
+ });
46081
+ }
46082
+ };
46083
+ function countOccurrences2(haystack, needle) {
46084
+ if (!needle) return 0;
46085
+ return haystack.split(needle).length - 1;
46086
+ }
45994
46087
  var bm25Algorithm = {
45995
46088
  name: "bm25",
45996
46089
  description: "BM25 with stemming + CJK bigram tokenization. IR-standard relevance ranking.",
@@ -45999,11 +46092,8 @@ var bm25Algorithm = {
45999
46092
  const k1 = 1.2;
46000
46093
  const b2 = 0.75;
46001
46094
  const parsed = docs.map((d) => {
46002
- const text = d.text;
46003
- const tf = tfMap(text, true);
46004
- let len = 0;
46005
- for (const v2 of tf.values()) len += v2;
46006
- return { id: d.ref, tf, len };
46095
+ const f2 = docFeatures(d.text);
46096
+ return { id: d.ref, tf: f2.tf, len: f2.len };
46007
46097
  });
46008
46098
  const avgdl = parsed.reduce((s3, d) => s3 + d.len, 0) / (N2 || 1);
46009
46099
  const qTerms = tokenize(query, { stem: true });
@@ -46030,14 +46120,13 @@ var fuzzyAlgorithm = {
46030
46120
  name: "fuzzy",
46031
46121
  description: "Character bigram overlap. Typo-tolerant, script-agnostic, high recall.",
46032
46122
  score(docs, query) {
46033
- const qTokens = query.toLowerCase().split(/[\s,]+/).filter((t) => t.length >= 4);
46123
+ const qTokens = query.toLowerCase().split(/[\s,]+/).filter((t) => t.length >= 4 || t.length >= 2 && CJK.test(t));
46034
46124
  if (qTokens.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));
46035
46125
  const qGrams = /* @__PURE__ */ new Set();
46036
46126
  for (const t of qTokens) for (const g2 of charBigrams(t)) qGrams.add(g2);
46037
46127
  if (qGrams.size === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));
46038
46128
  return docs.map((d) => {
46039
- const haystack = d.text.toLowerCase();
46040
- const docGrams = new Set(charBigrams(haystack));
46129
+ const docGrams = docFeatures(d.text).grams;
46041
46130
  let hits = 0;
46042
46131
  for (const g2 of qGrams) if (docGrams.has(g2)) hits++;
46043
46132
  return { ref: d.ref, score: hits / qGrams.size };
@@ -46108,6 +46197,9 @@ function stateDir() {
46108
46197
  function defaultLogFile() {
46109
46198
  return path.join(stateDir(), "bili.log");
46110
46199
  }
46200
+ function proxyOriginFile() {
46201
+ return path.join(stateDir(), "proxy-origin");
46202
+ }
46111
46203
  function caDir() {
46112
46204
  return path.join(dataDir(), "ca");
46113
46205
  }
@@ -46564,13 +46656,13 @@ function getUpstreamConnectionStatus() {
46564
46656
  }
46565
46657
 
46566
46658
  // src/config.ts
46567
- function safeReadJson(path14) {
46659
+ function safeReadJson(path15) {
46568
46660
  try {
46569
- const raw = readFileSync(path14, "utf8").replace(/^\uFEFF/, "");
46661
+ const raw = readFileSync(path15, "utf8").replace(/^\uFEFF/, "");
46570
46662
  return JSON.parse(raw);
46571
46663
  } catch (e) {
46572
46664
  if (e.code !== "ENOENT") {
46573
- log("error", `[acp-config] failed to parse ${path14}: ${String(e)}`);
46665
+ log("error", `[acp-config] failed to parse ${path15}: ${String(e)}`);
46574
46666
  }
46575
46667
  return void 0;
46576
46668
  }
@@ -46951,7 +47043,7 @@ import path3 from "path";
46951
47043
  var REGISTRY_URL = "https://models.dev/models.json";
46952
47044
  var CACHE_FILE = path3.join(cacheDir(), "models-dev.json");
46953
47045
  var TTL_MS = 24 * 60 * 60 * 1e3;
46954
- var cache = null;
47046
+ var cache2 = null;
46955
47047
  var loading = null;
46956
47048
  function parse(raw) {
46957
47049
  try {
@@ -47003,25 +47095,25 @@ async function fetchFresh() {
47003
47095
  }
47004
47096
  }
47005
47097
  async function loadRegistry() {
47006
- if (cache) return cache;
47098
+ if (cache2) return cache2;
47007
47099
  if (diskCacheFresh()) {
47008
47100
  const disk = await readDiskCache();
47009
47101
  if (disk) {
47010
- cache = disk;
47011
- return cache;
47102
+ cache2 = disk;
47103
+ return cache2;
47012
47104
  }
47013
47105
  }
47014
47106
  if (loading) return loading;
47015
47107
  loading = (async () => {
47016
47108
  const fresh = await fetchFresh();
47017
47109
  if (fresh) {
47018
- cache = fresh;
47110
+ cache2 = fresh;
47019
47111
  log("info", `[acp-registry] loaded models.dev (${Object.keys(fresh).length} models)`);
47020
47112
  return fresh;
47021
47113
  }
47022
47114
  const disk = await readDiskCache();
47023
47115
  if (disk) {
47024
- cache = disk;
47116
+ cache2 = disk;
47025
47117
  log("info", `[acp-registry] using stale disk cache (${Object.keys(disk).length} models, fetch failed)`);
47026
47118
  return disk;
47027
47119
  }
@@ -47295,14 +47387,17 @@ function openaiToCore(body) {
47295
47387
  }
47296
47388
  case "user": {
47297
47389
  const text = stringContent(m2.content);
47298
- const img = firstImagePart(m2.content);
47390
+ const imgs = allImageParts(m2.content);
47391
+ const firstImg = imgs[0];
47392
+ const firstUrl = firstImg ? firstImg.image_url.url : void 0;
47393
+ const firstParsed = firstUrl ? parseDataUrl(firstUrl) : void 0;
47299
47394
  const base = deriveMessageId("user", "text", text);
47300
47395
  msgs.push({
47301
47396
  id: clusters.next(base),
47302
47397
  role: "user",
47303
47398
  contentType: "text",
47304
47399
  text,
47305
- ...img ? { rawOpenaiContent: img.part, imageMediaType: img.mediaType, imageBase64: img.base64 } : {}
47400
+ ...imgs.length === 1 && firstParsed ? { rawOpenaiContent: imgs[0], imageMediaType: firstParsed.mediaType, imageBase64: firstParsed.base64 } : imgs.length > 1 ? { rawOpenaiContentParts: imgs } : {}
47306
47401
  });
47307
47402
  break;
47308
47403
  }
@@ -47397,10 +47492,12 @@ function coreToOpenai(messages) {
47397
47492
  if (m2.role === "system") {
47398
47493
  out.push({ role: m2.originalRole === "developer" ? "developer" : "system", content: m2.text ?? "" });
47399
47494
  } else if (m2.role === "user") {
47400
- if (m2.rawOpenaiContent || m2.imageBase64) {
47495
+ if (m2.rawOpenaiContent || m2.imageBase64 || m2.rawOpenaiContentParts) {
47401
47496
  const parts = [];
47402
47497
  if (m2.text) parts.push({ type: "text", text: m2.text });
47403
- if (m2.rawOpenaiContent) {
47498
+ if (m2.rawOpenaiContentParts && m2.rawOpenaiContentParts.length > 0) {
47499
+ for (const part of m2.rawOpenaiContentParts) parts.push(part);
47500
+ } else if (m2.rawOpenaiContent) {
47404
47501
  parts.push(m2.rawOpenaiContent);
47405
47502
  } else if (m2.imageBase64 && m2.imageMediaType) {
47406
47503
  parts.push({ type: "image_url", image_url: { url: `data:${m2.imageMediaType};base64,${m2.imageBase64}` } });
@@ -47446,19 +47543,17 @@ function stringContent(content) {
47446
47543
  }
47447
47544
  return "";
47448
47545
  }
47449
- function firstImagePart(content) {
47450
- if (!Array.isArray(content)) return void 0;
47546
+ function allImageParts(content) {
47547
+ if (!Array.isArray(content)) return [];
47548
+ const out = [];
47451
47549
  for (const p2 of content) {
47452
- if (p2 && typeof p2 === "object" && p2.type === "image_url") {
47453
- const iu = p2.image_url;
47454
- const url = iu?.url;
47455
- if (typeof url === "string") {
47456
- const parsed = parseDataUrl(url);
47457
- if (parsed) return { part: p2, mediaType: parsed.mediaType, base64: parsed.base64 };
47458
- }
47459
- }
47550
+ if (typeof p2 !== "object" || p2 === null) continue;
47551
+ if (!("type" in p2) || p2.type !== "image_url" || !("image_url" in p2)) continue;
47552
+ const imagePart = p2;
47553
+ const url = imagePart.image_url.url;
47554
+ if (typeof url === "string" && parseDataUrl(url)) out.push(p2);
47460
47555
  }
47461
- return void 0;
47556
+ return out;
47462
47557
  }
47463
47558
  var OPAQUE_ITEM_TYPES = /* @__PURE__ */ new Set([
47464
47559
  "additional_tools",
@@ -49269,11 +49364,11 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
49269
49364
  const newBody = adapter.buildRequest(coreMessages, systemPrompt, requestBody);
49270
49365
  if (process.env.ACP_DUMP_REQ !== "0" && ctx.debug) {
49271
49366
  try {
49272
- const fs10 = await import("fs");
49367
+ const fs11 = await import("fs");
49273
49368
  const dumpDir = process.env.ACP_DUMP_DIR || `${process.env.HOME}/.local/state/billion-context/dumps`;
49274
- fs10.mkdirSync(dumpDir, { recursive: true });
49369
+ fs11.mkdirSync(dumpDir, { recursive: true });
49275
49370
  const sid = ctx.session.id ?? "unknown";
49276
- fs10.writeFileSync(`${dumpDir}/req-${Date.now()}-${sid}-REREQUEST.json`, JSON.stringify(newBody, null, 2));
49371
+ fs11.writeFileSync(`${dumpDir}/req-${Date.now()}-${sid}-REREQUEST.json`, JSON.stringify(newBody, null, 2));
49277
49372
  } catch {
49278
49373
  }
49279
49374
  }
@@ -51344,21 +51439,21 @@ function mtimesEqual(a, b2) {
51344
51439
  }
51345
51440
  return true;
51346
51441
  }
51347
- var cache2 = null;
51442
+ var cache3 = null;
51348
51443
  function discoverMitmDomains(env = process.env) {
51349
51444
  const now = Date.now();
51350
- if (cache2 && now - cache2.checkedAt < TTL_MS2) {
51351
- return cache2.domains;
51445
+ if (cache3 && now - cache3.checkedAt < TTL_MS2) {
51446
+ return cache3.domains;
51352
51447
  }
51353
51448
  const paths = configFilePaths(env);
51354
51449
  const mtimes = readMtimes(paths);
51355
- if (cache2 && mtimesEqual(mtimes, cache2.mtimes)) {
51356
- cache2.checkedAt = now;
51357
- return cache2.domains;
51450
+ if (cache3 && mtimesEqual(mtimes, cache3.mtimes)) {
51451
+ cache3.checkedAt = now;
51452
+ return cache3.domains;
51358
51453
  }
51359
51454
  const config = loadClientConfig(env, process.cwd());
51360
51455
  const domains = extractHttpsHosts(config);
51361
- cache2 = { checkedAt: now, mtimes, domains };
51456
+ cache3 = { checkedAt: now, mtimes, domains };
51362
51457
  return domains;
51363
51458
  }
51364
51459
 
@@ -52313,6 +52408,13 @@ Content-Length: ${Buffer.byteLength(body)}\r
52313
52408
  }
52314
52409
  server.listen(opts.port, opts.host, () => {
52315
52410
  const displayHost = opts.host === "0.0.0.0" ? "localhost" : opts.host;
52411
+ try {
52412
+ fs6.mkdirSync(stateDir(), { recursive: true });
52413
+ 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;
52414
+ fs6.writeFileSync(proxyOriginFile(), `http://${originHost}:${server.address() === null ? opts.port : server.address().port}
52415
+ `);
52416
+ } catch {
52417
+ }
52316
52418
  const nOverrides = Object.keys(opts.routes).length;
52317
52419
  log2(
52318
52420
  "info",
@@ -56865,7 +56967,18 @@ var VERSION2 = (() => {
56865
56967
  return "dev";
56866
56968
  }
56867
56969
  })();
56868
- var PROXY_ORIGIN = process.env.BILI_MCP_PROXY ?? "http://127.0.0.1:8787";
56970
+ var DEFAULT_PROXY_ORIGIN = "http://127.0.0.1:8787";
56971
+ function resolveProxyOrigin() {
56972
+ const fromEnv = process.env.BILI_MCP_PROXY?.trim();
56973
+ if (fromEnv && fromEnv.length > 0) return fromEnv;
56974
+ try {
56975
+ const discovered = fs8.readFileSync(proxyOriginFile(), "utf8").trim();
56976
+ if (/^https?:\/\/\S+$/.test(discovered)) return discovered;
56977
+ } catch {
56978
+ }
56979
+ return DEFAULT_PROXY_ORIGIN;
56980
+ }
56981
+ var TOOL_TIMEOUT_MS = 6e4;
56869
56982
  var CONVERSATION_FROM_ENV = process.env.CLAUDE_CODE_SESSION_ID?.trim() || process.env.BILI_CONVERSATION_ID?.trim() || void 0;
56870
56983
  var IDENTITY_BINDING = Boolean(process.env.CLAUDE_CODE_SESSION_ID?.trim());
56871
56984
  var manifestTools = [];
@@ -56884,19 +56997,34 @@ function sendError2(id, code, message) {
56884
56997
  send({ jsonrpc: "2.0", id, error: { code, message } });
56885
56998
  }
56886
56999
  async function fetchManifest() {
56887
- const res = await fetch(`${PROXY_ORIGIN}/__bili/plugin/manifest`);
57000
+ const res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/manifest`, { signal: AbortSignal.timeout(5e3) });
56888
57001
  if (!res.ok) throw new Error(`manifest fetch failed: ${res.status}`);
56889
57002
  const data = await res.json();
56890
57003
  const anthropic = data.tools?.anthropic ?? [];
56891
57004
  manifestTools = anthropic.map((t) => ({ name: t.name, description: t.description, inputSchema: t.input_schema }));
56892
57005
  if (manifestTools.length === 0) throw new Error("manifest served no anthropic tools");
56893
57006
  }
56894
- async function forwardTool(tool, args) {
56895
- const res = await fetch(`${PROXY_ORIGIN}/__bili/plugin/tool`, {
56896
- method: "POST",
56897
- headers: { "content-type": "application/json" },
56898
- body: JSON.stringify({ conversationId, tool, args })
57007
+ var manifestPromise = null;
57008
+ function ensureManifest() {
57009
+ manifestPromise ??= fetchManifest().catch((err2) => {
57010
+ manifestPromise = null;
57011
+ throw err2;
56899
57012
  });
57013
+ return manifestPromise;
57014
+ }
57015
+ async function forwardTool(tool, args, timeoutMs = TOOL_TIMEOUT_MS) {
57016
+ let res;
57017
+ try {
57018
+ res = await fetch(`${resolveProxyOrigin()}/__bili/plugin/tool`, {
57019
+ method: "POST",
57020
+ headers: { "content-type": "application/json" },
57021
+ body: JSON.stringify({ conversationId, tool, args }),
57022
+ signal: AbortSignal.timeout(timeoutMs)
57023
+ });
57024
+ } catch (err2) {
57025
+ if (err2 instanceof Error && err2.name === "TimeoutError") throw new Error(`tool forward timed out after ${timeoutMs}ms: ${tool}`);
57026
+ throw err2;
57027
+ }
56900
57028
  const data = await res.json();
56901
57029
  if (!res.ok || !data.ok) throw new Error(data.error ?? `tool forward failed: ${res.status}`);
56902
57030
  return data.result ?? "";
@@ -56911,10 +57039,11 @@ async function handleMessage(msg2) {
56911
57039
  if (fromMeta) conversationId ??= fromMeta;
56912
57040
  initialized2 = true;
56913
57041
  if (conversationId && !registered) {
56914
- const registerFetch = fetch(`${PROXY_ORIGIN}/__bili/plugin/register`, {
57042
+ const registerFetch = fetch(`${resolveProxyOrigin()}/__bili/plugin/register`, {
56915
57043
  method: "POST",
56916
57044
  headers: { "content-type": "application/json" },
56917
- body: JSON.stringify({ conversationId, agent: "mcp", identity: IDENTITY_BINDING })
57045
+ body: JSON.stringify({ conversationId, agent: "mcp", identity: IDENTITY_BINDING }),
57046
+ signal: AbortSignal.timeout(5e3)
56918
57047
  });
56919
57048
  registered = true;
56920
57049
  if (IDENTITY_BINDING) {
@@ -56939,7 +57068,12 @@ async function handleMessage(msg2) {
56939
57068
  sendError2(id, -32002, "server not initialized");
56940
57069
  return;
56941
57070
  }
56942
- sendResult(id, { tools: manifestTools });
57071
+ try {
57072
+ await ensureManifest();
57073
+ sendResult(id, { tools: manifestTools });
57074
+ } catch (err2) {
57075
+ sendError2(id, -32003, `bili proxy unreachable at ${resolveProxyOrigin()} (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 start bili or set BILI_MCP_PROXY`);
57076
+ }
56943
57077
  return;
56944
57078
  }
56945
57079
  case "tools/call": {
@@ -56970,12 +57104,6 @@ async function handleMessage(msg2) {
56970
57104
  }
56971
57105
  }
56972
57106
  async function mcpMain() {
56973
- try {
56974
- await fetchManifest();
56975
- } catch (err2) {
56976
- console.error(`bili-mcp: ${err2 instanceof Error ? err2.message : String(err2)} (proxy at ${PROXY_ORIGIN})`);
56977
- process.exit(1);
56978
- }
56979
57107
  let buf = "";
56980
57108
  process.stdin.setEncoding("utf8");
56981
57109
  process.stdin.on("data", (chunk) => {
@@ -57005,12 +57133,311 @@ if (process.argv[1] && /(?:^|[\\/])mcp\.(?:ts|js)$/.test(process.argv[1])) {
57005
57133
  void mcpMain();
57006
57134
  }
57007
57135
 
57136
+ // src/plugin-install.ts
57137
+ import fs9 from "fs";
57138
+ import path11 from "path";
57139
+ import os4 from "os";
57140
+ import { execFileSync as execFileSync2 } from "child_process";
57141
+ import { fileURLToPath as fileURLToPath5 } from "url";
57142
+ var PLUGIN_AGENTS = ["pi", "omp", "claude", "codex", "opencode"];
57143
+ function selfPackageRoot() {
57144
+ const here = fileURLToPath5(import.meta.url);
57145
+ return path11.resolve(path11.dirname(here), "..");
57146
+ }
57147
+ function homeFile(rel, envOverride) {
57148
+ const raw = (envOverride !== void 0 ? process.env[envOverride] : void 0)?.trim();
57149
+ const base = raw && raw.length > 0 ? raw : os4.homedir();
57150
+ return path11.join(base, rel);
57151
+ }
57152
+ function backupOnce(file) {
57153
+ if (fs9.existsSync(file) && !fs9.existsSync(`${file}.bili-bak`)) {
57154
+ fs9.copyFileSync(file, `${file}.bili-bak`);
57155
+ }
57156
+ }
57157
+ function readJson(file) {
57158
+ let text;
57159
+ try {
57160
+ text = fs9.readFileSync(file, "utf8");
57161
+ } catch (err2) {
57162
+ if (err2.code === "ENOENT") return {};
57163
+ throw err2;
57164
+ }
57165
+ let parsed;
57166
+ try {
57167
+ parsed = JSON.parse(text);
57168
+ } catch (err2) {
57169
+ throw new Error(`${file}: not valid JSON (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 fix it or restore ${path11.basename(file)}.bili-bak first; refusing to overwrite`);
57170
+ }
57171
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
57172
+ throw new Error(`${file}: expected a JSON object at top level, refusing to overwrite`);
57173
+ }
57174
+ return parsed;
57175
+ }
57176
+ function writeJson(file, data) {
57177
+ fs9.mkdirSync(path11.dirname(file), { recursive: true });
57178
+ backupOnce(file);
57179
+ fs9.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
57180
+ }
57181
+ function requireDistFile(file) {
57182
+ if (!fs9.existsSync(file)) {
57183
+ 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
57184
+ `);
57185
+ }
57186
+ }
57187
+ function piSettingsFile() {
57188
+ return path11.join(resolvePiHome(process.env), "settings.json");
57189
+ }
57190
+ function isPiEntry(entry, root) {
57191
+ return entry === root || entry === `npm:billion-context` || /^npm:billion-context@/.test(entry) || /(^|\/)node_modules\/billion-context(\/|$)/.test(entry);
57192
+ }
57193
+ function piInstall() {
57194
+ const root = selfPackageRoot();
57195
+ const file = piSettingsFile();
57196
+ const settings = readJson(file);
57197
+ const packages = Array.isArray(settings.packages) ? settings.packages.map(String) : [];
57198
+ if (packages.some((p2) => p2 === root)) return `pi: already installed (${file})`;
57199
+ const kept = packages.filter((p2) => !isPiEntry(p2, root));
57200
+ kept.push(root);
57201
+ settings.packages = kept;
57202
+ writeJson(file, settings);
57203
+ return `pi: installed -> ${file} packages += ${root}`;
57204
+ }
57205
+ function piRemove() {
57206
+ const root = selfPackageRoot();
57207
+ const file = piSettingsFile();
57208
+ const settings = readJson(file);
57209
+ const packages = Array.isArray(settings.packages) ? settings.packages.map(String) : [];
57210
+ const kept = packages.filter((p2) => !isPiEntry(p2, root));
57211
+ if (kept.length === packages.length) return `pi: not installed (${file})`;
57212
+ settings.packages = kept;
57213
+ writeJson(file, settings);
57214
+ return `pi: removed from ${file}`;
57215
+ }
57216
+ function piStatus() {
57217
+ const root = selfPackageRoot();
57218
+ const packages = readJson(piSettingsFile()).packages;
57219
+ const list = Array.isArray(packages) ? packages.map(String) : [];
57220
+ return list.some((p2) => isPiEntry(p2, root)) ? "installed" : "not installed";
57221
+ }
57222
+ function ompConfigFile() {
57223
+ const raw = process.env.PI_CODING_AGENT_DIR?.trim();
57224
+ if (raw && raw.length > 0) return path11.join(raw, "config.yml");
57225
+ return path11.join(os4.homedir(), ".omp", "agent", "config.yml");
57226
+ }
57227
+ function ompExtensionPath() {
57228
+ return path11.join(selfPackageRoot(), "dist", "agent", "omp.js");
57229
+ }
57230
+ function ompEntryValue(line) {
57231
+ return line.replace(/#.*$/, "").trim().replace(/^-\s*/, "").replace(/^["']|["']$/g, "").trim();
57232
+ }
57233
+ function ompRemove() {
57234
+ const file = ompConfigFile();
57235
+ const entry = ompExtensionPath();
57236
+ if (!fs9.existsSync(file)) return `omp: not installed (${file})`;
57237
+ const text = fs9.readFileSync(file, "utf8");
57238
+ const cleaned = text.split("\n").filter((line) => ompEntryValue(line) !== entry).join("\n");
57239
+ if (cleaned === text) return `omp: not installed (${file})`;
57240
+ backupOnce(file);
57241
+ fs9.writeFileSync(file, cleaned);
57242
+ return `omp: removed from ${file}`;
57243
+ }
57244
+ function ompInstall() {
57245
+ const file = ompConfigFile();
57246
+ const entry = ompExtensionPath();
57247
+ requireDistFile(entry);
57248
+ fs9.mkdirSync(path11.dirname(file), { recursive: true });
57249
+ const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
57250
+ if (text.split("\n").some((line) => ompEntryValue(line) === entry)) return `omp: already installed (${file})`;
57251
+ const keyCount = (text.match(/^extensions:/gm) ?? []).length;
57252
+ if (keyCount > 1) throw new Error(`${file}: multiple \`extensions:\` keys \u2014 fix the file first, refusing to edit`);
57253
+ if (/^extensions:\s*\S/m.test(text) && !/^extensions:\s*$/m.test(text)) {
57254
+ throw new Error(`${file}: \`extensions:\` uses flow style or an inline value; convert it to a block list first, refusing to edit`);
57255
+ }
57256
+ let out;
57257
+ const extMatch = /^extensions:\s*$/m.exec(text);
57258
+ if (extMatch !== null) {
57259
+ const afterKey = text.indexOf("\n", extMatch.index);
57260
+ const rest = afterKey < 0 ? "" : text.slice(afterKey + 1);
57261
+ const firstNonList = rest.search(/^(?!\s*-\s)\S/m);
57262
+ const existingIndent = /^(\s*)-\s\S/m.exec(rest)?.[1] ?? " ";
57263
+ let head;
57264
+ let tail;
57265
+ if (firstNonList >= 0) {
57266
+ head = text.slice(0, afterKey + 1 + firstNonList);
57267
+ tail = text.slice(afterKey + 1 + firstNonList);
57268
+ } else {
57269
+ head = text.length === 0 || text.endsWith("\n") ? text : text + "\n";
57270
+ tail = "";
57271
+ }
57272
+ out = `${head}${existingIndent}- ${entry}
57273
+ ${tail}`;
57274
+ } else {
57275
+ out = text.endsWith("\n") || text.length === 0 ? text : text + "\n";
57276
+ out += `extensions:
57277
+ - ${entry}
57278
+ `;
57279
+ }
57280
+ const occurrences = out.split("\n").filter((line) => ompEntryValue(line) === entry).length;
57281
+ if (occurrences !== 1) {
57282
+ throw new Error(`${file}: edit would leave ${occurrences} copies of the entry \u2014 aborting without writing`);
57283
+ }
57284
+ backupOnce(file);
57285
+ fs9.writeFileSync(file, out);
57286
+ return `omp: installed -> ${file} extensions += ${entry}`;
57287
+ }
57288
+ function ompStatus() {
57289
+ const file = ompConfigFile();
57290
+ const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
57291
+ return text.split("\n").some((line) => ompEntryValue(line) === ompExtensionPath()) ? "installed" : "not installed";
57292
+ }
57293
+ var CLAUDE_EXEC_TIMEOUT_MS = 15e3;
57294
+ function claudeMcpJson() {
57295
+ return homeFile(".claude.json", "CLAUDE_CONFIG_DIR");
57296
+ }
57297
+ function claudeInstall() {
57298
+ const root = selfPackageRoot();
57299
+ const mcpJs = path11.join(root, "dist", "mcp.js");
57300
+ requireDistFile(mcpJs);
57301
+ const claude = process.env.CLAUDE?.trim() || "claude";
57302
+ try {
57303
+ execFileSync2(claude, ["mcp", "add", "bili", "--scope", "user", "-e", `BILI_MCP_PROXY=${resolveProxyOrigin()}`, "--", process.execPath, mcpJs], { stdio: ["ignore", "pipe", "pipe"], timeout: CLAUDE_EXEC_TIMEOUT_MS });
57304
+ return `claude: installed via \`claude mcp add\` (user scope) -> ${claudeMcpJson()}`;
57305
+ } catch (err2) {
57306
+ const stderr = err2 instanceof Error && "stderr" in err2 ? String(err2.stderr ?? "") : "";
57307
+ throw new Error(`claude: install failed (${stderr.trim() || (err2 instanceof Error ? err2.message : String(err2))}) \u2014 is the claude CLI on PATH?`);
57308
+ }
57309
+ }
57310
+ function claudeRemove() {
57311
+ if (claudeStatus() === "not installed") return `claude: not installed (${claudeMcpJson()})`;
57312
+ const claude = process.env.CLAUDE?.trim() || "claude";
57313
+ try {
57314
+ execFileSync2(claude, ["mcp", "remove", "bili", "--scope", "user"], { stdio: ["ignore", "pipe", "pipe"], timeout: CLAUDE_EXEC_TIMEOUT_MS });
57315
+ return "claude: removed";
57316
+ } catch (err2) {
57317
+ throw new Error(`claude: remove failed (${err2 instanceof Error ? err2.message : String(err2)})`);
57318
+ }
57319
+ }
57320
+ function claudeStatus() {
57321
+ const data = readJson(claudeMcpJson());
57322
+ return data.mcpServers && "bili" in data.mcpServers ? "installed" : "not installed";
57323
+ }
57324
+ function codexToml() {
57325
+ const raw = process.env.CODEX_HOME?.trim();
57326
+ if (raw && raw.length > 0) return path11.join(raw, "config.toml");
57327
+ return homeFile(".codex/config.toml");
57328
+ }
57329
+ function codexBlock() {
57330
+ return `
57331
+ [mcp_servers.bili]
57332
+ command = ${JSON.stringify(process.execPath)}
57333
+ args = [${JSON.stringify(path11.join(selfPackageRoot(), "dist", "mcp.js"))}]
57334
+ env = { BILI_MCP_PROXY = ${JSON.stringify(resolveProxyOrigin())} }
57335
+ `;
57336
+ }
57337
+ function codexInstall() {
57338
+ const file = codexToml();
57339
+ const text = fs9.existsSync(file) ? fs9.readFileSync(file, "utf8") : "";
57340
+ const existing = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
57341
+ if (existing !== null) {
57342
+ const block = text.slice(existing.index, text.indexOf("\n[", existing.index + 1) === -1 ? void 0 : text.indexOf("\n[", existing.index + 1));
57343
+ if (block.includes(`BILI_MCP_PROXY = ${JSON.stringify(resolveProxyOrigin())}`)) return `codex: already installed (${file})`;
57344
+ const refreshed = text.slice(0, existing.index) + codexBlock().replace(/^\n/, "") + text.slice(existing.index + block.length);
57345
+ backupOnce(file);
57346
+ fs9.writeFileSync(file, refreshed);
57347
+ return `codex: refreshed proxy origin -> ${file} [mcp_servers.bili]`;
57348
+ }
57349
+ fs9.mkdirSync(path11.dirname(file), { recursive: true });
57350
+ backupOnce(file);
57351
+ fs9.writeFileSync(file, text + (text.endsWith("\n") || text.length === 0 ? "" : "\n") + codexBlock());
57352
+ return `codex: installed -> ${file} [mcp_servers.bili]`;
57353
+ }
57354
+ function codexRemove() {
57355
+ const file = codexToml();
57356
+ if (!fs9.existsSync(file)) return `codex: not installed (${file})`;
57357
+ const text = fs9.readFileSync(file, "utf8");
57358
+ const start = (() => {
57359
+ const m2 = /^[ \t]*\[mcp_servers\.bili\][ \t]*$/m.exec(text);
57360
+ return m2 === null ? -1 : m2.index;
57361
+ })();
57362
+ if (start < 0) return `codex: not installed (${file})`;
57363
+ const lineStart = text.lastIndexOf("\n", start - 1) + 1;
57364
+ const after = text.slice(start);
57365
+ const nextTable = after.slice(after.indexOf("\n") + 1).search(/^[ \t]*\[/m);
57366
+ const end = nextTable >= 0 ? start + after.indexOf("\n") + 1 + nextTable : text.length;
57367
+ const cleaned = (text.slice(0, lineStart).replace(/\n+$/, "\n") + text.slice(end)).replace(/^\n+/, "");
57368
+ backupOnce(file);
57369
+ fs9.writeFileSync(file, cleaned);
57370
+ return `codex: removed from ${file}`;
57371
+ }
57372
+ function codexStatus() {
57373
+ const text = fs9.existsSync(codexToml()) ? fs9.readFileSync(codexToml(), "utf8") : "";
57374
+ return /^\[mcp_servers\.bili\]\s*$/m.test(text) ? "installed" : "not installed";
57375
+ }
57376
+ function opencodeJson() {
57377
+ const raw = process.env.OPENCODE_CONFIG?.trim();
57378
+ if (raw && raw.length > 0) return raw;
57379
+ const xdg2 = process.env.XDG_CONFIG_HOME?.trim();
57380
+ if (xdg2 && xdg2.length > 0) return path11.join(xdg2, "opencode/opencode.json");
57381
+ return path11.join(os4.homedir(), ".config", "opencode", "opencode.json");
57382
+ }
57383
+ function opencodeInstall() {
57384
+ const file = opencodeJson();
57385
+ const mcpJs = path11.join(selfPackageRoot(), "dist", "mcp.js");
57386
+ requireDistFile(mcpJs);
57387
+ const data = readJson(file);
57388
+ const mcp = data.mcp ?? {};
57389
+ if ("bili" in mcp) return `opencode: already installed (${file})`;
57390
+ mcp.bili = { type: "local", command: [process.execPath, mcpJs], environment: { BILI_MCP_PROXY: resolveProxyOrigin() }, enabled: true };
57391
+ data.mcp = mcp;
57392
+ writeJson(file, data);
57393
+ return `opencode: installed -> ${file} mcp.bili`;
57394
+ }
57395
+ function opencodeRemove() {
57396
+ const file = opencodeJson();
57397
+ const data = readJson(file);
57398
+ const mcp = data.mcp;
57399
+ if (!mcp || !("bili" in mcp)) return `opencode: not installed (${file})`;
57400
+ delete mcp.bili;
57401
+ if (Object.keys(mcp).length === 0) delete data.mcp;
57402
+ writeJson(file, data);
57403
+ return `opencode: removed from ${file}`;
57404
+ }
57405
+ function opencodeStatus() {
57406
+ const mcp = readJson(opencodeJson()).mcp;
57407
+ return mcp && "bili" in mcp ? "installed" : "not installed";
57408
+ }
57409
+ function isPluginAgent(value) {
57410
+ return PLUGIN_AGENTS.includes(value);
57411
+ }
57412
+ function pluginInstall(agent) {
57413
+ return agent === "pi" ? piInstall() : agent === "omp" ? ompInstall() : agent === "claude" ? claudeInstall() : agent === "codex" ? codexInstall() : opencodeInstall();
57414
+ }
57415
+ function pluginRemove(agent) {
57416
+ return agent === "pi" ? piRemove() : agent === "omp" ? ompRemove() : agent === "claude" ? claudeRemove() : agent === "codex" ? codexRemove() : opencodeRemove();
57417
+ }
57418
+ function pluginStatusAll() {
57419
+ const checks = [
57420
+ ["pi", piStatus],
57421
+ ["omp", ompStatus],
57422
+ ["claude", claudeStatus],
57423
+ ["codex", codexStatus],
57424
+ ["opencode", opencodeStatus]
57425
+ ];
57426
+ return checks.map(([agent, check]) => {
57427
+ try {
57428
+ return { agent, status: check() };
57429
+ } catch (err2) {
57430
+ return { agent, status: `error: ${err2 instanceof Error ? err2.message : String(err2)}` };
57431
+ }
57432
+ });
57433
+ }
57434
+
57008
57435
  // src/launcher.ts
57009
57436
  import { randomUUID as randomUUID2 } from "crypto";
57010
- import fs9 from "fs";
57437
+ import fs10 from "fs";
57011
57438
  import net2 from "net";
57012
- import os4 from "os";
57013
- import path11 from "path";
57439
+ import os5 from "os";
57440
+ import path12 from "path";
57014
57441
  import { spawn } from "child_process";
57015
57442
  var LAUNCHER_DEFAULT_HOST = "127.0.0.1";
57016
57443
  var LAUNCHER_DEFAULT_PORT = 8787;
@@ -57054,12 +57481,12 @@ function unwrapUpstream2(url) {
57054
57481
  return idx >= 0 ? url.slice(idx + "/bili/".length) : url;
57055
57482
  }
57056
57483
  function resolveCaCertPath(env) {
57057
- const base = env.XDG_DATA_HOME || path11.join(os4.homedir(), ".local/share");
57058
- return path11.join(base, "billion-context", "ca", "root-ca.pem");
57484
+ const base = env.XDG_DATA_HOME || path12.join(os5.homedir(), ".local/share");
57485
+ return path12.join(base, "billion-context", "ca", "root-ca.pem");
57059
57486
  }
57060
57487
  function resolveCombinedCaPath(env) {
57061
- const base = env.XDG_DATA_HOME || path11.join(os4.homedir(), ".local/share");
57062
- return path11.join(base, "billion-context", "ca", "combined-ca.pem");
57488
+ const base = env.XDG_DATA_HOME || path12.join(os5.homedir(), ".local/share");
57489
+ return path12.join(base, "billion-context", "ca", "combined-ca.pem");
57063
57490
  }
57064
57491
  function discoverRoutes(client, config) {
57065
57492
  const httpsDomains = [];
@@ -57144,7 +57571,7 @@ function launcherInjectMcp(env, base) {
57144
57571
  return base !== "pi" && env.BILI_LAUNCHER_PLUGIN === "1";
57145
57572
  }
57146
57573
  function buildMcpConfig(origin) {
57147
- const script = process.argv[1] ? path11.resolve(path11.dirname(process.argv[1]), "mcp.js") : "bili-mcp";
57574
+ const script = process.argv[1] ? path12.resolve(path12.dirname(process.argv[1]), "mcp.js") : "bili-mcp";
57148
57575
  return {
57149
57576
  mcpServers: {
57150
57577
  bili: {
@@ -57161,7 +57588,7 @@ function buildClaudePluginEnv(origin, directUrl, baseEnv) {
57161
57588
  return { ...baseEnv, ANTHROPIC_BASE_URL: wrapUpstream(origin, upstream) };
57162
57589
  }
57163
57590
  function buildCodexMcpArgs(origin, conversationId2) {
57164
- const script = process.argv[1] ? path11.resolve(path11.dirname(process.argv[1]), "mcp.js") : "bili-mcp";
57591
+ const script = process.argv[1] ? path12.resolve(path12.dirname(process.argv[1]), "mcp.js") : "bili-mcp";
57165
57592
  return [
57166
57593
  "-c",
57167
57594
  `mcp_servers.bili.command=${JSON.stringify(process.execPath)}`,
@@ -57175,10 +57602,10 @@ function buildCodexMcpArgs(origin, conversationId2) {
57175
57602
  }
57176
57603
  function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
57177
57604
  if (httpRewrites.length === 0 && httpsRewrites.length === 0) return void 0;
57178
- const modelsPath = path11.join(piHome, "models.json");
57605
+ const modelsPath = path12.join(piHome, "models.json");
57179
57606
  let txt;
57180
57607
  try {
57181
- txt = fs9.readFileSync(modelsPath, "utf8");
57608
+ txt = fs10.readFileSync(modelsPath, "utf8");
57182
57609
  } catch {
57183
57610
  return void 0;
57184
57611
  }
@@ -57209,18 +57636,18 @@ function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
57209
57636
  }
57210
57637
  }
57211
57638
  }
57212
- const tmp = fs9.mkdtempSync(path11.join(os4.tmpdir(), "bili-pi-"));
57639
+ const tmp = fs10.mkdtempSync(path12.join(os5.tmpdir(), "bili-pi-"));
57213
57640
  try {
57214
- for (const entry of fs9.readdirSync(piHome)) {
57641
+ for (const entry of fs10.readdirSync(piHome)) {
57215
57642
  if (entry === "models.json") continue;
57216
57643
  try {
57217
- fs9.symlinkSync(path11.join(piHome, entry), path11.join(tmp, entry));
57644
+ fs10.symlinkSync(path12.join(piHome, entry), path12.join(tmp, entry));
57218
57645
  } catch {
57219
57646
  }
57220
57647
  }
57221
57648
  } catch {
57222
57649
  }
57223
- fs9.writeFileSync(path11.join(tmp, "models.json"), JSON.stringify(root));
57650
+ fs10.writeFileSync(path12.join(tmp, "models.json"), JSON.stringify(root));
57224
57651
  return tmp;
57225
57652
  }
57226
57653
  function dedupeInOrder(list) {
@@ -57301,8 +57728,8 @@ async function ensureProxyRunning(opts, deps = {}) {
57301
57728
  const spawnedOrigin = proxyOrigin(opts.host, port);
57302
57729
  const script = process.argv[1];
57303
57730
  if (!script) throw new Error("bili: cannot resolve launcher script path");
57304
- const logPath2 = path11.join(os4.tmpdir(), `bili-proxy-${port}.log`);
57305
- const logFd = fs9.openSync(logPath2, "a");
57731
+ const logPath2 = path12.join(os5.tmpdir(), `bili-proxy-${port}.log`);
57732
+ const logFd = fs10.openSync(logPath2, "a");
57306
57733
  let child;
57307
57734
  try {
57308
57735
  child = spawnImpl(
@@ -57319,7 +57746,7 @@ async function ensureProxyRunning(opts, deps = {}) {
57319
57746
  );
57320
57747
  } finally {
57321
57748
  try {
57322
- fs9.closeSync(logFd);
57749
+ fs10.closeSync(logFd);
57323
57750
  } catch {
57324
57751
  }
57325
57752
  }
@@ -57366,12 +57793,12 @@ var PATH_EXTS = process.platform === "win32" ? [".cmd", ".bat", ".exe", ""] : ["
57366
57793
  function resolveOnPath(name, env) {
57367
57794
  const p2 = env.PATH;
57368
57795
  if (!p2) return void 0;
57369
- for (const dir of p2.split(path11.delimiter)) {
57796
+ for (const dir of p2.split(path12.delimiter)) {
57370
57797
  if (!dir) continue;
57371
57798
  for (const ext of PATH_EXTS) {
57372
- const f2 = path11.join(dir, name + ext);
57799
+ const f2 = path12.join(dir, name + ext);
57373
57800
  try {
57374
- if (fs9.existsSync(f2) && fs9.statSync(f2).isFile()) return f2;
57801
+ if (fs10.existsSync(f2) && fs10.statSync(f2).isFile()) return f2;
57375
57802
  } catch {
57376
57803
  }
57377
57804
  }
@@ -57384,8 +57811,8 @@ function resolveClientCommand(client, env) {
57384
57811
  if (piBin) return { command: piBin, prefixArgs: [] };
57385
57812
  const piResolved = resolveOnPath("pi", env);
57386
57813
  if (piResolved) return { command: piResolved, prefixArgs: [] };
57387
- const cli = path11.join(
57388
- os4.homedir(),
57814
+ const cli = path12.join(
57815
+ os5.homedir(),
57389
57816
  ".pi/agent/npm/node_modules/@earendil-works/pi-coding-agent/dist/cli.js"
57390
57817
  );
57391
57818
  return { command: process.execPath, prefixArgs: [cli] };
@@ -57457,8 +57884,8 @@ async function runLaunch(params, deps = {}) {
57457
57884
  env = directUrl ? buildClaudePluginEnv(origin, true, process.env) : buildClaudeEnv(origin, ca, routes.httpRewrites, routes.httpsRewrites, process.env);
57458
57885
  if (directUrl) env.BILLION_CONTEXT_PROXY = origin;
57459
57886
  if (injectMcp) {
57460
- const mcpFile = path11.join(os4.tmpdir(), `bili-mcp-${Date.now()}.json`);
57461
- fs9.writeFileSync(mcpFile, JSON.stringify(buildMcpConfig(origin)));
57887
+ const mcpFile = path12.join(os5.tmpdir(), `bili-mcp-${Date.now()}.json`);
57888
+ fs10.writeFileSync(mcpFile, JSON.stringify(buildMcpConfig(origin)));
57462
57889
  tmpFiles.push(mcpFile);
57463
57890
  clientArgs = ["--mcp-config", mcpFile, ...clientArgs];
57464
57891
  }
@@ -57477,13 +57904,13 @@ async function runLaunch(params, deps = {}) {
57477
57904
  if (!handle2.reused) stopProxy(handle2);
57478
57905
  if (piTmpHome) {
57479
57906
  try {
57480
- fs9.rmSync(piTmpHome, { recursive: true, force: true });
57907
+ fs10.rmSync(piTmpHome, { recursive: true, force: true });
57481
57908
  } catch {
57482
57909
  }
57483
57910
  }
57484
57911
  for (const f2 of tmpFiles) {
57485
57912
  try {
57486
- fs9.rmSync(f2, { force: true });
57913
+ fs10.rmSync(f2, { force: true });
57487
57914
  } catch {
57488
57915
  }
57489
57916
  }
@@ -57509,8 +57936,8 @@ async function runTestPi(params, deps = {}) {
57509
57936
  }
57510
57937
  const ca = resolveCaCertPath(process.env);
57511
57938
  const env = buildPiEnv(handle2.origin, ca, process.env);
57512
- const sessionDir = path11.join(os4.tmpdir(), `bili-pi-test-${Date.now()}`);
57513
- fs9.mkdirSync(sessionDir, { recursive: true });
57939
+ const sessionDir = path12.join(os5.tmpdir(), `bili-pi-test-${Date.now()}`);
57940
+ fs10.mkdirSync(sessionDir, { recursive: true });
57514
57941
  const args = [
57515
57942
  "-p",
57516
57943
  "--no-session",
@@ -57538,7 +57965,7 @@ async function runTestPi(params, deps = {}) {
57538
57965
 
57539
57966
  // src/export.ts
57540
57967
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
57541
- import path12 from "path";
57968
+ import path13 from "path";
57542
57969
  function fmtDate(ms2) {
57543
57970
  return ms2 ? new Date(ms2).toISOString().replace("T", " ").slice(0, 19) + " UTC" : "\u2014";
57544
57971
  }
@@ -57670,7 +58097,7 @@ async function exportSession(selector, opts = {}) {
57670
58097
  }
57671
58098
  const markdown = renderHandoff(matches[0], opts.full ?? false);
57672
58099
  if (opts.output) {
57673
- mkdirSync6(path12.dirname(path12.resolve(opts.output)), { recursive: true });
58100
+ mkdirSync6(path13.dirname(path13.resolve(opts.output)), { recursive: true });
57674
58101
  writeFileSync5(opts.output, markdown, "utf8");
57675
58102
  return `written to ${opts.output}`;
57676
58103
  }
@@ -57679,12 +58106,12 @@ async function exportSession(selector, opts = {}) {
57679
58106
 
57680
58107
  // src/cli.ts
57681
58108
  import { readFileSync as readFileSync5 } from "fs";
57682
- import { fileURLToPath as fileURLToPath5 } from "url";
57683
- import path13 from "path";
58109
+ import { fileURLToPath as fileURLToPath6 } from "url";
58110
+ import path14 from "path";
57684
58111
  var VERSION3 = (() => {
57685
58112
  try {
57686
- const here = fileURLToPath5(import.meta.url);
57687
- const pkg = path13.join(path13.dirname(here), "..", "package.json");
58113
+ const here = fileURLToPath6(import.meta.url);
58114
+ const pkg = path14.join(path14.dirname(here), "..", "package.json");
57688
58115
  return JSON.parse(readFileSync5(pkg, "utf8")).version ?? "dev";
57689
58116
  } catch {
57690
58117
  return "dev";
@@ -57692,8 +58119,8 @@ var VERSION3 = (() => {
57692
58119
  })();
57693
58120
  var PACKAGE_NAME = (() => {
57694
58121
  try {
57695
- const here = fileURLToPath5(import.meta.url);
57696
- const pkg = path13.join(path13.dirname(here), "..", "package.json");
58122
+ const here = fileURLToPath6(import.meta.url);
58123
+ const pkg = path14.join(path14.dirname(here), "..", "package.json");
57697
58124
  return JSON.parse(readFileSync5(pkg, "utf8")).name ?? "billion-context";
57698
58125
  } catch {
57699
58126
  return "billion-context";
@@ -57711,6 +58138,13 @@ Usage:
57711
58138
  bili export [session] [--full] list sessions / export one as a Markdown handoff
57712
58139
  (--full includes original messages; --output FILE)
57713
58140
  bili update check for & install a newer version now
58141
+ bili plugin install <agent> install the thin plugin into a host (pi/omp/
58142
+ claude/codex/opencode; original backed up once)
58143
+ bili plugin remove <agent> remove it again
58144
+ bili plugin list show install status for every host
58145
+ bili mcp run the bili MCP server standalone (stdio)
58146
+ bili plugin-register <id> pre-bind a conversation to the plugin mode
58147
+ (--origin URL, --agent name)
57714
58148
  bili --version print version
57715
58149
  bili --help show this help
57716
58150
 
@@ -57753,8 +58187,11 @@ function parseArgs(argv) {
57753
58187
  let clientArgs = [];
57754
58188
  const mitmDomains = [];
57755
58189
  let exportSelector;
58190
+ let registerConversationId;
57756
58191
  let exportOutput;
57757
58192
  let exportFull = false;
58193
+ let pluginAction;
58194
+ let pluginAgent;
57758
58195
  for (let i = 0; i < argv.length; i++) {
57759
58196
  const a = argv[i];
57760
58197
  if (!client && positional.length === 0 && isLaunchClient(a)) {
@@ -57806,15 +58243,19 @@ function parseArgs(argv) {
57806
58243
  }
57807
58244
  case "--port":
57808
58245
  case "--host":
57809
- case "--config": {
58246
+ case "--config":
58247
+ case "--origin":
58248
+ case "--agent": {
57810
58249
  const val = argv[++i];
57811
- if (val === void 0) {
57812
- console.error(`bili: ${a} requires a value`);
58250
+ if (val === void 0 || val.length === 0) {
58251
+ console.error(`bili: ${a} requires a non-empty value`);
57813
58252
  process.exit(2);
57814
58253
  }
57815
58254
  if (a === "--port") overrides.ACP_PORT = val;
57816
58255
  else if (a === "--host") overrides.ACP_HOST = val;
57817
- else overrides.BILI_CONFIG_FILE = val;
58256
+ else if (a === "--config") overrides.BILI_CONFIG_FILE = val;
58257
+ else if (a === "--origin") overrides.BILI_MCP_PROXY = val;
58258
+ else overrides.BILI_PLUGIN_AGENT = val;
57818
58259
  break;
57819
58260
  }
57820
58261
  default:
@@ -57844,9 +58285,30 @@ function parseArgs(argv) {
57844
58285
  exportSelector = positional[1];
57845
58286
  } else if (cmd === "plugin-register") {
57846
58287
  command = "plugin-register";
57847
- exportSelector = positional[1];
58288
+ registerConversationId = positional[1];
57848
58289
  } else if (cmd === "mcp") {
57849
58290
  command = "mcp";
58291
+ } else if (cmd === "plugin") {
58292
+ command = "plugin";
58293
+ const action = positional[1];
58294
+ if (action === "install" || action === "remove" || action === "list") {
58295
+ pluginAction = action;
58296
+ } else {
58297
+ console.error(`bili plugin: unknown action "${action ?? ""}" (try "bili plugin install|remove|list <agent>")`);
58298
+ process.exit(2);
58299
+ }
58300
+ const agent = positional[2];
58301
+ if (agent !== void 0) {
58302
+ if (!isPluginAgent(agent)) {
58303
+ console.error(`bili plugin: unknown agent "${agent}" (try one of: ${PLUGIN_AGENTS.join(", ")})`);
58304
+ process.exit(2);
58305
+ }
58306
+ pluginAgent = agent;
58307
+ }
58308
+ if (pluginAction !== "list" && pluginAgent === void 0) {
58309
+ console.error(`bili plugin ${pluginAction}: agent is required (try one of: ${PLUGIN_AGENTS.join(", ")})`);
58310
+ process.exit(2);
58311
+ }
57850
58312
  } else if (cmd === "test") {
57851
58313
  const target = positional[1];
57852
58314
  if (target && isLaunchClient(target)) {
@@ -57861,10 +58323,10 @@ function parseArgs(argv) {
57861
58323
  process.exit(2);
57862
58324
  }
57863
58325
  }
57864
- return { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull };
58326
+ return { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull, registerConversationId, pluginAction, pluginAgent };
57865
58327
  }
57866
58328
  async function main() {
57867
- const { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull } = parseArgs(process.argv.slice(2));
58329
+ const { command, client, clientArgs, mitmDomains, overrides, exportSelector, exportOutput, exportFull, registerConversationId, pluginAction, pluginAgent } = parseArgs(process.argv.slice(2));
57868
58330
  if (command === "help") {
57869
58331
  process.stdout.write(HELP);
57870
58332
  return;
@@ -57874,17 +58336,19 @@ async function main() {
57874
58336
  return;
57875
58337
  }
57876
58338
  if (command === "plugin-register") {
57877
- const conversationId2 = exportSelector?.trim();
58339
+ const conversationId2 = registerConversationId?.trim();
57878
58340
  if (!conversationId2) {
57879
- console.error('bili plugin-register: conversation id is required (e.g. bili plugin-register "$CLAUDE_SESSION_ID" --origin http://127.0.0.1:8787)');
58341
+ console.error('bili plugin-register: conversation id is required (e.g. bili plugin-register "$CLAUDE_SESSION_ID" --origin http://127.0.0.1:8787 --agent claude)');
57880
58342
  process.exit(2);
57881
58343
  }
58344
+ const agent = (overrides.BILI_PLUGIN_AGENT ?? process.env.BILI_PLUGIN_AGENT ?? "claude").trim() || "claude";
57882
58345
  const origin = (overrides.BILI_MCP_PROXY ?? process.env.BILI_MCP_PROXY ?? "http://127.0.0.1:8787").replace(/\/$/, "");
57883
58346
  try {
57884
58347
  const res = await fetch(`${origin}/__bili/plugin/register`, {
57885
58348
  method: "POST",
57886
58349
  headers: { "content-type": "application/json" },
57887
- body: JSON.stringify({ conversationId: conversationId2, agent: "claude", identity: true })
58350
+ body: JSON.stringify({ conversationId: conversationId2, agent, identity: true }),
58351
+ signal: AbortSignal.timeout(5e3)
57888
58352
  });
57889
58353
  const data = await res.json();
57890
58354
  if (!res.ok || !data.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
@@ -57898,6 +58362,33 @@ async function main() {
57898
58362
  runMcpStdio();
57899
58363
  return;
57900
58364
  }
58365
+ if (command === "plugin") {
58366
+ if (overrides.BILI_MCP_PROXY !== void 0) process.env.BILI_MCP_PROXY = overrides.BILI_MCP_PROXY;
58367
+ if (pluginAction === "list") {
58368
+ for (const row of pluginStatusAll()) {
58369
+ console.log(`${row.agent.padEnd(10)} ${row.status}`);
58370
+ }
58371
+ return;
58372
+ }
58373
+ if (pluginAction === "install") {
58374
+ try {
58375
+ console.log(pluginInstall(pluginAgent));
58376
+ } catch (error) {
58377
+ console.error(`bili plugin: ${error instanceof Error ? error.message : String(error)}`);
58378
+ process.exit(1);
58379
+ }
58380
+ return;
58381
+ }
58382
+ if (pluginAction === "remove") {
58383
+ try {
58384
+ console.log(pluginRemove(pluginAgent));
58385
+ } catch (error) {
58386
+ console.error(`bili plugin: ${error instanceof Error ? error.message : String(error)}`);
58387
+ process.exit(1);
58388
+ }
58389
+ return;
58390
+ }
58391
+ }
57901
58392
  if (command === "export") {
57902
58393
  try {
57903
58394
  const text = await exportSession(exportSelector, { output: exportOutput, full: exportFull });