@botconnector/bccli 0.4.2 → 0.4.4

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.
Files changed (29) hide show
  1. package/dist/{acp-UYC6APR5.js → acp-SWBX4TT6.js} +2 -2
  2. package/dist/{args-NRTZWWEV.js → args-UCLW7NID.js} +2 -2
  3. package/dist/{chunk-TIMSYZIR.js → chunk-5BVC3Y6B.js} +2 -2
  4. package/dist/{chunk-266SY3MC.js → chunk-CGBSE55G.js} +1 -1
  5. package/dist/{chunk-R72OV7RF.js → chunk-FI7RUJRX.js} +255 -71
  6. package/dist/{chunk-ZEPTUKNW.js → chunk-HBQ6OLQT.js} +76 -20
  7. package/dist/{chunk-5YJ3ZQVR.js → chunk-MSDK4IIJ.js} +9 -7
  8. package/dist/{chunk-IYR5PYA3.js → chunk-OZ5GHMTN.js} +1 -1
  9. package/dist/{chunk-KPTML72Q.js → chunk-QQJ2VVIW.js} +8 -0
  10. package/dist/{chunk-H7XJDKJY.js → chunk-RZF6A43N.js} +1 -1
  11. package/dist/{chunk-SVD4LHJC.js → chunk-SMTBYDNO.js} +1 -1
  12. package/dist/{chunk-6UO5GX55.js → chunk-TGGKACSE.js} +1 -1
  13. package/dist/{chunk-C64KM37J.js → chunk-YCHCHOMK.js} +5 -1
  14. package/dist/cli.js +22 -22
  15. package/dist/{ghBotCli-TSLRORJJ.js → ghBotCli-ZVWU7EMG.js} +8 -8
  16. package/dist/{login-RYESFZG6.js → login-QPUWIC76.js} +1 -1
  17. package/dist/lsp.d.ts +23 -0
  18. package/dist/{modelsCli-OP7CDZC7.js → modelsCli-SZK4E2BY.js} +3 -3
  19. package/dist/{providerCli-5OZI2GQQ.js → providerCli-PKI7B2SC.js} +4 -4
  20. package/dist/sdk.js +341 -92
  21. package/dist/{serve-4J7HA4JO.js → serve-L3SAIAAI.js} +9 -9
  22. package/dist/{session-YQXCCKXI.js → session-ASXO6GXR.js} +3 -3
  23. package/dist/{setup-S4AJT6XE.js → setup-F7FZ66OS.js} +7 -7
  24. package/dist/tools/diagnostics.d.ts +8 -0
  25. package/dist/tools/sandbox.d.ts +3 -0
  26. package/dist/{transferCli-R2KEIWQR.js → transferCli-HKGAWZ3Q.js} +3 -3
  27. package/dist/{ui-36ZEK65V.js → ui-NPA52YJH.js} +45 -9
  28. package/dist/{update-FSS7X5WV.js → update-AFIM34US.js} +1 -1
  29. package/package.json +1 -1
