@botconnector/bccli 0.4.0-beta.40 → 0.4.0-beta.41

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.
@@ -98,7 +98,7 @@ function runtimeAgent(cwd) {
98
98
  return {
99
99
  async run(text, onChunk, signal) {
100
100
  const { parseCliArgs } = await import("./args-4SMOHFN5.js");
101
- const { createRuntime } = await import("./setup-I7UY7X7C.js");
101
+ const { createRuntime } = await import("./setup-45WQXUBK.js");
102
102
  const rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll: true } });
103
103
  rt.agent.onEvent = (event) => {
104
104
  if (event.type === "text") onChunk(event.delta);
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runCommand,
4
4
  runHooks
5
- } from "./chunk-ZMU7MXCH.js";
5
+ } from "./chunk-DBHDZ5EP.js";
6
6
  import {
7
7
  ConfigError
8
8
  } from "./chunk-M7LLJQ7M.js";
@@ -8,6 +8,7 @@ import {
8
8
 
9
9
  // src/tools/bash.ts
10
10
  import { spawn } from "child_process";
11
+ import { existsSync as existsSync2 } from "fs";
11
12
  import { z } from "zod";
12
13
 
13
14
  // src/tools/sandbox.ts
@@ -57,6 +58,40 @@ function sandboxArgv(command, opts) {
57
58
  return void 0;
58
59
  }
59
60
 
61
+ // src/tools/shell.ts
62
+ import { existsSync } from "fs";
63
+ import { win32 } from "path";
64
+ var PS_PRELUDE = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; $OutputEncoding=[Text.Encoding]::UTF8; ";
65
+ var PS_EPILOGUE = "\nif ($LASTEXITCODE -ne $null) { exit $LASTEXITCODE } elseif (-not $?) { exit 1 }";
66
+ function gitBashCandidates(env) {
67
+ const roots = [env.ProgramW6432, env.ProgramFiles, env["ProgramFiles(x86)"], env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs")];
68
+ const fromRoots = roots.filter((root) => !!root).map((root) => win32.join(root, "Git", "bin", "bash.exe"));
69
+ const fromPath = (env.PATH ?? env.Path ?? "").split(";").filter(Boolean).map((dir) => win32.join(dir, "..", "bin", "bash.exe"));
70
+ return [...fromRoots, ...fromPath];
71
+ }
72
+ function resolveShell(deps) {
73
+ if (deps.platform !== "win32") return void 0;
74
+ const bash = gitBashCandidates(deps.env).find((candidate) => deps.exists(candidate));
75
+ if (bash) return { name: "bash", file: bash, args: (command) => ["-c", command] };
76
+ return {
77
+ name: "powershell",
78
+ file: "powershell.exe",
79
+ args: (command) => [
80
+ "-NoProfile",
81
+ "-NonInteractive",
82
+ "-ExecutionPolicy",
83
+ "Bypass",
84
+ "-EncodedCommand",
85
+ Buffer.from(PS_PRELUDE + command + PS_EPILOGUE, "utf16le").toString("base64")
86
+ ]
87
+ };
88
+ }
89
+ var cachedDefault = null;
90
+ function defaultShell() {
91
+ if (cachedDefault === null) cachedDefault = resolveShell({ platform: process.platform, env: process.env, exists: existsSync });
92
+ return cachedDefault;
93
+ }
94
+
60
95
  // src/tools/bash.ts
61
96
  var HALF = 15e3;
62
97
  function killProcessTree(pid, platform = process.platform, spawnFn = spawn) {
@@ -87,8 +122,8 @@ function killAllCommands() {
87
122
  }
88
123
  var backgrounds = /* @__PURE__ */ new Map();
89
124
  var nextBackgroundId = 1;
90
- function startBackground(command, cwd, env) {
91
- const child = spawnChild(command, cwd, env);
125
+ function startBackground(command, cwd, env, shell) {
126
+ const child = spawnChild(command, cwd, env, shell);
92
127
  const task = {
93
128
  id: nextBackgroundId++,
94
129
  command: Array.isArray(command) ? command.join(" ") : command,
@@ -159,8 +194,14 @@ function renderBackgroundTasks() {
159
194
  return `Background tasks:
160
195
  ${lines.join("\n")}`;
161
196
  }
162
- function spawnChild(command, cwd, env) {
163
- return Array.isArray(command) ? spawn(command[0], command.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env }) : spawn(command, { cwd, shell: true, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
197
+ function spawnChild(command, cwd, env, shell) {
198
+ if (Array.isArray(command)) {
199
+ return spawn(command[0], command.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
200
+ }
201
+ if (shell) {
202
+ return spawn(shell.file, shell.args(command), { cwd, shell: false, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
203
+ }
204
+ return spawn(command, { cwd, shell: true, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
164
205
  }
165
206
  var NETWORK_PATTERNS = [
166
207
  /\b(curl|wget|ftp|scp|sftp|rsync|lynx|telnet)\b/i,
@@ -196,7 +237,7 @@ function offlineEnv(env = process.env) {
196
237
  }
197
238
  function runCommand(command, opts) {
198
239
  return new Promise((resolve) => {
199
- const child = spawnChild(command, opts.cwd, opts.env);
240
+ const child = spawnChild(command, opts.cwd, opts.env, opts.shell ?? defaultShell());
200
241
  if (!exitHookInstalled) {
201
242
  process.on("exit", killAllCommands);
202
243
  exitHookInstalled = true;
@@ -264,13 +305,20 @@ var BASH_SCHEMA = z.object({
264
305
  task_id: z.number().int().optional().describe("Poll a background task started with background: true (omit command)"),
265
306
  kill: z.boolean().optional().describe("With task_id: stop the background task")
266
307
  });
308
+ var SHELL_NOTE = {
309
+ bash: "Shell: Git Bash. Unix tools such as tail, grep, ls, sed and head are available.",
310
+ powershell: "Shell: Windows PowerShell 5.1. Unix tools such as tail, grep, ls, sed and head are NOT installed; use PowerShell equivalents (Select-Object -Last 40, Select-String, Get-ChildItem, Get-Content)."
311
+ };
267
312
  function createBashTool(options = {}) {
268
313
  const offline = options.networkPolicy === "offline";
269
314
  const sandbox = options.sandbox === true;
270
315
  const platform = options.platform ?? process.platform;
316
+ const shell = resolveShell({ platform, env: process.env, exists: existsSync2, ...options.shellDeps });
271
317
  const childEnv = offline ? offlineEnv() : void 0;
318
+ const shellNote = shell ? `
319
+ ${SHELL_NOTE[shell.name]}` : "";
272
320
  const description = `${offline ? `${BASH_DESCRIPTION}
273
- Network access is off (networkPolicy "offline"): internet commands such as curl, wget, git fetch/push/clone, package installs (npm, pip, ...), gh, and docker pull are blocked.` : BASH_DESCRIPTION}${sandbox ? "\nCommands run inside an OS sandbox: file writes are limited to the working directory and temp areas." : ""}`;
321
+ Network access is off (networkPolicy "offline"): internet commands such as curl, wget, git fetch/push/clone, package installs (npm, pip, ...), gh, and docker pull are blocked.` : BASH_DESCRIPTION}${sandbox ? "\nCommands run inside an OS sandbox: file writes are limited to the working directory and temp areas." : ""}${shellNote}`;
274
322
  return defineTool({
275
323
  name: "bash",
276
324
  description,
@@ -310,7 +358,7 @@ Network access is off (networkPolicy "offline"): internet commands such as curl,
310
358
  }
311
359
  if (input.background) {
312
360
  if (!input.command) return { output: 'The "command" argument is required to start a background task.', isError: true };
313
- const task = startBackground(exec, ctx.cwd, childEnv);
361
+ const task = startBackground(exec, ctx.cwd, childEnv, shell);
314
362
  return {
315
363
  output: `Background task #${task.id} started: ${input.command}
316
364
  Poll it with {task_id: ${task.id}}; stop it with {task_id: ${task.id}, kill: true}.`
@@ -323,7 +371,8 @@ Poll it with {task_id: ${task.id}}; stop it with {task_id: ${task.id}, kill: tru
323
371
  cwd: ctx.cwd,
324
372
  timeoutMs: input.timeout_ms ?? 12e4,
325
373
  signal: ctx.signal,
326
- env: childEnv
374
+ env: childEnv,
375
+ shell
327
376
  });
328
377
  const status = r.timedOut ? `[stopped: timeout after ${Math.round((input.timeout_ms ?? 12e4) / 1e3)} seconds]` : r.aborted ? "[cancelled by the user]" : `[exit code ${r.exitCode}]`;
329
378
  return { output: `${r.output.trimEnd()}
@@ -353,12 +402,12 @@ var BUILTIN_AGENTS = [
353
402
  ];
354
403
 
355
404
  // src/context.ts
356
- import { existsSync, readFileSync } from "fs";
405
+ import { existsSync as existsSync3, readFileSync } from "fs";
357
406
  import { dirname, join } from "path";
358
407
  var FILES = ["AGENTS.md", "BCCLI.md"];
359
408
  function readIf(path) {
360
409
  try {
361
- return existsSync(path) ? readFileSync(path, "utf8").trim() : void 0;
410
+ return existsSync3(path) ? readFileSync(path, "utf8").trim() : void 0;
362
411
  } catch {
363
412
  return void 0;
364
413
  }
@@ -382,7 +431,7 @@ ${text}`);
382
431
  }
383
432
  function isGitRepo(cwd) {
384
433
  for (let dir = cwd; ; dir = dirname(dir)) {
385
- if (existsSync(join(dir, ".git"))) return true;
434
+ if (existsSync3(join(dir, ".git"))) return true;
386
435
  if (dirname(dir) === dir) return false;
387
436
  }
388
437
  }
@@ -426,7 +475,7 @@ ${instructions}` : ""}`;
426
475
  }
427
476
 
428
477
  // src/extensions.ts
429
- import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
478
+ import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
430
479
  import { basename, join as join2 } from "path";
431
480
  function parseFrontmatter(text) {
432
481
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
@@ -461,7 +510,7 @@ function loadSkills(r) {
461
510
  for (const dir of dirs(r, "skills")) {
462
511
  for (const entry of list(dir)) {
463
512
  const file = join2(dir, entry, "SKILL.md");
464
- if (!existsSync2(file)) continue;
513
+ if (!existsSync4(file)) continue;
465
514
  const { data } = parseFrontmatter(readFileSync2(file, "utf8"));
466
515
  const name = str(data.name) || entry;
467
516
  byName.set(name, { name, description: str(data.description) ?? "", dir: join2(dir, entry), file });
@@ -590,12 +639,12 @@ async function runHooks(hooks, event, payload = {}, opts = {}) {
590
639
  }
591
640
 
592
641
  // src/slash/memory.ts
593
- import { appendFileSync, existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
642
+ import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
594
643
  function instructionFiles(cwd, home) {
595
- return instructionPaths(cwd, home).filter((path) => existsSync3(path)).map((path) => ({ path, lines: readFileSync3(path, "utf8").split("\n").filter(Boolean).length }));
644
+ return instructionPaths(cwd, home).filter((path) => existsSync5(path)).map((path) => ({ path, lines: readFileSync3(path, "utf8").split("\n").filter(Boolean).length }));
596
645
  }
597
646
  function appendMemory(file, text) {
598
- const prefix = existsSync3(file) && !readFileSync3(file, "utf8").endsWith("\n") ? "\n" : "";
647
+ const prefix = existsSync5(file) && !readFileSync3(file, "utf8").endsWith("\n") ? "\n" : "";
599
648
  appendFileSync(file, `${prefix}- ${text.trim()}
600
649
  `);
601
650
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.0-beta.40" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.0-beta.41" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
@@ -17,7 +17,7 @@ import {
17
17
  parseFrontmatter,
18
18
  runHooks,
19
19
  validateGlobPattern
20
- } from "./chunk-ZMU7MXCH.js";
20
+ } from "./chunk-DBHDZ5EP.js";
21
21
  import {
22
22
  Permissions
23
23
  } from "./chunk-GAFJEQTJ.js";
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-PDVS4UWM.js";
4
+ } from "./chunk-EQQTTE2K.js";
5
5
  import {
6
6
  resolveWorktree,
7
7
  runPrint
8
- } from "./chunk-RV74TCEP.js";
8
+ } from "./chunk-BUHWQU3V.js";
9
9
  import {
10
10
  helpText,
11
11
  parseCliArgs
@@ -15,9 +15,9 @@ import {
15
15
  } from "./chunk-DSFHN5CH.js";
16
16
  import {
17
17
  createRuntime
18
- } from "./chunk-WH7XLDGZ.js";
18
+ } from "./chunk-M4IYXI3V.js";
19
19
  import "./chunk-3HCOAJEQ.js";
20
- import "./chunk-ZMU7MXCH.js";
20
+ import "./chunk-DBHDZ5EP.js";
21
21
  import "./chunk-GAFJEQTJ.js";
22
22
  import "./chunk-JROUQ5YS.js";
23
23
  import "./chunk-LN32JIZR.js";
@@ -90,16 +90,16 @@ async function main() {
90
90
  return runModelsCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), fetch: globalThis.fetch });
91
91
  }
92
92
  if (args.command === "update") {
93
- const { runUpdateCommand } = await import("./update-SZUG3YSB.js");
93
+ const { runUpdateCommand } = await import("./update-VBDEHHMR.js");
94
94
  return runUpdateCommand({ env: process.env });
95
95
  }
96
96
  if (args.command === "acp") {
97
- const { runtimeAgent, runAcp } = await import("./acp-5A7EXLCG.js");
97
+ const { runtimeAgent, runAcp } = await import("./acp-SZWZ5EE4.js");
98
98
  await runAcp(process.stdin, process.stdout, { cwd, newAgent: (c) => runtimeAgent(c) });
99
99
  return 0;
100
100
  }
101
101
  if (args.command === "serve") {
102
- const { startServe } = await import("./serve-JNQUP7CZ.js");
102
+ const { startServe } = await import("./serve-KQ35P4W3.js");
103
103
  const handle = await startServe({ port: args.port, host: args.host, token: args.token, cwd, env: process.env });
104
104
  process.stderr.write(`bccli serve ${handle.url} \u2014 Authorization: Bearer ${handle.token}
105
105
  `);
@@ -135,13 +135,13 @@ async function main() {
135
135
  if (!process.stdin.isTTY) throw new ConfigError(t('Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"'));
136
136
  if (rt.config.updateCheck !== "off" && !process.env.BCCLI_NO_UPDATE_CHECK) {
137
137
  try {
138
- const { checkForUpdate } = await import("./update-SZUG3YSB.js");
138
+ const { checkForUpdate } = await import("./update-VBDEHHMR.js");
139
139
  const update = await checkForUpdate({ home: rt.home, fetch: globalThis.fetch, now: /* @__PURE__ */ new Date() });
140
140
  if (update) console.error(update);
141
141
  } catch {
142
142
  }
143
143
  }
144
- const { startInteractive } = await import("./ui-GVIMUZNS.js");
144
+ const { startInteractive } = await import("./ui-S4QFJJIB.js");
145
145
  return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
146
146
  }
147
147
  main().then(
package/dist/sdk.js CHANGED
@@ -1900,6 +1900,7 @@ import { z as z8 } from "zod";
1900
1900
 
1901
1901
  // src/tools/bash.ts
1902
1902
  import { spawn as spawn2 } from "child_process";
1903
+ import { existsSync as existsSync3 } from "fs";
1903
1904
  import { z } from "zod";
1904
1905
 
1905
1906
  // src/tools/sandbox.ts
@@ -1949,6 +1950,40 @@ function sandboxArgv(command, opts) {
1949
1950
  return void 0;
1950
1951
  }
1951
1952
 
1953
+ // src/tools/shell.ts
1954
+ import { existsSync as existsSync2 } from "fs";
1955
+ import { win32 } from "path";
1956
+ var PS_PRELUDE = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; $OutputEncoding=[Text.Encoding]::UTF8; ";
1957
+ var PS_EPILOGUE = "\nif ($LASTEXITCODE -ne $null) { exit $LASTEXITCODE } elseif (-not $?) { exit 1 }";
1958
+ function gitBashCandidates(env) {
1959
+ const roots = [env.ProgramW6432, env.ProgramFiles, env["ProgramFiles(x86)"], env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs")];
1960
+ const fromRoots = roots.filter((root) => !!root).map((root) => win32.join(root, "Git", "bin", "bash.exe"));
1961
+ const fromPath = (env.PATH ?? env.Path ?? "").split(";").filter(Boolean).map((dir) => win32.join(dir, "..", "bin", "bash.exe"));
1962
+ return [...fromRoots, ...fromPath];
1963
+ }
1964
+ function resolveShell(deps) {
1965
+ if (deps.platform !== "win32") return void 0;
1966
+ const bash = gitBashCandidates(deps.env).find((candidate) => deps.exists(candidate));
1967
+ if (bash) return { name: "bash", file: bash, args: (command) => ["-c", command] };
1968
+ return {
1969
+ name: "powershell",
1970
+ file: "powershell.exe",
1971
+ args: (command) => [
1972
+ "-NoProfile",
1973
+ "-NonInteractive",
1974
+ "-ExecutionPolicy",
1975
+ "Bypass",
1976
+ "-EncodedCommand",
1977
+ Buffer.from(PS_PRELUDE + command + PS_EPILOGUE, "utf16le").toString("base64")
1978
+ ]
1979
+ };
1980
+ }
1981
+ var cachedDefault = null;
1982
+ function defaultShell() {
1983
+ if (cachedDefault === null) cachedDefault = resolveShell({ platform: process.platform, env: process.env, exists: existsSync2 });
1984
+ return cachedDefault;
1985
+ }
1986
+
1952
1987
  // src/tools/types.ts
1953
1988
  function defineTool(tool) {
1954
1989
  return tool;
@@ -1984,8 +2019,8 @@ function killAllCommands() {
1984
2019
  }
1985
2020
  var backgrounds = /* @__PURE__ */ new Map();
1986
2021
  var nextBackgroundId = 1;
1987
- function startBackground(command, cwd, env) {
1988
- const child = spawnChild(command, cwd, env);
2022
+ function startBackground(command, cwd, env, shell) {
2023
+ const child = spawnChild(command, cwd, env, shell);
1989
2024
  const task = {
1990
2025
  id: nextBackgroundId++,
1991
2026
  command: Array.isArray(command) ? command.join(" ") : command,
@@ -2046,8 +2081,14 @@ ${task.tail}` : task.head + task.tail;
2046
2081
  return `${body.trimEnd()}
2047
2082
  ${backgroundStatus(task)}`.trimStart();
2048
2083
  }
2049
- function spawnChild(command, cwd, env) {
2050
- return Array.isArray(command) ? spawn2(command[0], command.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env }) : spawn2(command, { cwd, shell: true, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
2084
+ function spawnChild(command, cwd, env, shell) {
2085
+ if (Array.isArray(command)) {
2086
+ return spawn2(command[0], command.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
2087
+ }
2088
+ if (shell) {
2089
+ return spawn2(shell.file, shell.args(command), { cwd, shell: false, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
2090
+ }
2091
+ return spawn2(command, { cwd, shell: true, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"], env });
2051
2092
  }
2052
2093
  var NETWORK_PATTERNS = [
2053
2094
  /\b(curl|wget|ftp|scp|sftp|rsync|lynx|telnet)\b/i,
@@ -2083,7 +2124,7 @@ function offlineEnv(env = process.env) {
2083
2124
  }
2084
2125
  function runCommand(command, opts) {
2085
2126
  return new Promise((resolve4) => {
2086
- const child = spawnChild(command, opts.cwd, opts.env);
2127
+ const child = spawnChild(command, opts.cwd, opts.env, opts.shell ?? defaultShell());
2087
2128
  if (!exitHookInstalled) {
2088
2129
  process.on("exit", killAllCommands);
2089
2130
  exitHookInstalled = true;
@@ -2151,13 +2192,20 @@ var BASH_SCHEMA = z.object({
2151
2192
  task_id: z.number().int().optional().describe("Poll a background task started with background: true (omit command)"),
2152
2193
  kill: z.boolean().optional().describe("With task_id: stop the background task")
2153
2194
  });
2195
+ var SHELL_NOTE = {
2196
+ bash: "Shell: Git Bash. Unix tools such as tail, grep, ls, sed and head are available.",
2197
+ powershell: "Shell: Windows PowerShell 5.1. Unix tools such as tail, grep, ls, sed and head are NOT installed; use PowerShell equivalents (Select-Object -Last 40, Select-String, Get-ChildItem, Get-Content)."
2198
+ };
2154
2199
  function createBashTool(options = {}) {
2155
2200
  const offline = options.networkPolicy === "offline";
2156
2201
  const sandbox = options.sandbox === true;
2157
2202
  const platform = options.platform ?? process.platform;
2203
+ const shell = resolveShell({ platform, env: process.env, exists: existsSync3, ...options.shellDeps });
2158
2204
  const childEnv = offline ? offlineEnv() : void 0;
2205
+ const shellNote = shell ? `
2206
+ ${SHELL_NOTE[shell.name]}` : "";
2159
2207
  const description = `${offline ? `${BASH_DESCRIPTION}
2160
- Network access is off (networkPolicy "offline"): internet commands such as curl, wget, git fetch/push/clone, package installs (npm, pip, ...), gh, and docker pull are blocked.` : BASH_DESCRIPTION}${sandbox ? "\nCommands run inside an OS sandbox: file writes are limited to the working directory and temp areas." : ""}`;
2208
+ Network access is off (networkPolicy "offline"): internet commands such as curl, wget, git fetch/push/clone, package installs (npm, pip, ...), gh, and docker pull are blocked.` : BASH_DESCRIPTION}${sandbox ? "\nCommands run inside an OS sandbox: file writes are limited to the working directory and temp areas." : ""}${shellNote}`;
2161
2209
  return defineTool({
2162
2210
  name: "bash",
2163
2211
  description,
@@ -2197,7 +2245,7 @@ Network access is off (networkPolicy "offline"): internet commands such as curl,
2197
2245
  }
2198
2246
  if (input.background) {
2199
2247
  if (!input.command) return { output: 'The "command" argument is required to start a background task.', isError: true };
2200
- const task = startBackground(exec, ctx.cwd, childEnv);
2248
+ const task = startBackground(exec, ctx.cwd, childEnv, shell);
2201
2249
  return {
2202
2250
  output: `Background task #${task.id} started: ${input.command}
2203
2251
  Poll it with {task_id: ${task.id}}; stop it with {task_id: ${task.id}, kill: true}.`
@@ -2210,7 +2258,8 @@ Poll it with {task_id: ${task.id}}; stop it with {task_id: ${task.id}, kill: tru
2210
2258
  cwd: ctx.cwd,
2211
2259
  timeoutMs: input.timeout_ms ?? 12e4,
2212
2260
  signal: ctx.signal,
2213
- env: childEnv
2261
+ env: childEnv,
2262
+ shell
2214
2263
  });
2215
2264
  const status = r.timedOut ? `[stopped: timeout after ${Math.round((input.timeout_ms ?? 12e4) / 1e3)} seconds]` : r.aborted ? "[cancelled by the user]" : `[exit code ${r.exitCode}]`;
2216
2265
  return { output: `${r.output.trimEnd()}
@@ -2926,7 +2975,7 @@ function createReadTool(options = {}) {
2926
2975
  var readTool = createReadTool({ vision: true });
2927
2976
 
2928
2977
  // src/tools/write.ts
2929
- import { existsSync as existsSync2 } from "fs";
2978
+ import { existsSync as existsSync4 } from "fs";
2930
2979
  import { mkdir, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
2931
2980
  import { dirname } from "path";
2932
2981
  import { z as z7 } from "zod";
@@ -2941,16 +2990,16 @@ var writeTool = defineTool({
2941
2990
  target: (input) => input.path,
2942
2991
  async validate(input, ctx) {
2943
2992
  const abs = resolvePath(ctx.cwd, input.path);
2944
- return existsSync2(abs) && !ctx.readFiles.has(abs) ? `${input.path} already exists. Read it with read before overwriting it.` : void 0;
2993
+ return existsSync4(abs) && !ctx.readFiles.has(abs) ? `${input.path} already exists. Read it with read before overwriting it.` : void 0;
2945
2994
  },
2946
2995
  async preview(input, ctx) {
2947
2996
  const abs = resolvePath(ctx.cwd, input.path);
2948
- const old = existsSync2(abs) ? await readFile4(abs, "utf8") : "";
2997
+ const old = existsSync4(abs) ? await readFile4(abs, "utf8") : "";
2949
2998
  return formatDiff(diffLines(old, input.content));
2950
2999
  },
2951
3000
  async run(input, ctx) {
2952
3001
  const abs = resolvePath(ctx.cwd, input.path);
2953
- if (existsSync2(abs) && !ctx.readFiles.has(abs)) {
3002
+ if (existsSync4(abs) && !ctx.readFiles.has(abs)) {
2954
3003
  return { output: `${input.path} already exists. Read it with read before overwriting it.`, isError: true };
2955
3004
  }
2956
3005
  try {
@@ -3428,7 +3477,7 @@ ${t("This model may not support tool calling. Try another model with /model.")}`
3428
3477
  };
3429
3478
 
3430
3479
  // src/checkpoints.ts
3431
- import { existsSync as existsSync3, statSync } from "fs";
3480
+ import { existsSync as existsSync5, statSync } from "fs";
3432
3481
  import { readFile as readFile5, rm, writeFile as writeFile3 } from "fs/promises";
3433
3482
  var MAX_TURNS = 20;
3434
3483
  var MAX_BYTES2 = 2 * 1024 * 1024;
@@ -3466,7 +3515,7 @@ var CheckpointStore = class {
3466
3515
  if (!this.current) this.beginTurn();
3467
3516
  const turn = this.current;
3468
3517
  if (turn.has(path)) return;
3469
- if (!existsSync3(path)) turn.set(path, null);
3518
+ if (!existsSync5(path)) turn.set(path, null);
3470
3519
  else if (statSync(path).size > MAX_BYTES2) turn.set(path, "skipped");
3471
3520
  else turn.set(path, await readFile5(path));
3472
3521
  while (this.turns() > MAX_TURNS) this.history.shift();
@@ -3534,7 +3583,7 @@ var CheckpointStore = class {
3534
3583
  continue;
3535
3584
  }
3536
3585
  try {
3537
- if (!existsSync3(path)) into.set(path, null);
3586
+ if (!existsSync5(path)) into.set(path, null);
3538
3587
  else if (statSync(path).size > MAX_BYTES2) into.set(path, "skipped");
3539
3588
  else into.set(path, await readFile5(path));
3540
3589
  } catch {
@@ -3593,7 +3642,7 @@ import { z as z9 } from "zod";
3593
3642
 
3594
3643
  // src/mcp/config.ts
3595
3644
  import { createHash } from "crypto";
3596
- import { chmodSync as chmodSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3645
+ import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3597
3646
  import { dirname as dirname2, join as join3, resolve as resolve3 } from "path";
3598
3647
  var ENV_REF = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
3599
3648
  function expandEnvVars(config, env) {
@@ -3616,14 +3665,14 @@ function expandEnvVars(config, env) {
3616
3665
 
3617
3666
  // src/mcp/oauth.ts
3618
3667
  import { spawn as spawn3 } from "child_process";
3619
- import { chmodSync as chmodSync3, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3668
+ import { chmodSync as chmodSync3, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3620
3669
  import { createServer } from "http";
3621
3670
  import { dirname as dirname3, join as join4 } from "path";
3622
3671
  import { auth } from "@modelcontextprotocol/sdk/client/auth.js";
3623
3672
  var oauthStorePath = (home) => join4(home, "mcp-oauth.json");
3624
3673
  function readStore(home) {
3625
3674
  const path = oauthStorePath(home);
3626
- if (!existsSync5(path)) return {};
3675
+ if (!existsSync7(path)) return {};
3627
3676
  try {
3628
3677
  return JSON.parse(readFileSync4(path, "utf8"));
3629
3678
  } catch {
@@ -3887,12 +3936,12 @@ var McpManager = class {
3887
3936
  import { homedir as homedir2 } from "os";
3888
3937
 
3889
3938
  // src/context.ts
3890
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
3939
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
3891
3940
  import { dirname as dirname4, join as join5 } from "path";
3892
3941
  var FILES = ["AGENTS.md", "BCCLI.md"];
3893
3942
  function readIf(path) {
3894
3943
  try {
3895
- return existsSync6(path) ? readFileSync5(path, "utf8").trim() : void 0;
3944
+ return existsSync8(path) ? readFileSync5(path, "utf8").trim() : void 0;
3896
3945
  } catch {
3897
3946
  return void 0;
3898
3947
  }
@@ -3916,7 +3965,7 @@ ${text}`);
3916
3965
  }
3917
3966
  function isGitRepo(cwd) {
3918
3967
  for (let dir = cwd; ; dir = dirname4(dir)) {
3919
- if (existsSync6(join5(dir, ".git"))) return true;
3968
+ if (existsSync8(join5(dir, ".git"))) return true;
3920
3969
  if (dirname4(dir) === dir) return false;
3921
3970
  }
3922
3971
  }
@@ -3960,7 +4009,7 @@ ${instructions}` : ""}`;
3960
4009
  }
3961
4010
 
3962
4011
  // src/extensions.ts
3963
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
4012
+ import { existsSync as existsSync9, readdirSync, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
3964
4013
  import { basename, join as join6 } from "path";
3965
4014
  function parseFrontmatter(text) {
3966
4015
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
@@ -3995,7 +4044,7 @@ function loadSkills(r) {
3995
4044
  for (const dir of dirs(r, "skills")) {
3996
4045
  for (const entry of list(dir)) {
3997
4046
  const file = join6(dir, entry, "SKILL.md");
3998
- if (!existsSync7(file)) continue;
4047
+ if (!existsSync9(file)) continue;
3999
4048
  const { data } = parseFrontmatter(readFileSync6(file, "utf8"));
4000
4049
  const name = str(data.name) || entry;
4001
4050
  byName.set(name, { name, description: str(data.description) ?? "", dir: join6(dir, entry), file });
@@ -4102,7 +4151,7 @@ async function addProviderKey(providerId, key, deps) {
4102
4151
 
4103
4152
  // src/session.ts
4104
4153
  import { randomBytes as randomBytes2 } from "crypto";
4105
- import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync, statSync as statSync3 } from "fs";
4154
+ import { appendFileSync, existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync, statSync as statSync3 } from "fs";
4106
4155
  import { join as join8 } from "path";
4107
4156
  function projectDir(home, cwd) {
4108
4157
  const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(-100) || "root";
@@ -4132,7 +4181,7 @@ var Session = class _Session {
4132
4181
  }
4133
4182
  static list(home, cwd) {
4134
4183
  const dir = projectDir(home, cwd);
4135
- if (!existsSync8(dir)) return [];
4184
+ if (!existsSync10(dir)) return [];
4136
4185
  return readdirSync2(dir).filter((f) => f.endsWith(".jsonl")).map((f) => {
4137
4186
  const session = new _Session(join8(dir, f));
4138
4187
  const first = session.load().find((m) => m.role === "user");
@@ -4153,7 +4202,7 @@ var Session = class _Session {
4153
4202
  this.write({ t: "reset" });
4154
4203
  }
4155
4204
  load() {
4156
- if (!existsSync8(this.file)) return [];
4205
+ if (!existsSync10(this.file)) return [];
4157
4206
  let messages = [];
4158
4207
  for (const line of readFileSync7(this.file, "utf8").split("\n")) {
4159
4208
  if (!line.trim()) continue;
@@ -4403,14 +4452,14 @@ function createTodoTool(store) {
4403
4452
  }
4404
4453
 
4405
4454
  // src/tools/memory.ts
4406
- import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
4455
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4407
4456
  import { join as join9 } from "path";
4408
4457
  import { z as z15 } from "zod";
4409
4458
 
4410
4459
  // src/slash/memory.ts
4411
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
4460
+ import { appendFileSync as appendFileSync2, existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
4412
4461
  function appendMemory(file, text) {
4413
- const prefix = existsSync9(file) && !readFileSync9(file, "utf8").endsWith("\n") ? "\n" : "";
4462
+ const prefix = existsSync11(file) && !readFileSync9(file, "utf8").endsWith("\n") ? "\n" : "";
4414
4463
  appendFileSync2(file, `${prefix}- ${text.trim()}
4415
4464
  `);
4416
4465
  }
@@ -4430,7 +4479,7 @@ function createSaveMemoryTool(opts) {
4430
4479
  const content = input.content.trim();
4431
4480
  if (!content) return { output: "Memory content is empty.", isError: true };
4432
4481
  const file = input.scope === "global" ? join9(opts.home, "BCCLI.md") : join9(ctx.cwd, "AGENTS.md");
4433
- if (existsSync10(file)) {
4482
+ if (existsSync12(file)) {
4434
4483
  const lines = readFileSync10(file, "utf8").split("\n");
4435
4484
  if (lines.some((line) => line.trim() === `- ${content}`)) {
4436
4485
  return { output: `Already saved to ${file}.` };
@@ -4711,7 +4760,7 @@ function createDiagnosticsTool(servers) {
4711
4760
  }
4712
4761
 
4713
4762
  // src/plugins.ts
4714
- import { existsSync as existsSync11 } from "fs";
4763
+ import { existsSync as existsSync13 } from "fs";
4715
4764
  import { createRequire } from "module";
4716
4765
  import { isAbsolute as isAbsolute3, join as join11 } from "path";
4717
4766
  import { z as z18 } from "zod";
@@ -4742,7 +4791,7 @@ function loadPlugins(specs, opts) {
4742
4791
  } catch {
4743
4792
  throw new ConfigError(t("Plugin not found: {spec}", { spec }));
4744
4793
  }
4745
- if (!existsSync11(file)) throw new ConfigError(t("Plugin not found: {spec}", { spec }));
4794
+ if (!existsSync13(file)) throw new ConfigError(t("Plugin not found: {spec}", { spec }));
4746
4795
  let mod;
4747
4796
  try {
4748
4797
  mod = require_(file);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-PDVS4UWM.js";
4
+ } from "./chunk-EQQTTE2K.js";
5
5
  import {
6
6
  LOOPBACK_BIND,
7
7
  MAX_FRAME_BYTES,
@@ -13,9 +13,9 @@ import {
13
13
  } from "./chunk-AS7VV7D3.js";
14
14
  import {
15
15
  createRuntime
16
- } from "./chunk-WH7XLDGZ.js";
16
+ } from "./chunk-M4IYXI3V.js";
17
17
  import "./chunk-3HCOAJEQ.js";
18
- import "./chunk-ZMU7MXCH.js";
18
+ import "./chunk-DBHDZ5EP.js";
19
19
  import "./chunk-GAFJEQTJ.js";
20
20
  import "./chunk-JROUQ5YS.js";
21
21
  import {
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  createRuntime,
4
4
  lunaPtcAutoEnabled
5
- } from "./chunk-WH7XLDGZ.js";
5
+ } from "./chunk-M4IYXI3V.js";
6
6
  import "./chunk-3HCOAJEQ.js";
7
- import "./chunk-ZMU7MXCH.js";
7
+ import "./chunk-DBHDZ5EP.js";
8
8
  import "./chunk-GAFJEQTJ.js";
9
9
  import "./chunk-JROUQ5YS.js";
10
10
  import "./chunk-LN32JIZR.js";
@@ -9,7 +9,7 @@ import {
9
9
  toolLabel,
10
10
  verifyFollowup,
11
11
  worktreeListText
12
- } from "./chunk-RV74TCEP.js";
12
+ } from "./chunk-BUHWQU3V.js";
13
13
  import {
14
14
  BUILTIN_AGENTS,
15
15
  appendMemory,
@@ -21,7 +21,7 @@ import {
21
21
  renderBackgroundTasks,
22
22
  runHooks,
23
23
  validateGlobPattern
24
- } from "./chunk-ZMU7MXCH.js";
24
+ } from "./chunk-DBHDZ5EP.js";
25
25
  import {
26
26
  nextMode
27
27
  } from "./chunk-GAFJEQTJ.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-PDVS4UWM.js";
4
+ } from "./chunk-EQQTTE2K.js";
5
5
  import {
6
6
  t
7
7
  } from "./chunk-M23QBX3V.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.40",
3
+ "version": "0.4.0-beta.41",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {