billion-context 0.1.46-pr.211.21 → 0.1.46-pr.211.23

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.
@@ -0,0 +1,54 @@
1
+ import { createRequire as __biliCreateRequire } from 'node:module';
2
+ const require = __biliCreateRequire(import.meta.url);
3
+
4
+ // src/agent/opencode.ts
5
+ var proxyBase = process.env.BILLION_CONTEXT_PROXY ?? "";
6
+ async function showText(ctx, sid, text) {
7
+ const prompt = ctx.client?.session?.prompt;
8
+ if (typeof prompt !== "function") return;
9
+ try {
10
+ await prompt({
11
+ path: { id: sid },
12
+ body: { noReply: true, parts: [{ type: "text", text, ignored: true }] }
13
+ });
14
+ } catch {
15
+ }
16
+ }
17
+ var server = async (ctx) => {
18
+ if (!proxyBase) return {};
19
+ console.log("[bili-opencode] plugin active (proxy " + proxyBase + ")");
20
+ return {
21
+ config: async (opencodeConfig) => {
22
+ opencodeConfig.command ??= {};
23
+ opencodeConfig.command["acp"] = {
24
+ template: "",
25
+ description: "Show ACP status (billion-context proxy)"
26
+ };
27
+ },
28
+ "command.execute.before": async (input) => {
29
+ if (input.command !== "acp") return;
30
+ const sid = input.sessionID;
31
+ let text;
32
+ try {
33
+ const res = await fetch(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(sid)}&fallback=latest`);
34
+ const status = await res.json();
35
+ if (typeof status.panel === "string" && status.panel.length > 0) {
36
+ text = status.panel;
37
+ } else if (status.ok === false) {
38
+ text = "bili: no ACP session yet (send a model request first, then run /acp)";
39
+ } else {
40
+ text = "bili: proxy returned no status panel";
41
+ }
42
+ } catch (err) {
43
+ text = `bili: /acp failed (${err instanceof Error ? err.message : String(err)})`;
44
+ }
45
+ await showText(ctx, sid, text);
46
+ throw new Error("__BILI_ACP_HANDLED__");
47
+ }
48
+ };
49
+ };
50
+ var opencode_default = server;
51
+ export {
52
+ opencode_default as default
53
+ };
54
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/agent/opencode.ts"],"sourcesContent":["// Thin opencode plugin for the billion-context proxy (`bili opencode`).\n//\n// Activates ONLY when BILLION_CONTEXT_PROXY is set (the launcher sets it);\n// otherwise it is a no-op so shipping it inside the package is harmless.\n// Mirrors the pi/omp plugin (src/agent/pi.ts):\n// - registers the /acp command (config hook + command.execute.before)\n// - binds the opencode session id to the proxy session via the\n// pending-register queue (POST /__bili/plugin/register on session.created)\n// - renders the proxy's buildStatusPanel via an ignored chat message\n\ninterface OpencodeCommandConfig {\n template: string;\n description?: string;\n}\n\ninterface OpencodeConfig {\n command?: Record<string, OpencodeCommandConfig>;\n [key: string]: unknown;\n}\n\ninterface OpencodeSessionInfo {\n id?: unknown;\n}\n\ninterface OpencodeEvent {\n type?: string;\n properties?: { info?: OpencodeSessionInfo; [key: string]: unknown };\n}\n\ninterface OpencodeEventInput {\n event?: OpencodeEvent;\n}\n\ninterface OpencodeCommandInput {\n command: string;\n sessionID: string;\n arguments?: string;\n}\n\ninterface OpencodePromptPart {\n type: string;\n text: string;\n ignored?: boolean;\n}\n\ninterface OpencodeClient {\n session?: {\n prompt?: (args: {\n path: { id: string };\n body: { noReply: boolean; parts: OpencodePromptPart[] };\n }) => Promise<unknown>;\n };\n}\n\ninterface OpencodePluginContext {\n client?: OpencodeClient;\n}\n\ninterface OpencodeHooks {\n config?: (input: OpencodeConfig) => Promise<void>;\n event?: (input: OpencodeEventInput) => Promise<void>;\n \"command.execute.before\"?: (input: OpencodeCommandInput, output: { parts: unknown[] }) => Promise<void>;\n}\n\nconst proxyBase = process.env.BILLION_CONTEXT_PROXY ?? \"\";\n\nasync function showText(ctx: OpencodePluginContext, sid: string, text: string): Promise<void> {\n const prompt = ctx.client?.session?.prompt;\n if (typeof prompt !== \"function\") return;\n try {\n await prompt({\n path: { id: sid },\n body: { noReply: true, parts: [{ type: \"text\", text, ignored: true }] },\n });\n } catch {}\n}\n\nconst server = async (ctx: OpencodePluginContext): Promise<OpencodeHooks> => {\n if (!proxyBase) return {};\n console.log(\"[bili-opencode] plugin active (proxy \" + proxyBase + \")\");\n return {\n config: async (opencodeConfig) => {\n opencodeConfig.command ??= {};\n opencodeConfig.command[\"acp\"] = {\n template: \"\",\n description: \"Show ACP status (billion-context proxy)\",\n };\n },\n \"command.execute.before\": async (input) => {\n if (input.command !== \"acp\") return;\n const sid = input.sessionID;\n let text: string;\n try {\n const res = await fetch(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(sid)}&fallback=latest`);\n const status = (await res.json()) as { ok?: boolean; panel?: string; error?: string };\n if (typeof status.panel === \"string\" && status.panel.length > 0) {\n text = status.panel;\n } else if (status.ok === false) {\n text = \"bili: no ACP session yet (send a model request first, then run /acp)\";\n } else {\n text = \"bili: proxy returned no status panel\";\n }\n } catch (err) {\n text = `bili: /acp failed (${err instanceof Error ? err.message : String(err)})`;\n }\n await showText(ctx, sid, text);\n throw new Error(\"__BILI_ACP_HANDLED__\");\n },\n };\n};\n\nexport default server;\n"],"mappings":";;;;AAgEA,IAAM,YAAY,QAAQ,IAAI,yBAAyB;AAEvD,eAAe,SAAS,KAA4B,KAAa,MAA6B;AACtF,QAAM,SAAS,IAAI,QAAQ,SAAS;AACpC,MAAI,OAAO,WAAW,WAAY;AAClC,MAAI;AACA,UAAM,OAAO;AAAA,MACT,MAAM,EAAE,IAAI,IAAI;AAAA,MAChB,MAAM,EAAE,SAAS,MAAM,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,IAC1E,CAAC;AAAA,EACL,QAAQ;AAAA,EAAC;AACjB;AAEA,IAAM,SAAS,OAAO,QAAuD;AACzE,MAAI,CAAC,UAAW,QAAO,CAAC;AACxB,UAAQ,IAAI,0CAA0C,YAAY,GAAG;AACrE,SAAO;AAAA,IACH,QAAQ,OAAO,mBAAmB;AAC9B,qBAAe,YAAY,CAAC;AAC5B,qBAAe,QAAQ,KAAK,IAAI;AAAA,QAC5B,UAAU;AAAA,QACV,aAAa;AAAA,MACjB;AAAA,IACJ;AAAA,IACA,0BAA0B,OAAO,UAAU;AACvC,UAAI,MAAM,YAAY,MAAO;AAC7B,YAAM,MAAM,MAAM;AAClB,UAAI;AACJ,UAAI;AACA,cAAM,MAAM,MAAM,MAAM,GAAG,SAAS,wCAAwC,mBAAmB,GAAG,CAAC,kBAAkB;AACrH,cAAM,SAAU,MAAM,IAAI,KAAK;AAC/B,YAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,SAAS,GAAG;AAC7D,iBAAO,OAAO;AAAA,QAClB,WAAW,OAAO,OAAO,OAAO;AAC5B,iBAAO;AAAA,QACX,OAAO;AACH,iBAAO;AAAA,QACX;AAAA,MACJ,SAAS,KAAK;AACV,eAAO,sBAAsB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACjF;AACA,YAAM,SAAS,KAAK,KAAK,IAAI;AAC7B,YAAM,IAAI,MAAM,sBAAsB;AAAA,IAC1C;AAAA,EACJ;AACJ;AAEA,IAAO,mBAAQ;","names":[]}
package/dist/index.js CHANGED
@@ -51706,15 +51706,23 @@ function handlePluginManifest(res) {
51706
51706
  statusEndpoint: "/__bili/plugin/status"
51707
51707
  }));
51708
51708
  }
51709
- function handlePluginStatus(conversationId2, res) {
51710
- const entry = conversations.get(conversationId2);
51711
- const session = entry ? peekSession(entry.sessionId) : void 0;
51712
- if (!entry || !session) {
51709
+ function handlePluginStatus(conversationId2, res, fallbackLatest = false) {
51710
+ let entry = conversations.get(conversationId2);
51711
+ let session = entry ? peekSession(entry.sessionId) : void 0;
51712
+ let viaFallback = false;
51713
+ if ((!entry || !session) && fallbackLatest) {
51714
+ const latest = listSessions().filter((s3) => typeof s3.lastSeen === "number").sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
51715
+ if (latest) {
51716
+ session = latest;
51717
+ viaFallback = true;
51718
+ }
51719
+ }
51720
+ if (!session) {
51713
51721
  res.writeHead(404, { "content-type": "application/json" });
51714
51722
  res.end(JSON.stringify({ ok: false, error: "unknown plugin conversation" }));
51715
51723
  return;
51716
51724
  }
51717
- entry.lastSeen = Date.now();
51725
+ if (entry) entry.lastSeen = Date.now();
51718
51726
  const limit = session.metadata.effectiveContextLimit;
51719
51727
  const mem = remembered.get(session.id);
51720
51728
  const modelContextLimit = typeof limit === "number" && limit > 0 ? limit : 2e5;
@@ -51736,7 +51744,7 @@ function handlePluginStatus(conversationId2, res) {
51736
51744
  res.end(JSON.stringify({
51737
51745
  ok: true,
51738
51746
  conversationId: conversationId2,
51739
- sessionId: session.id,
51747
+ fallback: viaFallback || void 0,
51740
51748
  label: session.meta.label ?? null,
51741
51749
  pluginAgent: session.metadata.pluginAgent ?? null,
51742
51750
  contextLimit: typeof limit === "number" ? limit : null,
@@ -52217,6 +52225,41 @@ function readOmpConfig(ompHome) {
52217
52225
  }
52218
52226
  return parseOmpYaml(text);
52219
52227
  }
52228
+ function resolveOpencodeConfigFile(env) {
52229
+ if (nonEmpty2(env.OPENCODE_CONFIG)) return env.OPENCODE_CONFIG;
52230
+ const xdg2 = nonEmpty2(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path8.join(os.homedir(), ".config");
52231
+ return path8.join(xdg2, "opencode", "opencode.json");
52232
+ }
52233
+ function readOpencodeConfig(file) {
52234
+ let text;
52235
+ try {
52236
+ text = fs4.readFileSync(file, "utf8");
52237
+ } catch {
52238
+ return { providers: {} };
52239
+ }
52240
+ let parsed;
52241
+ try {
52242
+ parsed = JSON.parse(text);
52243
+ } catch {
52244
+ return { providers: {} };
52245
+ }
52246
+ const providers = {};
52247
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
52248
+ const root = parsed;
52249
+ const provRoot = root.provider;
52250
+ if (provRoot && typeof provRoot === "object" && !Array.isArray(provRoot)) {
52251
+ for (const [name, value] of Object.entries(provRoot)) {
52252
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
52253
+ const opts = value.options;
52254
+ if (opts && typeof opts === "object" && !Array.isArray(opts)) {
52255
+ const baseURL = opts.baseURL;
52256
+ if (typeof baseURL === "string") providers[name] = { baseURL };
52257
+ }
52258
+ }
52259
+ }
52260
+ }
52261
+ return { providers };
52262
+ }
52220
52263
  function parseZcodeConfig(obj) {
52221
52264
  const result = { providers: {} };
52222
52265
  if (!obj || typeof obj !== "object" || Array.isArray(obj)) return result;
@@ -52259,6 +52302,7 @@ function loadClientConfig(env, cwd) {
52259
52302
  const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path8.join(home, ".zcode");
52260
52303
  config.zcode = readZcodeConfig(zcodeHome);
52261
52304
  config.omp = readOmpConfig(resolveOmpHome(env));
52305
+ config.opencode = readOpencodeConfig(resolveOpencodeConfigFile(env));
52262
52306
  return config;
52263
52307
  }
52264
52308
 
@@ -53483,13 +53527,14 @@ async function handle(req, res, opts, core, config, log2) {
53483
53527
  if (req.method === "GET" && req.url === "/__bili/plugin/manifest") return handlePluginManifest(res);
53484
53528
  if (req.method === "GET" && req.url?.startsWith("/__bili/plugin/status")) {
53485
53529
  const query = req.url.slice(req.url.indexOf("?") + 1);
53486
- const conversationId2 = new URLSearchParams(query).get("conversationId")?.trim() ?? "";
53530
+ const params = new URLSearchParams(query);
53531
+ const conversationId2 = params.get("conversationId")?.trim() ?? "";
53487
53532
  if (!conversationId2) {
53488
53533
  res.writeHead(400, { "content-type": "application/json" });
53489
53534
  res.end(JSON.stringify({ ok: false, error: "conversationId query parameter is required" }));
53490
53535
  return;
53491
53536
  }
53492
- return handlePluginStatus(conversationId2, res);
53537
+ return handlePluginStatus(conversationId2, res, params.get("fallback") === "latest");
53493
53538
  }
53494
53539
  if (req.method === "POST" && req.url === "/__bili/plugin/tool") {
53495
53540
  try {
@@ -58438,6 +58483,10 @@ function discoverRoutes(client, config) {
58438
58483
  for (const [name, prov] of Object.entries(config.omp?.providers ?? {})) {
58439
58484
  classify(prov.baseUrl, name);
58440
58485
  }
58486
+ } else if (client === "opencode") {
58487
+ for (const [name, prov] of Object.entries(config.opencode?.providers ?? {})) {
58488
+ classify(prov.baseURL, name);
58489
+ }
58441
58490
  } else {
58442
58491
  for (const [name, prov] of Object.entries(config.codex?.providers ?? {})) {
58443
58492
  classify(prov.baseUrl, `model_providers.${name}.base_url`);
@@ -58616,6 +58665,43 @@ function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
58616
58665
  fs10.writeFileSync(path13.join(tmp, "models.yml"), lines.join("\n"));
58617
58666
  return tmp;
58618
58667
  }
58668
+ function prepareOpencodeHttpRewrite(configFile2, origin, httpRewrites, httpsRewrites, pluginPath) {
58669
+ if (httpRewrites.length === 0 && httpsRewrites.length === 0 && !pluginPath) return void 0;
58670
+ let root = {};
58671
+ try {
58672
+ const txt = fs10.readFileSync(configFile2, "utf8");
58673
+ const parsed = JSON.parse(txt);
58674
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
58675
+ root = { ...parsed };
58676
+ }
58677
+ } catch {
58678
+ }
58679
+ const provRoot = root.provider;
58680
+ if (provRoot && typeof provRoot === "object" && !Array.isArray(provRoot)) {
58681
+ const providers = provRoot;
58682
+ const rewrite = (rewrites, wrap) => {
58683
+ for (const r of rewrites) {
58684
+ const prov = providers[r.key];
58685
+ if (!prov || typeof prov !== "object" || Array.isArray(prov)) continue;
58686
+ const p2 = prov;
58687
+ if (!p2.options || typeof p2.options !== "object") continue;
58688
+ const existing = typeof p2.options.baseURL === "string" ? p2.options.baseURL : r.realUpstream;
58689
+ p2.options.baseURL = wrap ? wrapUpstream(origin, unwrapUpstream2(existing)) : r.realUpstream;
58690
+ }
58691
+ };
58692
+ rewrite(httpRewrites, true);
58693
+ rewrite(httpsRewrites, false);
58694
+ }
58695
+ if (pluginPath) {
58696
+ const plugins = Array.isArray(root.plugin) ? root.plugin.filter((p2) => typeof p2 === "string") : [];
58697
+ if (!plugins.includes(pluginPath)) plugins.push(pluginPath);
58698
+ root.plugin = plugins;
58699
+ }
58700
+ const tmp = fs10.mkdtempSync(path13.join(os5.tmpdir(), "bili-opencode-"));
58701
+ const tmpFile = path13.join(tmp, "opencode.json");
58702
+ fs10.writeFileSync(tmpFile, JSON.stringify(root));
58703
+ return tmpFile;
58704
+ }
58619
58705
  function dedupeInOrder(list) {
58620
58706
  const seen = /* @__PURE__ */ new Set();
58621
58707
  const out = [];
@@ -58820,6 +58906,7 @@ async function runLaunch(params, deps = {}) {
58820
58906
  let clientArgs = params.clientArgs;
58821
58907
  let piTmpHome;
58822
58908
  let ompTmpHome;
58909
+ let opencodeTmpFile;
58823
58910
  const tmpFiles = [];
58824
58911
  const directUrl = launcherDirectUrl(process.env);
58825
58912
  if (directUrl) {
@@ -58848,6 +58935,10 @@ async function runLaunch(params, deps = {}) {
58848
58935
  if (ompTmpHome) env.PI_CODING_AGENT_DIR = ompTmpHome;
58849
58936
  } else if (base === "opencode") {
58850
58937
  env = { ...process.env, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: ca, BILLION_CONTEXT_PROXY: origin };
58938
+ const opencodePlugin = process.argv[1] ? path13.resolve(path13.dirname(process.argv[1]), "agent", "opencode.js") : void 0;
58939
+ const opencodePluginPath = opencodePlugin && fs10.existsSync(opencodePlugin) ? opencodePlugin : void 0;
58940
+ opencodeTmpFile = prepareOpencodeHttpRewrite(resolveOpencodeConfigFile(process.env), origin, routes.httpRewrites, routes.httpsRewrites, opencodePluginPath);
58941
+ if (opencodeTmpFile) env.OPENCODE_CONFIG = opencodeTmpFile;
58851
58942
  } else if (base === "codex") {
58852
58943
  const codexConversationId = injectMcp ? randomUUID2() : void 0;
58853
58944
  if (directUrl) {
@@ -58892,6 +58983,12 @@ async function runLaunch(params, deps = {}) {
58892
58983
  } catch {
58893
58984
  }
58894
58985
  }
58986
+ if (opencodeTmpFile) {
58987
+ try {
58988
+ fs10.rmSync(path13.dirname(opencodeTmpFile), { recursive: true, force: true });
58989
+ } catch {
58990
+ }
58991
+ }
58895
58992
  for (const f2 of tmpFiles) {
58896
58993
  try {
58897
58994
  fs10.rmSync(f2, { force: true });