@@ -180,8 +180,8 @@ function runtimeAgent(cwd, allowAll = false) {
180
180
  return {
181
181
  async run(text, onChunk, signal, io) {
182
182
  if (!rt) {
183
- const { parseCliArgs } = await import("./args-NRTZWWEV.js");
184
- const { createRuntime } = await import("./setup-S4AJT6XE.js");
183
+ const { parseCliArgs } = await import("./args-UCLW7NID.js");
184
+ const { createRuntime } = await import("./setup-F7FZ66OS.js");
185
185
  rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
186
186
  }
187
187
  if (io && !allowAll) rt.agent.askPermission = (req) => io.askPermission(req);
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  helpText,
4
4
  parseCliArgs
5
- } from "./chunk-6UO5GX55.js";
5
+ } from "./chunk-TGGKACSE.js";
6
6
  import "./chunk-WFZKJY3R.js";
7
- import "./chunk-KPTML72Q.js";
7
+ import "./chunk-QQJ2VVIW.js";
8
8
  import "./chunk-RX4UQX43.js";
9
9
  import "./chunk-3WHI4LN3.js";
10
10
  export {
@@ -91,8 +91,8 @@ function defaultLoginDeps() {
91
91
  fetch: globalThis.fetch,
92
92
  // Wiring NYATA jalur lama: persis runLogin lama (provider add + prompt key).
93
93
  legacyAdd: async (providerId, targetCwd) => {
94
- const { runProviderCommand } = await import("./providerCli-5OZI2GQQ.js");
95
- const { parseCliArgs: parse } = await import("./args-NRTZWWEV.js");
94
+ const { runProviderCommand } = await import("./providerCli-PKI7B2SC.js");
95
+ const { parseCliArgs: parse } = await import("./args-UCLW7NID.js");
96
96
  return runProviderCommand(parse(["provider", "add", providerId]), {
97
97
  env: process.env,
98
98
  cwd: targetCwd,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.2" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.4" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
@@ -24,7 +24,7 @@ import {
24
24
  resolvePath,
25
25
  runHooks,
26
26
  validateGlobPattern
27
- } from "./chunk-ZEPTUKNW.js";
27
+ } from "./chunk-HBQ6OLQT.js";
28
28
  import {
29
29
  createWebSearchTool,
30
30
  fetchTool
@@ -37,10 +37,10 @@ import {
37
37
  } from "./chunk-WFZKJY3R.js";
38
38
  import {
39
39
  addProviderKey
40
- } from "./chunk-H7XJDKJY.js";
40
+ } from "./chunk-RZF6A43N.js";
41
41
  import {
42
42
  listAllModels
43
- } from "./chunk-IYR5PYA3.js";
43
+ } from "./chunk-OZ5GHMTN.js";
44
44
  import {
45
45
  providerName
46
46
  } from "./chunk-HQW4BROS.js";
@@ -50,14 +50,14 @@ import {
50
50
  } from "./chunk-3I5BW3ZT.js";
51
51
  import {
52
52
  Session
53
- } from "./chunk-SVD4LHJC.js";
53
+ } from "./chunk-SMTBYDNO.js";
54
54
  import {
55
55
  completionAssistantMessage,
56
56
  createProvider,
57
57
  hasPendingProgrammaticReplay,
58
58
  imageUserMessage,
59
59
  withFallbackProvider
60
- } from "./chunk-5YJ3ZQVR.js";
60
+ } from "./chunk-MSDK4IIJ.js";
61
61
  import {
62
62
  expandEnvVars
63
63
  } from "./chunk-6M55UPES.js";
@@ -1914,14 +1914,14 @@ function createRepoMapTool() {
1914
1914
  }
1915
1915
 
1916
1916
  // src/tools/diagnostics.ts
1917
- import { extname as extname3 } from "path";
1917
+ import { extname as extname3, relative as relative2 } from "path";
1918
1918
  import { z as z14 } from "zod";
1919
1919
 
1920
1920
  // src/lsp.ts
1921
1921
  import { spawn } from "child_process";
1922
1922
  import { readFileSync as readFileSync4 } from "fs";
1923
1923
  import { extname as extname2 } from "path";
1924
- import { pathToFileURL } from "url";
1924
+ import { fileURLToPath, pathToFileURL } from "url";
1925
1925
  var LANGUAGE_IDS = {
1926
1926
  ".ts": "typescript",
1927
1927
  ".tsx": "typescriptreact",
@@ -1989,86 +1989,253 @@ function createLspParser(onMessage) {
1989
1989
  }
1990
1990
  };
1991
1991
  }
1992
- function getDiagnostics(opts) {
1993
- return new Promise((resolve) => {
1994
- const child = spawn(opts.server.command, opts.server.args ?? [], {
1995
- cwd: opts.cwd,
1996
- stdio: ["pipe", "pipe", "ignore"],
1997
- shell: useShellForLsp(opts.server.command)
1992
+ function extractHoverText(contents) {
1993
+ if (!contents) return "";
1994
+ if (typeof contents === "string") return contents.trim();
1995
+ if (Array.isArray(contents)) return contents.map(extractHoverText).filter(Boolean).join("\n\n");
1996
+ if (typeof contents === "object" && "value" in contents && typeof contents.value === "string") {
1997
+ return contents.value.trim();
1998
+ }
1999
+ return "";
2000
+ }
2001
+ function normalizeLocations(raw) {
2002
+ const items = Array.isArray(raw) ? raw : raw ? [raw] : [];
2003
+ const out = [];
2004
+ for (const item of items) {
2005
+ if (!item || typeof item !== "object") continue;
2006
+ const rec = item;
2007
+ const uri = rec.uri ?? rec.targetUri;
2008
+ const start = rec.range?.start ?? rec.targetSelectionRange?.start ?? rec.targetRange?.start;
2009
+ if (!uri) continue;
2010
+ let path = uri;
2011
+ try {
2012
+ if (uri.startsWith("file:")) path = fileURLToPath(uri);
2013
+ } catch {
2014
+ }
2015
+ out.push({
2016
+ uri,
2017
+ path,
2018
+ line: start?.line ?? 0,
2019
+ character: start?.character ?? 0
1998
2020
  });
1999
- const uri = pathToFileURL(opts.file).href;
2000
- let settled = false;
2001
- let nextId = 2;
2002
- const send = (msg) => {
2003
- try {
2004
- child.stdin.write(encodeLsp(msg));
2005
- } catch {
2006
- }
2007
- };
2008
- const finish = (diags) => {
2009
- if (settled) return;
2010
- settled = true;
2011
- clearTimeout(timer);
2012
- opts.signal?.removeEventListener("abort", onAbort);
2013
- send({ jsonrpc: "2.0", id: nextId++, method: "shutdown" });
2014
- send({ jsonrpc: "2.0", method: "exit" });
2015
- const killer = setTimeout(() => {
2016
- try {
2017
- child.kill();
2018
- } catch {
2021
+ }
2022
+ return out;
2023
+ }
2024
+ function createWarmLspClient(opts) {
2025
+ let child;
2026
+ let initPromise;
2027
+ let nextId = 2;
2028
+ const opened = /* @__PURE__ */ new Map();
2029
+ const pendingRpc = /* @__PURE__ */ new Map();
2030
+ const diagWaiters = /* @__PURE__ */ new Map();
2031
+ const send = (msg) => {
2032
+ try {
2033
+ child?.stdin?.write(encodeLsp(msg));
2034
+ } catch {
2035
+ }
2036
+ };
2037
+ const resetState = () => {
2038
+ child = void 0;
2039
+ initPromise = void 0;
2040
+ opened.clear();
2041
+ for (const [, resolve] of pendingRpc) resolve(void 0);
2042
+ pendingRpc.clear();
2043
+ for (const [, waiters] of diagWaiters) {
2044
+ for (const w of waiters) w([]);
2045
+ }
2046
+ diagWaiters.clear();
2047
+ };
2048
+ const ensureStarted = () => {
2049
+ if (initPromise && child && !child.killed) return initPromise;
2050
+ opened.clear();
2051
+ initPromise = new Promise((resolveInit) => {
2052
+ const proc = spawn(opts.server.command, opts.server.args ?? [], {
2053
+ cwd: opts.cwd,
2054
+ stdio: ["pipe", "pipe", "ignore"],
2055
+ shell: useShellForLsp(opts.server.command)
2056
+ });
2057
+ child = proc;
2058
+ let initSettled = false;
2059
+ const settleInit = () => {
2060
+ if (!initSettled) {
2061
+ initSettled = true;
2062
+ resolveInit();
2019
2063
  }
2020
- }, 500);
2021
- killer.unref?.();
2022
- resolve(diags);
2023
- };
2024
- const onAbort = () => finish([]);
2025
- if (opts.signal?.aborted) return finish([]);
2026
- opts.signal?.addEventListener("abort", onAbort, { once: true });
2027
- const timer = setTimeout(() => finish([]), opts.timeoutMs ?? 8e3);
2028
- const parser = createLspParser((msg) => {
2029
- if (msg.id === 1 && msg.result) {
2030
- send({ jsonrpc: "2.0", method: "initialized", params: {} });
2031
- let text = "";
2032
- try {
2033
- text = readFileSync4(opts.file, "utf8");
2034
- } catch {
2064
+ };
2065
+ const parser = createLspParser((msg) => {
2066
+ if (msg.id === 1 && msg.result !== void 0) {
2067
+ send({ jsonrpc: "2.0", method: "initialized", params: {} });
2068
+ settleInit();
2069
+ return;
2035
2070
  }
2036
- send({
2037
- jsonrpc: "2.0",
2038
- method: "textDocument/didOpen",
2039
- params: { textDocument: { uri, languageId: languageIdFor(opts.file), version: 1, text } }
2040
- });
2041
- }
2042
- if (msg.method === "textDocument/publishDiagnostics" && msg.params?.uri === uri) {
2043
- finish(
2044
- (msg.params.diagnostics ?? []).map((d) => ({
2071
+ if (msg.id !== void 0 && pendingRpc.has(msg.id)) {
2072
+ const fn = pendingRpc.get(msg.id);
2073
+ pendingRpc.delete(msg.id);
2074
+ fn?.(msg.result);
2075
+ return;
2076
+ }
2077
+ if (msg.method === "textDocument/publishDiagnostics" && msg.params?.uri) {
2078
+ const uri = msg.params.uri;
2079
+ const diags = (msg.params.diagnostics ?? []).map((d) => ({
2045
2080
  line: d.range?.start?.line ?? 0,
2046
2081
  character: d.range?.start?.character ?? 0,
2047
2082
  severity: d.severity ?? 1,
2048
2083
  message: String(d.message ?? "")
2049
- }))
2050
- );
2051
- }
2084
+ }));
2085
+ const list = diagWaiters.get(uri);
2086
+ if (list?.length) {
2087
+ diagWaiters.delete(uri);
2088
+ for (const w of list) w(diags);
2089
+ }
2090
+ }
2091
+ });
2092
+ proc.stdout?.on("data", (c) => parser.push(c));
2093
+ proc.on("error", () => {
2094
+ resetState();
2095
+ settleInit();
2096
+ });
2097
+ proc.on("close", () => {
2098
+ resetState();
2099
+ settleInit();
2100
+ });
2101
+ send({
2102
+ jsonrpc: "2.0",
2103
+ id: 1,
2104
+ method: "initialize",
2105
+ params: { processId: process.pid, capabilities: {}, rootUri: pathToFileURL(opts.cwd).href }
2106
+ });
2052
2107
  });
2053
- child.stdout?.on("data", (c) => parser.push(c));
2054
- child.on("error", () => finish([]));
2055
- child.on("close", () => finish([]));
2056
- send({
2057
- jsonrpc: "2.0",
2058
- id: 1,
2059
- method: "initialize",
2060
- params: { processId: process.pid, capabilities: {}, rootUri: pathToFileURL(opts.cwd).href }
2108
+ return initPromise;
2109
+ };
2110
+ const syncDocument = (file) => {
2111
+ const uri = pathToFileURL(file).href;
2112
+ let text = "";
2113
+ try {
2114
+ text = readFileSync4(file, "utf8");
2115
+ } catch {
2116
+ }
2117
+ const prevVersion = opened.get(uri);
2118
+ if (prevVersion === void 0) {
2119
+ opened.set(uri, 1);
2120
+ send({
2121
+ jsonrpc: "2.0",
2122
+ method: "textDocument/didOpen",
2123
+ params: { textDocument: { uri, languageId: languageIdFor(file), version: 1, text } }
2124
+ });
2125
+ } else {
2126
+ const version = prevVersion + 1;
2127
+ opened.set(uri, version);
2128
+ send({
2129
+ jsonrpc: "2.0",
2130
+ method: "textDocument/didChange",
2131
+ params: {
2132
+ textDocument: { uri, version },
2133
+ contentChanges: [{ text }]
2134
+ }
2135
+ });
2136
+ }
2137
+ return uri;
2138
+ };
2139
+ const request = (method, params, timeoutMs = opts.timeoutMs ?? 8e3) => new Promise((resolve) => {
2140
+ const id = nextId++;
2141
+ const timer = setTimeout(() => {
2142
+ pendingRpc.delete(id);
2143
+ resolve(void 0);
2144
+ }, timeoutMs);
2145
+ pendingRpc.set(id, (res) => {
2146
+ clearTimeout(timer);
2147
+ resolve(res);
2061
2148
  });
2149
+ send({ jsonrpc: "2.0", id, method, params });
2062
2150
  });
2151
+ return {
2152
+ async diagnostics(file, timeoutMs = opts.timeoutMs ?? 8e3) {
2153
+ await ensureStarted();
2154
+ if (!child) return [];
2155
+ const uri = pathToFileURL(file).href;
2156
+ return new Promise((resolve) => {
2157
+ const timer = setTimeout(() => {
2158
+ const list2 = diagWaiters.get(uri) ?? [];
2159
+ diagWaiters.set(
2160
+ uri,
2161
+ list2.filter((w) => w !== onDiag)
2162
+ );
2163
+ resolve([]);
2164
+ }, timeoutMs);
2165
+ const onDiag = (diags) => {
2166
+ clearTimeout(timer);
2167
+ resolve(diags);
2168
+ };
2169
+ const list = diagWaiters.get(uri) ?? [];
2170
+ list.push(onDiag);
2171
+ diagWaiters.set(uri, list);
2172
+ syncDocument(file);
2173
+ });
2174
+ },
2175
+ async hover(file, line, character, timeoutMs) {
2176
+ await ensureStarted();
2177
+ if (!child) return "";
2178
+ const uri = syncDocument(file);
2179
+ const res = await request("textDocument/hover", { textDocument: { uri }, position: { line, character } }, timeoutMs);
2180
+ return extractHoverText(res?.contents);
2181
+ },
2182
+ async definition(file, line, character, timeoutMs) {
2183
+ await ensureStarted();
2184
+ if (!child) return [];
2185
+ const uri = syncDocument(file);
2186
+ const res = await request("textDocument/definition", { textDocument: { uri }, position: { line, character } }, timeoutMs);
2187
+ return normalizeLocations(res);
2188
+ },
2189
+ async references(file, line, character, timeoutMs) {
2190
+ await ensureStarted();
2191
+ if (!child) return [];
2192
+ const uri = syncDocument(file);
2193
+ const res = await request(
2194
+ "textDocument/references",
2195
+ { textDocument: { uri }, position: { line, character }, context: { includeDeclaration: true } },
2196
+ timeoutMs
2197
+ );
2198
+ return normalizeLocations(res);
2199
+ },
2200
+ async close() {
2201
+ if (!child) return;
2202
+ const proc = child;
2203
+ send({ jsonrpc: "2.0", id: nextId++, method: "shutdown" });
2204
+ send({ jsonrpc: "2.0", method: "exit" });
2205
+ resetState();
2206
+ const killer = setTimeout(() => {
2207
+ try {
2208
+ proc.kill();
2209
+ } catch {
2210
+ }
2211
+ }, 200);
2212
+ killer.unref?.();
2213
+ }
2214
+ };
2063
2215
  }
2064
2216
 
2065
2217
  // src/tools/diagnostics.ts
2066
2218
  var SEVERITY = { 1: "error", 2: "warning", 3: "info", 4: "hint" };
2067
- var SCHEMA = z14.object({ path: z14.string().describe("File to check (absolute or relative to the working directory)") });
2219
+ var SCHEMA = z14.object({
2220
+ path: z14.string().describe("File to check (absolute or relative to the working directory)"),
2221
+ action: z14.enum(["diagnostics", "hover", "definition", "references"]).optional().describe("LSP query action, default diagnostics"),
2222
+ line: z14.number().int().min(1).optional().describe("1-based line number for hover, definition, or references"),
2223
+ character: z14.number().int().min(1).optional().describe("1-based column number for hover, definition, or references")
2224
+ });
2068
2225
  function createDiagnosticsTool(servers) {
2226
+ const warmPool = /* @__PURE__ */ new Map();
2227
+ const clientFor = (server, cwd) => {
2228
+ const key = `${cwd}::${server.command}::${(server.args ?? []).join("\0")}`;
2229
+ let client = warmPool.get(key);
2230
+ if (!client) {
2231
+ client = createWarmLspClient({ server, cwd, timeoutMs: 15e3 });
2232
+ warmPool.set(key, client);
2233
+ }
2234
+ return client;
2235
+ };
2069
2236
  return defineTool({
2070
2237
  name: "diagnostics",
2071
- description: 'Run the configured LSP server(s) on one file and return its diagnostics (errors/warnings). Configure servers under "lsp.servers" in ~/.bccli/config.json, e.g. { "extensions": [".ts"], "command": "typescript-language-server", "args": ["--stdio"] }.',
2238
+ description: 'Query the configured LSP server(s) on a file for diagnostics (errors/warnings), hover docs, definition, or references. Configure servers under "lsp.servers" in ~/.bccli/config.json, e.g. { "extensions": [".ts"], "command": "typescript-language-server", "args": ["--stdio"] }.',
2072
2239
  schema: SCHEMA,
2073
2240
  kind: "read",
2074
2241
  target: (input) => input.path,
@@ -2079,7 +2246,24 @@ function createDiagnosticsTool(servers) {
2079
2246
  if (!server) {
2080
2247
  return { output: t("No LSP server is configured for {ext} files.", { ext: ext || "(none)" }), isError: true };
2081
2248
  }
2082
- const diags = await getDiagnostics({ server, cwd: ctx.cwd, file, timeoutMs: 15e3 });
2249
+ const client = clientFor(server, ctx.cwd);
2250
+ const action = input.action ?? "diagnostics";
2251
+ const line0 = Math.max(0, (input.line ?? 1) - 1);
2252
+ const char0 = Math.max(0, (input.character ?? 1) - 1);
2253
+ if (action === "hover") {
2254
+ const text = await client.hover(file, line0, char0, 15e3);
2255
+ return { output: text || "No hover information." };
2256
+ }
2257
+ if (action === "definition" || action === "references") {
2258
+ const locs = action === "definition" ? await client.definition(file, line0, char0, 15e3) : await client.references(file, line0, char0, 15e3);
2259
+ if (!locs.length) return { output: `No ${action} found.` };
2260
+ const formatted = locs.map((l) => {
2261
+ const rel = relative2(ctx.cwd, l.path).replace(/\\/g, "/") || input.path;
2262
+ return `${rel}:${l.line + 1}:${l.character + 1}`;
2263
+ });
2264
+ return { output: formatted.join("\n") };
2265
+ }
2266
+ const diags = await client.diagnostics(file, 15e3);
2083
2267
  if (!diags.length) return { output: "No diagnostics." };
2084
2268
  const lines = diags.map((d) => `${input.path}:${d.line + 1}:${d.character + 1} ${SEVERITY[d.severity] ?? "error"} ${d.message}`);
2085
2269
  return { output: lines.join("\n"), isError: diags.some((d) => d.severity === 1) };
@@ -14,6 +14,11 @@ import { join } from "path";
14
14
  import { z } from "zod";
15
15
 
16
16
  // src/tools/sandbox.ts
17
+ function winPathToWsl(winPath) {
18
+ const normalized = winPath.replace(/\\/g, "/");
19
+ const m = /^([A-Za-z]):\/(.*)$/.exec(normalized);
20
+ return m ? `/mnt/${m[1].toLowerCase()}/${m[2]}` : normalized;
21
+ }
17
22
  function darwinProfile(cwd, network) {
18
23
  const writable = [cwd, "/tmp", "/private/tmp", "/dev", "/var/folders"].map((p) => `(subpath "${p}")`).join(" ");
19
24
  return [
@@ -57,6 +62,33 @@ function sandboxArgv(command, opts) {
57
62
  command
58
63
  ];
59
64
  }
65
+ if (opts.platform === "win32" && (opts.wslBwrap || process.env.BCCLI_WIN32_WSL_SANDBOX === "1")) {
66
+ const wslCwd = winPathToWsl(opts.cwd);
67
+ return [
68
+ "wsl.exe",
69
+ "--",
70
+ "bwrap",
71
+ "--ro-bind",
72
+ "/",
73
+ "/",
74
+ "--dev-bind",
75
+ "/dev",
76
+ "/dev",
77
+ "--proc",
78
+ "/proc",
79
+ "--bind",
80
+ wslCwd,
81
+ wslCwd,
82
+ "--tmpfs",
83
+ "/tmp",
84
+ "--die-with-parent",
85
+ ...opts.network ? [] : ["--unshare-net"],
86
+ "--",
87
+ "/bin/bash",
88
+ "-c",
89
+ command
90
+ ];
91
+ }
60
92
  return void 0;
61
93
  }
62
94
 
@@ -168,10 +200,14 @@ function startBackground(command, cwd, env, shell) {
168
200
  task.status = "exited";
169
201
  task.head += `${task.head ? "\n" : ""}${error.message}`;
170
202
  });
171
- child.on("close", (code) => {
203
+ child.on("exit", (code) => {
172
204
  task.status = "exited";
173
205
  task.exitCode = code;
174
206
  });
207
+ child.on("close", (code) => {
208
+ task.status = "exited";
209
+ if (task.exitCode === null) task.exitCode = code;
210
+ });
175
211
  return task;
176
212
  }
177
213
  function backgroundStatus(task) {
@@ -275,8 +311,40 @@ function runCommand(command, opts) {
275
311
  };
276
312
  child.stdout.on("data", onData);
277
313
  child.stderr.on("data", onData);
314
+ let settled = false;
315
+ let exitDrainTimer;
316
+ let killDrainTimer;
317
+ const finish = (exitCode, extra = "") => {
318
+ if (settled) return;
319
+ settled = true;
320
+ active.delete(killAsAborted);
321
+ clearTimeout(timer);
322
+ if (exitDrainTimer) clearTimeout(exitDrainTimer);
323
+ if (killDrainTimer) clearTimeout(killDrainTimer);
324
+ opts.signal.removeEventListener("abort", onAbort);
325
+ child.stdout.removeListener("data", onData);
326
+ child.stderr.removeListener("data", onData);
327
+ child.stdout.destroy();
328
+ child.stderr.destroy();
329
+ let spillNote = "";
330
+ if (dropped && fullChunks.length) {
331
+ try {
332
+ const spillPath = join(tmpdir(), `bccli-bash-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.log`);
333
+ writeFileSync(spillPath, fullChunks.join(""), "utf8");
334
+ spillNote = `; full output saved to ${spillPath}`;
335
+ } catch {
336
+ }
337
+ }
338
+ const output = dropped ? `${head}
339
+ \u2026 [${dropped} characters truncated${spillNote}] \u2026
340
+ ${tail}` : head + tail;
341
+ resolve3({ output: output + extra, exitCode, timedOut, aborted });
342
+ };
278
343
  const kill = () => {
279
344
  if (child.pid !== void 0) killProcessTree(child.pid);
345
+ if (!killDrainTimer) {
346
+ killDrainTimer = setTimeout(() => finish(child.exitCode), 500);
347
+ }
280
348
  };
281
349
  const killAsAborted = () => {
282
350
  aborted = true;
@@ -293,29 +361,16 @@ function runCommand(command, opts) {
293
361
  };
294
362
  if (opts.signal.aborted) onAbort();
295
363
  opts.signal.addEventListener("abort", onAbort, { once: true });
296
- const finish = (exitCode, extra = "") => {
297
- active.delete(killAsAborted);
298
- clearTimeout(timer);
299
- opts.signal.removeEventListener("abort", onAbort);
300
- let spillNote = "";
301
- if (dropped && fullChunks.length) {
302
- try {
303
- const spillPath = join(tmpdir(), `bccli-bash-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.log`);
304
- writeFileSync(spillPath, fullChunks.join(""), "utf8");
305
- spillNote = `; full output saved to ${spillPath}`;
306
- } catch {
307
- }
364
+ child.on("exit", (code) => {
365
+ if (!exitDrainTimer) {
366
+ exitDrainTimer = setTimeout(() => finish(code), 200);
308
367
  }
309
- const output = dropped ? `${head}
310
- \u2026 [${dropped} characters truncated${spillNote}] \u2026
311
- ${tail}` : head + tail;
312
- resolve3({ output: output + extra, exitCode, timedOut, aborted });
313
- };
368
+ });
314
369
  child.on("error", (error) => finish(null, error.message));
315
- child.on("close", (code) => finish(code));
370
+ child.on("close", (code) => finish(code ?? child.exitCode));
316
371
  });
317
372
  }
318
- var BASH_DESCRIPTION = "Run a shell command in the project directory. No interactive input. Default timeout 2 minutes (max 10). Use for tests, builds, git, and other CLI tasks. Set background: true for long-running jobs, then poll with task_id (stop with kill: true) or use the /tasks command.";
373
+ var BASH_DESCRIPTION = "Run a shell command in the project directory. No interactive input. Default timeout 2 minutes (max 10). Use for tests, builds, git, and other CLI tasks. Set background: true for long-running jobs, then poll with task_id (stop with kill: true) or use the /tasks command. Do not pipe commands that start background daemons (such as agent-browser) through | head or | tail.";
319
374
  var BASH_SCHEMA = z.object({
320
375
  command: z.string().optional().describe("The shell command to run (required unless task_id is set)"),
321
376
  timeout_ms: z.number().int().min(1e3).max(6e5).optional().describe("Timeout in milliseconds"),
@@ -797,6 +852,7 @@ function normalizeGlobPath(path) {
797
852
  }
798
853
 
799
854
  export {
855
+ resolveShell,
800
856
  runHooks,
801
857
  renderBackgroundTasks,
802
858
  runCommand,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  reasoningPayload
4
- } from "./chunk-KPTML72Q.js";
4
+ } from "./chunk-QQJ2VVIW.js";
5
5
  import {
6
6
  t
7
7
  } from "./chunk-3WHI4LN3.js";
@@ -159,7 +159,7 @@ async function readStream(res, onText, onThinking) {
159
159
  if (!choice) return;
160
160
  if (choice.finish_reason) finishReason = choice.finish_reason;
161
161
  const delta = choice.delta ?? {};
162
- const reasoning = delta.reasoning_content || delta.reasoning;
162
+ const reasoning = delta.reasoning_content || delta.reasoning || delta.thinking;
163
163
  if (reasoning) emit({ text: "", thinking: reasoning });
164
164
  if (delta.content) emit(splitter.push(delta.content));
165
165
  for (const tc of delta.tool_calls ?? []) {
@@ -190,7 +190,7 @@ async function readStream(res, onText, onThinking) {
190
190
  const toolCalls = calls.map((call, index) => ({ ...call, id: call.id || `call_${index}` }));
191
191
  return { text, toolCalls, thinking: thinking || void 0, usage, finishReason };
192
192
  }
193
- async function readJson(res) {
193
+ async function readJson(res, onText, onThinking) {
194
194
  const body = await res.json();
195
195
  const choice = body.choices?.[0];
196
196
  const toolCalls = (choice?.message?.tool_calls ?? []).map((tc, i) => ({
@@ -199,7 +199,9 @@ async function readJson(res) {
199
199
  arguments: tc.function?.arguments ?? ""
200
200
  }));
201
201
  const split = splitThinking(choice?.message?.content ?? "");
202
- const thinking = (choice?.message?.reasoning_content || choice?.message?.reasoning || "") + split.thinking;
202
+ const thinking = (choice?.message?.reasoning_content || choice?.message?.reasoning || choice?.message?.thinking || "") + split.thinking;
203
+ if (thinking) onThinking?.(thinking);
204
+ if (split.text) onText?.(split.text);
203
205
  return { text: split.text, toolCalls, thinking: thinking || void 0, usage: toUsage(body.usage), finishReason: choice?.finish_reason };
204
206
  }
205
207
  function contentText(content) {
@@ -758,7 +760,7 @@ function createProvider(options) {
758
760
  const isBotConnectorCloud = /^https:\/\/api\.botconnector\.id\/v1\/?$/.test(baseURL) && apiKey?.startsWith("bc_live_");
759
761
  if (isBotConnectorCloud) {
760
762
  headers["x-botconnector-client"] = "bccli";
761
- headers["x-botconnector-client-version"] = "0.4.2";
763
+ headers["x-botconnector-client-version"] = "0.4.4";
762
764
  }
763
765
  const useNativeResponses = isBotConnectorCloud && providerId === "bc-cloud" && model === "gpt-6-luna";
764
766
  const useResponsesWebSocket = useNativeResponses && Boolean(apiKey) && (fetchOverride === void 0 || responsesWebSocketFactory !== void 0);
@@ -789,7 +791,7 @@ function createProvider(options) {
789
791
  baseURL: baseURL.replace(/\/+$/, ""),
790
792
  defaultHeaders: {
791
793
  "x-botconnector-client": "bccli",
792
- "x-botconnector-client-version": "0.4.2"
794
+ "x-botconnector-client-version": "0.4.4"
793
795
  }
794
796
  });
795
797
  lunaWs = responsesWebSocketFactory ? responsesWebSocketFactory(client) : new ResponsesWS(client, { reconnect: null });
@@ -942,7 +944,7 @@ function createProvider(options) {
942
944
  { model, messages, stream: true, stream_options: { include_usage: true }, ...tools?.length ? { tools } : {}, ...reasoningOverride },
943
945
  signal
944
946
  );
945
- if ((res.headers.get("content-type") ?? "").includes("application/json")) return readJson(res);
947
+ if ((res.headers.get("content-type") ?? "").includes("application/json")) return readJson(res, onText, onThinking);
946
948
  if (!res.body) throw new ProviderError(t("Empty response from the provider"));
947
949
  return readStream(res, onText, onThinking);
948
950
  },
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-HQW4BROS.js";
6
6
  import {
7
7
  createProvider
8
- } from "./chunk-5YJ3ZQVR.js";
8
+ } from "./chunk-MSDK4IIJ.js";
9
9
  import {
10
10
  PRESETS,
11
11
  readCredentials