@botconnector/bccli 0.4.0-beta.14 → 0.4.0-beta.16
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/README.md +14 -0
- package/dist/args-L555OESS.js +12 -0
- package/dist/{chunk-6BLZELE6.js → chunk-4KMOCORM.js} +2 -2
- package/dist/{chunk-TRMRDQ43.js → chunk-6AVRFRFU.js} +31 -24
- package/dist/{chunk-7S6JXQCH.js → chunk-D7CF42EW.js} +2 -1
- package/dist/chunk-DDA5TJ7T.js +440 -0
- package/dist/{chunk-BFZXRKW5.js → chunk-ERVDVPKJ.js} +4 -3
- package/dist/{chunk-3MWAQJE7.js → chunk-K5J2GGXT.js} +10 -4
- package/dist/{chunk-DX7CZTBB.js → chunk-RQGMYLVH.js} +11 -10
- package/dist/{chunk-U7GK73CK.js → chunk-RY7NCJXH.js} +19 -18
- package/dist/{chunk-CLN4Z5E3.js → chunk-VEZFR7M7.js} +6 -3
- package/dist/cli.js +132 -119
- package/dist/{config-YUNKPCNB.js → config-CGYYFECG.js} +2 -2
- package/dist/{integrationCli-3CGHHTM2.js → integrationCli-RQO3HHQE.js} +31 -30
- package/dist/{login-N2CJC6RU.js → login-O2BQX6LZ.js} +1 -1
- package/dist/{mcpCli-DZWQPTOS.js → mcpCli-QJE7P76I.js} +11 -10
- package/dist/providerCli-3FJAUH7C.js +12 -0
- package/dist/{ui-5BJA3UXH.js → ui-MESB34TF.js} +655 -246
- package/package.json +1 -1
- package/dist/args-SKWUZOJD.js +0 -12
- package/dist/chunk-2MGINW4O.js +0 -114
- package/dist/providerCli-Q7LRM2NP.js +0 -12
package/dist/cli.js
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
loadSkills,
|
|
9
9
|
parseFrontmatter,
|
|
10
10
|
runPrint
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-K5J2GGXT.js";
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
helpText,
|
|
14
14
|
parseCliArgs
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-6AVRFRFU.js";
|
|
16
16
|
import {
|
|
17
17
|
Permissions
|
|
18
18
|
} from "./chunk-ELML4KVQ.js";
|
|
@@ -20,14 +20,15 @@ import {
|
|
|
20
20
|
addProviderKey,
|
|
21
21
|
createProvider,
|
|
22
22
|
listAllModels
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-RY7NCJXH.js";
|
|
24
24
|
import {
|
|
25
|
-
providerName
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
providerName,
|
|
26
|
+
readGlobalConfigFile
|
|
27
|
+
} from "./chunk-D7CF42EW.js";
|
|
28
|
+
import "./chunk-VEZFR7M7.js";
|
|
28
29
|
import {
|
|
29
30
|
runLogin
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-4KMOCORM.js";
|
|
31
32
|
import {
|
|
32
33
|
Session,
|
|
33
34
|
pruneSessions
|
|
@@ -36,8 +37,11 @@ import {
|
|
|
36
37
|
ConfigError,
|
|
37
38
|
bccliHome,
|
|
38
39
|
loadConfig,
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
resolveLanguage,
|
|
41
|
+
resolveModel,
|
|
42
|
+
setLanguage,
|
|
43
|
+
t
|
|
44
|
+
} from "./chunk-DDA5TJ7T.js";
|
|
41
45
|
|
|
42
46
|
// src/textToolCalls.ts
|
|
43
47
|
var PAIR = /(?:<arg_key>\s*|`)?([A-Za-z_]\w*)(?:\s*<\/arg_key>)?`?\s*(?:=\s*`|<arg_value>)([\s\S]*?)<\/arg_value>/g;
|
|
@@ -56,17 +60,17 @@ function coerce(value, type) {
|
|
|
56
60
|
return value.replace(/^\n+|\n+$/g, "");
|
|
57
61
|
}
|
|
58
62
|
function pickTool(name, keys, tools) {
|
|
59
|
-
const named = name && tools.find((
|
|
63
|
+
const named = name && tools.find((t2) => t2.function.name === name);
|
|
60
64
|
if (named) return named;
|
|
61
65
|
let best;
|
|
62
66
|
let bestScore = 0;
|
|
63
67
|
let tie = false;
|
|
64
|
-
for (const
|
|
65
|
-
const params =
|
|
68
|
+
for (const t2 of tools) {
|
|
69
|
+
const params = t2.function.parameters;
|
|
66
70
|
const props = Object.keys(params.properties ?? {});
|
|
67
71
|
if (!(params.required ?? []).every((r) => keys.includes(r))) continue;
|
|
68
72
|
const score = keys.filter((k) => props.includes(k)).length;
|
|
69
|
-
if (score > bestScore) [best, bestScore, tie] = [
|
|
73
|
+
if (score > bestScore) [best, bestScore, tie] = [t2, score, false];
|
|
70
74
|
else if (score === bestScore && score > 0) tie = true;
|
|
71
75
|
}
|
|
72
76
|
return tie ? void 0 : best;
|
|
@@ -202,7 +206,7 @@ function runCommand(command, opts) {
|
|
|
202
206
|
clearTimeout(timer);
|
|
203
207
|
opts.signal.removeEventListener("abort", onAbort);
|
|
204
208
|
const output = dropped ? `${head}
|
|
205
|
-
\u2026 [${dropped}
|
|
209
|
+
\u2026 [${dropped} characters truncated] \u2026
|
|
206
210
|
${tail}` : head + tail;
|
|
207
211
|
resolve2({ output: output + extra, exitCode, timedOut, aborted });
|
|
208
212
|
};
|
|
@@ -221,7 +225,7 @@ var bashTool = defineTool({
|
|
|
221
225
|
target: (input) => input.command,
|
|
222
226
|
async run(input, ctx) {
|
|
223
227
|
const r = await runCommand(input.command, { cwd: ctx.cwd, timeoutMs: input.timeout_ms ?? 12e4, signal: ctx.signal });
|
|
224
|
-
const status = r.timedOut ? `[
|
|
228
|
+
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}]`;
|
|
225
229
|
return { output: `${r.output.trimEnd()}
|
|
226
230
|
${status}`.trimStart(), isError: r.exitCode !== 0 };
|
|
227
231
|
}
|
|
@@ -280,7 +284,7 @@ function countOccurrences(haystack, needle) {
|
|
|
280
284
|
}
|
|
281
285
|
function applyEdit(content, input) {
|
|
282
286
|
if (input.old_string === input.new_string) {
|
|
283
|
-
return { output: "old_string
|
|
287
|
+
return { output: "old_string and new_string are identical; nothing to change.", isError: true };
|
|
284
288
|
}
|
|
285
289
|
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
286
290
|
const toEol = (s) => s.replace(/\r?\n/g, eol);
|
|
@@ -291,13 +295,13 @@ function applyEdit(content, input) {
|
|
|
291
295
|
if (count === 0) continue;
|
|
292
296
|
if (count > 1 && !input.replace_all) {
|
|
293
297
|
return {
|
|
294
|
-
output: `old_string
|
|
298
|
+
output: `old_string appears ${count} times in ${input.path}. Add more context to make it unique, or use replace_all.`,
|
|
295
299
|
isError: true
|
|
296
300
|
};
|
|
297
301
|
}
|
|
298
302
|
return input.replace_all ? content.split(oldText).join(newText) : content.replace(oldText, () => newText);
|
|
299
303
|
}
|
|
300
|
-
return { output: `old_string
|
|
304
|
+
return { output: `old_string not found in ${input.path}. Re-read the file.`, isError: true };
|
|
301
305
|
}
|
|
302
306
|
var editTool = defineTool({
|
|
303
307
|
name: "edit",
|
|
@@ -307,12 +311,12 @@ var editTool = defineTool({
|
|
|
307
311
|
target: (input) => input.path,
|
|
308
312
|
async validate(input, ctx) {
|
|
309
313
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
310
|
-
if (!ctx.readFiles.has(abs)) return `
|
|
314
|
+
if (!ctx.readFiles.has(abs)) return `Read ${input.path} with read before editing it.`;
|
|
311
315
|
let content;
|
|
312
316
|
try {
|
|
313
317
|
content = await readFile(abs, "utf8");
|
|
314
318
|
} catch (error) {
|
|
315
|
-
return `
|
|
319
|
+
return `Cannot read ${input.path}: ${errorCode(error)}`;
|
|
316
320
|
}
|
|
317
321
|
const next = applyEdit(content, input);
|
|
318
322
|
return typeof next === "string" ? void 0 : next.output;
|
|
@@ -326,19 +330,19 @@ var editTool = defineTool({
|
|
|
326
330
|
async run(input, ctx) {
|
|
327
331
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
328
332
|
if (!ctx.readFiles.has(abs)) {
|
|
329
|
-
return { output: `
|
|
333
|
+
return { output: `Read ${input.path} with read before editing it.`, isError: true };
|
|
330
334
|
}
|
|
331
335
|
let content;
|
|
332
336
|
try {
|
|
333
337
|
content = await readFile(abs, "utf8");
|
|
334
338
|
} catch (error) {
|
|
335
|
-
return { output: `
|
|
339
|
+
return { output: `Cannot read ${input.path}: ${errorCode(error)}`, isError: true };
|
|
336
340
|
}
|
|
337
341
|
const next = applyEdit(content, input);
|
|
338
342
|
if (typeof next !== "string") return next;
|
|
339
343
|
await ctx.checkpoint?.(abs);
|
|
340
344
|
await writeFile(abs, next);
|
|
341
|
-
return { output: `
|
|
345
|
+
return { output: `Edited ${input.path}.`, display: formatDiff(diffLines(content, next)) };
|
|
342
346
|
}
|
|
343
347
|
});
|
|
344
348
|
|
|
@@ -375,13 +379,13 @@ function describeFetchError(error) {
|
|
|
375
379
|
const cause = error.cause;
|
|
376
380
|
const code = cause?.code ?? "";
|
|
377
381
|
const detail = cause?.message ?? error.message;
|
|
378
|
-
if (error.name === "TimeoutError") return "
|
|
379
|
-
if (code === "ENOTFOUND" || code === "EAI_AGAIN") return `${detail} \u2014 DNS
|
|
382
|
+
if (error.name === "TimeoutError") return "no response within 30 seconds";
|
|
383
|
+
if (code === "ENOTFOUND" || code === "EAI_AGAIN") return `${detail} \u2014 DNS could not find the host (typo, offline, or blocked by DNS/ISP)`;
|
|
380
384
|
if (/CERT|SELF_SIGNED|UNABLE_TO/.test(code)) {
|
|
381
|
-
return `${detail} \u2014
|
|
385
|
+
return `${detail} \u2014 TLS certificate rejected; often caused by an antivirus or proxy that inspects HTTPS. Try running with NODE_OPTIONS=--use-system-ca`;
|
|
382
386
|
}
|
|
383
387
|
if (/ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|UND_ERR_CONNECT_TIMEOUT|UND_ERR_SOCKET/.test(code)) {
|
|
384
|
-
return `${detail} \u2014
|
|
388
|
+
return `${detail} \u2014 connection failed (firewall, proxy, or the site is blocked by the network)`;
|
|
385
389
|
}
|
|
386
390
|
return code ? `${detail} (${code})` : detail;
|
|
387
391
|
}
|
|
@@ -415,14 +419,14 @@ function pickRelevant(text, query, count = FOCUS_CHUNKS, size = FOCUS_SIZE) {
|
|
|
415
419
|
const q = [...new Set(words(query))];
|
|
416
420
|
const docs = chunks.map(words);
|
|
417
421
|
const avg = docs.reduce((n, d) => n + d.length, 0) / (docs.length || 1) || 1;
|
|
418
|
-
const idf = q.map((
|
|
419
|
-
const df = docs.filter((d) => d.includes(
|
|
422
|
+
const idf = q.map((t2) => {
|
|
423
|
+
const df = docs.filter((d) => d.includes(t2)).length;
|
|
420
424
|
return Math.log(1 + (docs.length - df + 0.5) / (df + 0.5));
|
|
421
425
|
});
|
|
422
426
|
const scored = docs.map((d, i) => ({
|
|
423
427
|
i,
|
|
424
|
-
score: q.reduce((sum,
|
|
425
|
-
const tf = d.filter((w) => w ===
|
|
428
|
+
score: q.reduce((sum, t2, k) => {
|
|
429
|
+
const tf = d.filter((w) => w === t2).length;
|
|
426
430
|
return sum + idf[k] * tf * 2.2 / (tf + 1.2 * (0.25 + 0.75 * d.length / avg));
|
|
427
431
|
}, 0)
|
|
428
432
|
})).filter((c) => c.score > 0).sort((a, b) => b.score - a.score).slice(0, count).sort((a, b) => a.i - b.i);
|
|
@@ -444,7 +448,7 @@ function recall(key) {
|
|
|
444
448
|
return hit;
|
|
445
449
|
}
|
|
446
450
|
var ACCEPT = "text/markdown, text/html;q=0.9, text/plain;q=0.8, */*;q=0.5";
|
|
447
|
-
var withCost = (text, what) => `${what} \xB7
|
|
451
|
+
var withCost = (text, what) => `${what} \xB7 ${t("~{n} tokens", { n: tokensOf(text) })}`;
|
|
448
452
|
function createFetchTool(opts = {}) {
|
|
449
453
|
const keenableURL = opts.keenableURL === void 0 ? "https://api.keenable.ai/v1/fetch/public" : opts.keenableURL;
|
|
450
454
|
const isPrivate = opts.isPrivate ?? isPrivateHost;
|
|
@@ -462,7 +466,7 @@ function createFetchTool(opts = {}) {
|
|
|
462
466
|
kind: "fetch",
|
|
463
467
|
target: (input) => input.url,
|
|
464
468
|
async run(input, ctx) {
|
|
465
|
-
if (!/^https?:\/\//i.test(input.url)) return { output: "URL
|
|
469
|
+
if (!/^https?:\/\//i.test(input.url)) return { output: "URL must start with http:// or https://", isError: true };
|
|
466
470
|
const target = new URL(input.url);
|
|
467
471
|
const prompt = input.prompt?.trim();
|
|
468
472
|
const askKeenable = !!prompt && !input.offset && !!keenableURL && !target.username && !target.password && !isPrivate(target.hostname);
|
|
@@ -473,14 +477,14 @@ ${prompt}`;
|
|
|
473
477
|
const hit = recall(key);
|
|
474
478
|
if (hit) {
|
|
475
479
|
ctx.refundFetch?.();
|
|
476
|
-
return { output: hit, display: withCost(hit, "
|
|
480
|
+
return { output: hit, display: withCost(hit, t("focused excerpt \xB7 cache")) };
|
|
477
481
|
}
|
|
478
482
|
const out = await extractWithKeenable(keenableURL, input.url, prompt, ctx.signal);
|
|
479
483
|
if (out) {
|
|
480
|
-
const output2 = `[
|
|
484
|
+
const output2 = `[Excerpt from ${input.url} for "${prompt}" (extracted by Keenable). If it says the answer is not there, try fetch without a prompt.]
|
|
481
485
|
${out}`;
|
|
482
486
|
remember(key, output2, output2.length);
|
|
483
|
-
return { output: output2, display: withCost(output2, "
|
|
487
|
+
return { output: output2, display: withCost(output2, t("focused excerpt (Keenable)")) };
|
|
484
488
|
}
|
|
485
489
|
}
|
|
486
490
|
let page = recall(`p
|
|
@@ -499,23 +503,23 @@ ${input.url}`, page, page.text.length);
|
|
|
499
503
|
if (prompt && !input.offset) {
|
|
500
504
|
const picked = pickRelevant(text, prompt);
|
|
501
505
|
if (picked) {
|
|
502
|
-
const output2 = `[
|
|
506
|
+
const output2 = `[Most relevant excerpt from ${input.url} for "${prompt}" (${text.length} characters total). Full page: fetch without a prompt.]
|
|
503
507
|
${picked}`;
|
|
504
|
-
return { output: output2, display: withCost(output2,
|
|
508
|
+
return { output: output2, display: withCost(output2, `${t("focused excerpt (local)")}${via}`) };
|
|
505
509
|
}
|
|
506
510
|
}
|
|
507
511
|
const offset = input.offset ?? 0;
|
|
508
512
|
if (offset >= text.length && text.length > 0) {
|
|
509
|
-
return { output: `offset ${offset}
|
|
513
|
+
return { output: `offset ${offset} is past the end of the page (${text.length} characters).`, isError: true };
|
|
510
514
|
}
|
|
511
515
|
const end = Math.min(offset + MAX_CHARS, text.length);
|
|
512
516
|
let output = text.slice(offset, end);
|
|
513
517
|
if (end < text.length || truncated) {
|
|
514
518
|
const total = truncated ? `${text.length}+` : text.length;
|
|
515
519
|
output += `
|
|
516
|
-
\u2026 [
|
|
520
|
+
\u2026 [truncated: characters ${offset}-${end} of ${total}. Continue with offset=${end}, or use prompt for a focused excerpt.]`;
|
|
517
521
|
}
|
|
518
|
-
const size = truncated ? "
|
|
522
|
+
const size = truncated ? t("over 5 MB, truncated") : t("{n} characters", { n: text.length });
|
|
519
523
|
return { output, display: withCost(output, `${size}${via}`) };
|
|
520
524
|
}
|
|
521
525
|
});
|
|
@@ -546,19 +550,19 @@ async function loadPage(inputUrl, signal) {
|
|
|
546
550
|
const next = new URL(location, url);
|
|
547
551
|
if (next.host !== url.host) {
|
|
548
552
|
await res.body?.cancel();
|
|
549
|
-
return { error: `Redirect
|
|
553
|
+
return { error: `Redirect to another host: ${next.href}. Call fetch again with that URL if needed (permission will be requested).` };
|
|
550
554
|
}
|
|
551
555
|
await res.body?.cancel();
|
|
552
556
|
url = next;
|
|
553
557
|
}
|
|
554
558
|
} catch (error) {
|
|
555
|
-
return { error: `
|
|
559
|
+
return { error: `Failed to fetch ${inputUrl}: ${describeFetchError(error)}` };
|
|
556
560
|
}
|
|
557
|
-
if (!res) return { error: `
|
|
561
|
+
if (!res) return { error: `Failed to fetch ${inputUrl}` };
|
|
558
562
|
const { text: body, truncated } = await readCapped(res);
|
|
559
563
|
const type = res.headers.get("content-type") ?? "";
|
|
560
564
|
const text = type.includes("html") ? htmlToText(body) : body;
|
|
561
|
-
if (!res.ok) return { error: `HTTP ${res.status}
|
|
565
|
+
if (!res.ok) return { error: `HTTP ${res.status} from ${inputUrl}: ${text.slice(0, 500)}` };
|
|
562
566
|
return { text, truncated, at: Date.now() };
|
|
563
567
|
}
|
|
564
568
|
var fetchTool = createFetchTool();
|
|
@@ -578,10 +582,10 @@ var globTool = defineTool({
|
|
|
578
582
|
async run(input, ctx) {
|
|
579
583
|
const root = resolvePath(ctx.cwd, input.path ?? ".");
|
|
580
584
|
const files = (await fg(input.pattern, { cwd: root, ignore: ignorePatterns(root), onlyFiles: true, dot: true })).sort();
|
|
581
|
-
if (!files.length) return { output: "
|
|
585
|
+
if (!files.length) return { output: "No matching files." };
|
|
582
586
|
const shown = files.slice(0, 500);
|
|
583
587
|
const more = files.length > shown.length ? `
|
|
584
|
-
\u2026 ${files.length - shown.length}
|
|
588
|
+
\u2026 ${files.length - shown.length} more files` : "";
|
|
585
589
|
return { output: shown.join("\n") + more, display: `${files.length} file` };
|
|
586
590
|
}
|
|
587
591
|
});
|
|
@@ -643,11 +647,11 @@ var grepTool = defineTool({
|
|
|
643
647
|
try {
|
|
644
648
|
new RegExp(input.pattern);
|
|
645
649
|
} catch (error) {
|
|
646
|
-
return { output: `
|
|
650
|
+
return { output: `Invalid regex: ${error.message}`, isError: true };
|
|
647
651
|
}
|
|
648
652
|
const matches = await grepRg(input.pattern, opts) ?? await grepJs(input.pattern, opts);
|
|
649
|
-
if (!matches.length) return { output: "
|
|
650
|
-
return { output: matches.join("\n"), display:
|
|
653
|
+
if (!matches.length) return { output: "No matches." };
|
|
654
|
+
return { output: matches.join("\n"), display: t("{n} results", { n: matches.length }) };
|
|
651
655
|
}
|
|
652
656
|
});
|
|
653
657
|
|
|
@@ -671,25 +675,25 @@ var readTool = defineTool({
|
|
|
671
675
|
try {
|
|
672
676
|
buffer = await readFile3(abs);
|
|
673
677
|
} catch (error) {
|
|
674
|
-
return { output: `
|
|
678
|
+
return { output: `Cannot read ${input.path}: ${errorCode(error)}`, isError: true };
|
|
675
679
|
}
|
|
676
680
|
if (buffer.subarray(0, 8e3).includes(0)) {
|
|
677
|
-
return { output: `${input.path}
|
|
681
|
+
return { output: `${input.path} is a binary file; not read.`, isError: true };
|
|
678
682
|
}
|
|
679
683
|
const lines = buffer.toString("utf8").split(/\r?\n/);
|
|
680
684
|
const start = (input.offset ?? 1) - 1;
|
|
681
685
|
const limit = input.limit ?? 2e3;
|
|
682
686
|
const slice = lines.slice(start, start + limit);
|
|
683
687
|
const body = slice.map((line, i) => {
|
|
684
|
-
const text = line.length > MAX_LINE ? `${line.slice(0, MAX_LINE)}\u2026 [
|
|
688
|
+
const text = line.length > MAX_LINE ? `${line.slice(0, MAX_LINE)}\u2026 [line truncated]` : line;
|
|
685
689
|
return `${String(start + i + 1).padStart(6)} ${text}`;
|
|
686
690
|
}).join("\n");
|
|
687
691
|
const remaining = lines.length - start - slice.length;
|
|
688
692
|
ctx.readFiles.add(abs);
|
|
689
693
|
return {
|
|
690
694
|
output: remaining > 0 ? `${body}
|
|
691
|
-
\u2026 ${remaining}
|
|
692
|
-
display:
|
|
695
|
+
\u2026 ${remaining} more lines (use offset)` : body,
|
|
696
|
+
display: t("{n} lines", { n: slice.length })
|
|
693
697
|
};
|
|
694
698
|
}
|
|
695
699
|
});
|
|
@@ -710,7 +714,7 @@ var writeTool = defineTool({
|
|
|
710
714
|
target: (input) => input.path,
|
|
711
715
|
async validate(input, ctx) {
|
|
712
716
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
713
|
-
return existsSync(abs) && !ctx.readFiles.has(abs) ? `${input.path}
|
|
717
|
+
return existsSync(abs) && !ctx.readFiles.has(abs) ? `${input.path} already exists. Read it with read before overwriting it.` : void 0;
|
|
714
718
|
},
|
|
715
719
|
async preview(input, ctx) {
|
|
716
720
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
@@ -720,18 +724,18 @@ var writeTool = defineTool({
|
|
|
720
724
|
async run(input, ctx) {
|
|
721
725
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
722
726
|
if (existsSync(abs) && !ctx.readFiles.has(abs)) {
|
|
723
|
-
return { output: `${input.path}
|
|
727
|
+
return { output: `${input.path} already exists. Read it with read before overwriting it.`, isError: true };
|
|
724
728
|
}
|
|
725
729
|
try {
|
|
726
730
|
await ctx.checkpoint?.(abs);
|
|
727
731
|
await mkdir(dirname(abs), { recursive: true });
|
|
728
732
|
await writeFile2(abs, input.content);
|
|
729
733
|
} catch (error) {
|
|
730
|
-
return { output: `
|
|
734
|
+
return { output: `Failed to write ${input.path}: ${errorCode(error)}`, isError: true };
|
|
731
735
|
}
|
|
732
736
|
ctx.readFiles.add(abs);
|
|
733
737
|
const lines = input.content.split("\n").length;
|
|
734
|
-
return { output: `
|
|
738
|
+
return { output: `Wrote ${input.path} (${lines} lines).`, display: t("{lines} lines written", { lines }) };
|
|
735
739
|
}
|
|
736
740
|
});
|
|
737
741
|
|
|
@@ -747,7 +751,7 @@ function toolDefinitions(tools) {
|
|
|
747
751
|
// src/webBudget.ts
|
|
748
752
|
var KEEP_TOKENS = 4e4;
|
|
749
753
|
var PRUNE_MIN_TOKENS = 2e4;
|
|
750
|
-
var STUB = "[
|
|
754
|
+
var STUB = "[old tool result removed:";
|
|
751
755
|
var tokens = (text) => Math.ceil(text.length / 4);
|
|
752
756
|
var isStub = (content) => content.startsWith(STUB);
|
|
753
757
|
function pruneOldFetches(messages) {
|
|
@@ -778,7 +782,7 @@ function pruneOldFetches(messages) {
|
|
|
778
782
|
if (oldTokens <= PRUNE_MIN_TOKENS) return false;
|
|
779
783
|
for (const i of old) {
|
|
780
784
|
const m = messages[i];
|
|
781
|
-
messages[i] = { ...m, content: `${STUB} fetch ${urls.get(m.tool_call_id)}.
|
|
785
|
+
messages[i] = { ...m, content: `${STUB} fetch ${urls.get(m.tool_call_id)}. Fetch it again (use prompt for a focused excerpt) if still needed.]` };
|
|
782
786
|
}
|
|
783
787
|
return true;
|
|
784
788
|
}
|
|
@@ -805,10 +809,10 @@ var WebBudget = class {
|
|
|
805
809
|
/** Reserves one fetch; returns the refusal to show the model when over budget. */
|
|
806
810
|
take() {
|
|
807
811
|
if (this.fetches >= this.perTurn) {
|
|
808
|
-
return `
|
|
812
|
+
return `Limit of ${this.perTurn} fetches per question reached (each fetch uses the user's tokens). Answer from the results you already have; if that is not enough, tell the user what is still missing.`;
|
|
809
813
|
}
|
|
810
814
|
if (this.chars >= this.sessionChars) {
|
|
811
|
-
return `
|
|
815
|
+
return `Total web page limit for this session reached (~${Math.round(this.sessionChars / 4e3)}k tokens). Answer from the results you already have and ask the user whether to search more.`;
|
|
812
816
|
}
|
|
813
817
|
this.fetches++;
|
|
814
818
|
return void 0;
|
|
@@ -865,7 +869,7 @@ var Agent = class {
|
|
|
865
869
|
this.definitions = toolDefinitions(tools);
|
|
866
870
|
}
|
|
867
871
|
isParallelSafe(call) {
|
|
868
|
-
const tool = this.turnTools.find((
|
|
872
|
+
const tool = this.turnTools.find((t2) => t2.name === call.name);
|
|
869
873
|
if (!tool?.parallelSafe) return false;
|
|
870
874
|
try {
|
|
871
875
|
const parsed = tool.schema.safeParse(JSON.parse(call.arguments || "{}"));
|
|
@@ -901,9 +905,9 @@ var Agent = class {
|
|
|
901
905
|
reasoning: this.reasoning
|
|
902
906
|
});
|
|
903
907
|
this.clear();
|
|
904
|
-
this.push({ role: "user", content: `
|
|
908
|
+
this.push({ role: "user", content: `Summary of the previous conversation:
|
|
905
909
|
${completion.text}` });
|
|
906
|
-
this.push({ role: "assistant", content: "
|
|
910
|
+
this.push({ role: "assistant", content: "OK, I will continue from this summary." });
|
|
907
911
|
this.onEvent({ type: "compacted" });
|
|
908
912
|
}
|
|
909
913
|
async run(text, signal) {
|
|
@@ -917,7 +921,7 @@ ${completion.text}` });
|
|
|
917
921
|
for (let step = 0; step < this.maxSteps; step++) {
|
|
918
922
|
if (step > 0 && this.lastInputTokens > this.contextWindow * 0.8) {
|
|
919
923
|
await this.compact(signal);
|
|
920
|
-
this.push({ role: "user", content: `
|
|
924
|
+
this.push({ role: "user", content: `Continue this task using the summary above: ${text}` });
|
|
921
925
|
}
|
|
922
926
|
pruneOldFetches(this.messages);
|
|
923
927
|
let completion = await this.provider.chat({
|
|
@@ -958,7 +962,7 @@ ${completion.text}` });
|
|
|
958
962
|
this.onEvent({ type: "textReplace", text: completion.text });
|
|
959
963
|
this.onEvent({
|
|
960
964
|
type: "error",
|
|
961
|
-
message: "
|
|
965
|
+
message: t("The model got stuck repeating text, so the answer was stopped. Try again or switch models with /model.")
|
|
962
966
|
});
|
|
963
967
|
return;
|
|
964
968
|
}
|
|
@@ -970,7 +974,7 @@ ${completion.text}` });
|
|
|
970
974
|
let i = 0;
|
|
971
975
|
while (i < calls.length) {
|
|
972
976
|
if (signal.aborted) {
|
|
973
|
-
for (const pending of calls.slice(i)) this.push({ role: "tool", tool_call_id: pending.id, content: "
|
|
977
|
+
for (const pending of calls.slice(i)) this.push({ role: "tool", tool_call_id: pending.id, content: "Cancelled by the user." });
|
|
974
978
|
this.onEvent({ type: "aborted" });
|
|
975
979
|
return;
|
|
976
980
|
}
|
|
@@ -999,7 +1003,7 @@ ${completion.text}` });
|
|
|
999
1003
|
this.onEvent({
|
|
1000
1004
|
type: "error",
|
|
1001
1005
|
message: noTools ? `${message}
|
|
1002
|
-
|
|
1006
|
+
${t("This model may not support tool calling. Try another model with /model.")}` : message
|
|
1003
1007
|
});
|
|
1004
1008
|
}
|
|
1005
1009
|
}
|
|
@@ -1009,17 +1013,17 @@ Model ini sepertinya tidak mendukung tool calling. Coba model lain dengan /model
|
|
|
1009
1013
|
this.onEvent({ type: "toolEnd", id: call.id, tool: call.name, output, isError: true });
|
|
1010
1014
|
return output;
|
|
1011
1015
|
};
|
|
1012
|
-
const tool = this.turnTools.find((
|
|
1013
|
-
if (!tool) return fail(`
|
|
1016
|
+
const tool = this.turnTools.find((t2) => t2.name === call.name);
|
|
1017
|
+
if (!tool) return fail(`Tool "${call.name}" does not exist. Available tools: ${this.turnTools.map((t2) => t2.name).join(", ")}`);
|
|
1014
1018
|
let args;
|
|
1015
1019
|
try {
|
|
1016
1020
|
args = JSON.parse(call.arguments || "{}");
|
|
1017
1021
|
} catch {
|
|
1018
|
-
return fail(`
|
|
1022
|
+
return fail(`Arguments are not valid JSON: ${call.arguments.slice(0, 200)}`);
|
|
1019
1023
|
}
|
|
1020
1024
|
const parsed = tool.schema.safeParse(args);
|
|
1021
1025
|
if (!parsed.success) {
|
|
1022
|
-
return fail(`
|
|
1026
|
+
return fail(`Invalid arguments: ${parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
1023
1027
|
}
|
|
1024
1028
|
const input = parsed.data;
|
|
1025
1029
|
const target = tool.target(input);
|
|
@@ -1061,7 +1065,7 @@ Model ini sepertinya tidak mendukung tool calling. Coba model lain dengan /model
|
|
|
1061
1065
|
decision = answer === "no" ? "deny" : "allow";
|
|
1062
1066
|
}
|
|
1063
1067
|
if (decision === "deny") {
|
|
1064
|
-
const output = this.permissions.mode === "plan" ? "
|
|
1068
|
+
const output = this.permissions.mode === "plan" ? "Denied: plan mode only allows reading and searching. Write the plan for the user without changing anything." : "The user declined to run this tool. Ask the user what they want, or try another approach.";
|
|
1065
1069
|
this.onEvent({ type: "toolEnd", id: call.id, tool: tool.name, output, isError: true });
|
|
1066
1070
|
return output;
|
|
1067
1071
|
}
|
|
@@ -1101,7 +1105,7 @@ var CheckpointStore = class {
|
|
|
1101
1105
|
while (this.turns() > MAX_TURNS) this.history.shift();
|
|
1102
1106
|
}
|
|
1103
1107
|
turns() {
|
|
1104
|
-
return this.history.filter((
|
|
1108
|
+
return this.history.filter((t2) => t2.size).length;
|
|
1105
1109
|
}
|
|
1106
1110
|
async undo() {
|
|
1107
1111
|
while (this.history.length && !this.history.at(-1)?.size) this.history.pop();
|
|
@@ -1147,7 +1151,7 @@ function mcpToolName(server, tool, taken) {
|
|
|
1147
1151
|
function withTimeout(promise, ms) {
|
|
1148
1152
|
let timer;
|
|
1149
1153
|
const timeout = new Promise((_, reject) => {
|
|
1150
|
-
timer = setTimeout(() => reject(new Error(
|
|
1154
|
+
timer = setTimeout(() => reject(new Error(t("timeout after {n} seconds", { n: Math.round(ms / 1e3) }))), ms);
|
|
1151
1155
|
});
|
|
1152
1156
|
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
1153
1157
|
}
|
|
@@ -1184,7 +1188,7 @@ var McpManager = class {
|
|
|
1184
1188
|
});
|
|
1185
1189
|
return;
|
|
1186
1190
|
}
|
|
1187
|
-
entry.tools = tools.map((
|
|
1191
|
+
entry.tools = tools.map((t2) => this.wrap(spec.name, client, t2));
|
|
1188
1192
|
entry.state = { ...entry.state, status: "ready", tools: entry.tools.length };
|
|
1189
1193
|
} catch (error) {
|
|
1190
1194
|
entry.state = { ...entry.state, status: "error", error: error.message };
|
|
@@ -1208,9 +1212,9 @@ var McpManager = class {
|
|
|
1208
1212
|
async run(input, ctx) {
|
|
1209
1213
|
try {
|
|
1210
1214
|
const result = await client.callTool({ name: tool.name, arguments: input }, void 0, { signal: ctx.signal });
|
|
1211
|
-
const output = (result.content ?? []).map((c) => c.type === "text" ? c.text ?? "" : `[${c.type}]`).join("\n") || "(
|
|
1215
|
+
const output = (result.content ?? []).map((c) => c.type === "text" ? c.text ?? "" : `[${c.type}]`).join("\n") || "(empty)";
|
|
1212
1216
|
return { output: output.length > 5e4 ? `${output.slice(0, 5e4)}
|
|
1213
|
-
\u2026 [
|
|
1217
|
+
\u2026 [truncated]` : output, isError: !!result.isError };
|
|
1214
1218
|
} catch (error) {
|
|
1215
1219
|
return { output: `Server MCP ${server} error: ${error.message}`, isError: true };
|
|
1216
1220
|
}
|
|
@@ -1221,8 +1225,8 @@ var McpManager = class {
|
|
|
1221
1225
|
const entry = this.servers.get(name);
|
|
1222
1226
|
if (!entry) return;
|
|
1223
1227
|
this.servers.delete(name);
|
|
1224
|
-
for (const
|
|
1225
|
-
if (entry.tools.length) this.opts.onToolsRemoved?.(entry.tools.map((
|
|
1228
|
+
for (const t2 of entry.tools) this.taken.delete(t2.name);
|
|
1229
|
+
if (entry.tools.length) this.opts.onToolsRemoved?.(entry.tools.map((t2) => t2.name));
|
|
1226
1230
|
await entry.client?.close().catch(() => {
|
|
1227
1231
|
});
|
|
1228
1232
|
this.opts.onChange?.();
|
|
@@ -1249,15 +1253,15 @@ function createExitPlanTool(opts) {
|
|
|
1249
1253
|
description: "Plan mode only: present the finished plan to the user for approval. If approved you may start implementing it.",
|
|
1250
1254
|
schema: z10.object({ plan: z10.string().describe("The plan, in markdown") }),
|
|
1251
1255
|
kind: "read",
|
|
1252
|
-
target: () => "
|
|
1256
|
+
target: () => t("plan"),
|
|
1253
1257
|
async run(input) {
|
|
1254
|
-
if (opts.permissions.mode !== "plan") return { output: "exit_plan
|
|
1258
|
+
if (opts.permissions.mode !== "plan") return { output: "exit_plan is only used in plan mode.", isError: true };
|
|
1255
1259
|
const decision = await opts.interaction.approvePlan(input.plan);
|
|
1256
1260
|
if (decision === "no") {
|
|
1257
|
-
return { output: "
|
|
1261
|
+
return { output: "The user has not approved yet. Ask what needs to change, revise the plan, then call exit_plan again." };
|
|
1258
1262
|
}
|
|
1259
1263
|
opts.permissions.mode = decision;
|
|
1260
|
-
return { output: `
|
|
1264
|
+
return { output: `Plan approved. The mode is now ${decision}. Start carrying out the plan now.` };
|
|
1261
1265
|
}
|
|
1262
1266
|
});
|
|
1263
1267
|
}
|
|
@@ -1274,7 +1278,7 @@ function createSkillTool(skills) {
|
|
|
1274
1278
|
target: (input) => input.name,
|
|
1275
1279
|
async run(input) {
|
|
1276
1280
|
const skill = skills.find((s) => s.name === input.name);
|
|
1277
|
-
if (!skill) return { output: `Skill "${input.name}"
|
|
1281
|
+
if (!skill) return { output: `Skill "${input.name}" does not exist. Available: ${skills.map((s) => s.name).join(", ") || "(none)"}`, isError: true };
|
|
1278
1282
|
const { body } = parseFrontmatter(readFileSync(skill.file, "utf8"));
|
|
1279
1283
|
return { output: `Base directory for this skill: ${skill.dir}
|
|
1280
1284
|
|
|
@@ -1334,12 +1338,12 @@ function createWebSearchTool(opts) {
|
|
|
1334
1338
|
}
|
|
1335
1339
|
}
|
|
1336
1340
|
if (!results.length) {
|
|
1337
|
-
return { output: errors.length ? `Web search
|
|
1341
|
+
return { output: errors.length ? `Web search failed (${errors.join("; ")}).` : "No results.", isError: errors.length > 0 };
|
|
1338
1342
|
}
|
|
1339
1343
|
const output = results.map((r, i) => `${i + 1}. ${r.title}
|
|
1340
1344
|
${r.url}${r.snippet ? `
|
|
1341
1345
|
${r.snippet}` : ""}`).join("\n");
|
|
1342
|
-
return { output, display:
|
|
1346
|
+
return { output, display: t("{n} results", { n: results.length }) };
|
|
1343
1347
|
}
|
|
1344
1348
|
});
|
|
1345
1349
|
}
|
|
@@ -1365,16 +1369,16 @@ ${list}`,
|
|
|
1365
1369
|
const allowed = byName.get(input.agent)?.tools;
|
|
1366
1370
|
if (!allowed) return false;
|
|
1367
1371
|
const base = opts.baseTools();
|
|
1368
|
-
return allowed.every((name) => base.find((
|
|
1372
|
+
return allowed.every((name) => base.find((t2) => t2.name === name)?.kind === "read");
|
|
1369
1373
|
},
|
|
1370
1374
|
async run(input, ctx) {
|
|
1371
1375
|
const def = byName.get(input.agent);
|
|
1372
|
-
if (!def) return { output: `Agent "${input.agent}"
|
|
1373
|
-
const base = opts.baseTools().filter((
|
|
1374
|
-
const unknown = (def.tools ?? []).filter((n) => !base.some((
|
|
1375
|
-
if (unknown.length) return { output: `Agent "${def.name}":
|
|
1376
|
+
if (!def) return { output: `Agent "${input.agent}" does not exist. Available: ${[...byName.keys()].join(", ")}`, isError: true };
|
|
1377
|
+
const base = opts.baseTools().filter((t2) => t2.name !== "task" && t2.name !== "exit_plan");
|
|
1378
|
+
const unknown = (def.tools ?? []).filter((n) => !base.some((t2) => t2.name === n));
|
|
1379
|
+
if (unknown.length) return { output: `Agent "${def.name}": unknown tools: ${unknown.join(", ")}`, isError: true };
|
|
1376
1380
|
const allowed = def.tools;
|
|
1377
|
-
const tools = allowed ? base.filter((
|
|
1381
|
+
const tools = allowed ? base.filter((t2) => allowed.includes(t2.name)) : base;
|
|
1378
1382
|
let provider;
|
|
1379
1383
|
try {
|
|
1380
1384
|
provider = def.model ? opts.providerFor(def.model) : opts.provider();
|
|
@@ -1407,14 +1411,14 @@ ${def.prompt}`,
|
|
|
1407
1411
|
await child.run(input.prompt, ctx.signal);
|
|
1408
1412
|
ctx.addUsage?.(child.totalUsage);
|
|
1409
1413
|
const tokens2 = child.totalUsage.inputTokens + child.totalUsage.outputTokens;
|
|
1410
|
-
const display =
|
|
1411
|
-
if (outcome?.type === "error") return { output: `Subagent ${def.name}
|
|
1412
|
-
if (outcome?.type === "aborted") return { output: `Subagent ${def.name}
|
|
1414
|
+
const display = t("{steps} steps \xB7 {tokens} tokens", { steps, tokens: tokens2 >= 1e3 ? `${Math.round(tokens2 / 1e3)}k` : tokens2 });
|
|
1415
|
+
if (outcome?.type === "error") return { output: `Subagent ${def.name} failed: ${outcome.message}`, isError: true, display };
|
|
1416
|
+
if (outcome?.type === "aborted") return { output: `Subagent ${def.name} was cancelled.`, isError: true, display };
|
|
1413
1417
|
const last = [...child.messages].reverse().find((m) => m.role === "assistant" && m.content);
|
|
1414
|
-
const report = last && typeof last.content === "string" ? last.content : "(
|
|
1418
|
+
const report = last && typeof last.content === "string" ? last.content : "(no report)";
|
|
1415
1419
|
const suffix = outcome?.type === "stepLimit" ? `
|
|
1416
1420
|
|
|
1417
|
-
(
|
|
1421
|
+
(The subagent stopped at its ${def.maxSteps ?? 50}-step limit.)` : "";
|
|
1418
1422
|
return { output: report + suffix, display };
|
|
1419
1423
|
}
|
|
1420
1424
|
});
|
|
@@ -1444,12 +1448,12 @@ function createTodoTool(store) {
|
|
|
1444
1448
|
kind: "read",
|
|
1445
1449
|
target: (input) => `${input.todos.length} item`,
|
|
1446
1450
|
async run(input) {
|
|
1447
|
-
if (input.todos.filter((
|
|
1448
|
-
return { output: "
|
|
1451
|
+
if (input.todos.filter((t2) => t2.status === "in_progress").length > 1) {
|
|
1452
|
+
return { output: "Only one item may be in_progress.", isError: true };
|
|
1449
1453
|
}
|
|
1450
1454
|
store.set(input.todos);
|
|
1451
|
-
const done = input.todos.filter((
|
|
1452
|
-
return { output: `Todo
|
|
1455
|
+
const done = input.todos.filter((t2) => t2.status === "completed").length;
|
|
1456
|
+
return { output: `Todo updated: ${done}/${input.todos.length} completed.` };
|
|
1453
1457
|
}
|
|
1454
1458
|
});
|
|
1455
1459
|
}
|
|
@@ -1468,7 +1472,7 @@ function createRuntime(opts) {
|
|
|
1468
1472
|
};
|
|
1469
1473
|
const provider = makeProvider(modelRef);
|
|
1470
1474
|
const mode = opts.args.allowAll ? "allowAll" : opts.args.permissionMode ?? config.permissionMode;
|
|
1471
|
-
const rules = [...config.allow, ...opts.args.allowedTools.map((
|
|
1475
|
+
const rules = [...config.allow, ...opts.args.allowedTools.map((t2) => TOOL_RULES[t2] ?? t2)];
|
|
1472
1476
|
const permissions = new Permissions(mode, rules, opts.cwd);
|
|
1473
1477
|
const roots = { cwd: opts.cwd, home, userHome: opts.userHome ?? homedir() };
|
|
1474
1478
|
const skills = loadSkills(roots);
|
|
@@ -1502,7 +1506,7 @@ function createRuntime(opts) {
|
|
|
1502
1506
|
const task = createTaskTool({
|
|
1503
1507
|
agents: [...BUILTIN_AGENTS, ...agentDefs],
|
|
1504
1508
|
// Subagents get whatever the main agent has right now (incl. MCP tools), minus task itself.
|
|
1505
|
-
baseTools: () => agent.tools.filter((
|
|
1509
|
+
baseTools: () => agent.tools.filter((t2) => t2.name !== "task"),
|
|
1506
1510
|
permissions,
|
|
1507
1511
|
provider: () => agent.provider,
|
|
1508
1512
|
providerFor: makeProvider,
|
|
@@ -1600,33 +1604,42 @@ function createRuntime(opts) {
|
|
|
1600
1604
|
}
|
|
1601
1605
|
|
|
1602
1606
|
// src/version.ts
|
|
1603
|
-
var VERSION = true ? "0.4.0-beta.
|
|
1607
|
+
var VERSION = true ? "0.4.0-beta.16" : "0.0.0-dev";
|
|
1604
1608
|
|
|
1605
1609
|
// src/cli.ts
|
|
1610
|
+
function chooseLanguage(argv) {
|
|
1611
|
+
let fromConfig;
|
|
1612
|
+
try {
|
|
1613
|
+
fromConfig = readGlobalConfigFile(process.env).language;
|
|
1614
|
+
} catch {
|
|
1615
|
+
}
|
|
1616
|
+
setLanguage(resolveLanguage(argv, process.env, fromConfig));
|
|
1617
|
+
}
|
|
1606
1618
|
async function main() {
|
|
1619
|
+
chooseLanguage(process.argv.slice(2));
|
|
1607
1620
|
const args = parseCliArgs(process.argv.slice(2));
|
|
1608
1621
|
if (args.version) {
|
|
1609
1622
|
console.log(VERSION);
|
|
1610
1623
|
return 0;
|
|
1611
1624
|
}
|
|
1612
1625
|
if (args.help) {
|
|
1613
|
-
console.log(
|
|
1626
|
+
console.log(helpText());
|
|
1614
1627
|
return 0;
|
|
1615
1628
|
}
|
|
1616
1629
|
const cwd = process.cwd();
|
|
1617
1630
|
if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
|
|
1618
1631
|
if (args.command === "mcp") {
|
|
1619
|
-
const { runMcpCommand } = await import("./mcpCli-
|
|
1620
|
-
const { readSecret } = await import("./login-
|
|
1632
|
+
const { runMcpCommand } = await import("./mcpCli-QJE7P76I.js");
|
|
1633
|
+
const { readSecret } = await import("./login-O2BQX6LZ.js");
|
|
1621
1634
|
return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1622
1635
|
}
|
|
1623
1636
|
if (args.command === "provider") {
|
|
1624
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
1625
|
-
const { readSecret } = await import("./login-
|
|
1637
|
+
const { runProviderCommand } = await import("./providerCli-3FJAUH7C.js");
|
|
1638
|
+
const { readSecret } = await import("./login-O2BQX6LZ.js");
|
|
1626
1639
|
return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1627
1640
|
}
|
|
1628
1641
|
if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
|
|
1629
|
-
const { runIntegrationCommand } = await import("./integrationCli-
|
|
1642
|
+
const { runIntegrationCommand } = await import("./integrationCli-RQO3HHQE.js");
|
|
1630
1643
|
return runIntegrationCommand(args, {
|
|
1631
1644
|
env: process.env,
|
|
1632
1645
|
cwd,
|
|
@@ -1648,11 +1661,11 @@ async function main() {
|
|
|
1648
1661
|
} catch {
|
|
1649
1662
|
}
|
|
1650
1663
|
if (args.print) {
|
|
1651
|
-
if (!args.prompt) throw new ConfigError('
|
|
1652
|
-
const { serversToStart } = await import("./config-
|
|
1664
|
+
if (!args.prompt) throw new ConfigError(t('-p mode needs a task, e.g. bccli -p "explain this repo"'));
|
|
1665
|
+
const { serversToStart } = await import("./config-CGYYFECG.js");
|
|
1653
1666
|
const plan = serversToStart(rt.home, cwd);
|
|
1654
1667
|
for (const s of plan.needTrust) {
|
|
1655
|
-
console.error(
|
|
1668
|
+
console.error(t('Project MCP server "{name}" skipped (not approved yet; run interactive bccli once to approve it).', { name: s.name }));
|
|
1656
1669
|
}
|
|
1657
1670
|
await rt.startMcp(plan.start);
|
|
1658
1671
|
try {
|
|
@@ -1661,8 +1674,8 @@ async function main() {
|
|
|
1661
1674
|
await rt.mcp.stop();
|
|
1662
1675
|
}
|
|
1663
1676
|
}
|
|
1664
|
-
if (!process.stdin.isTTY) throw new ConfigError('
|
|
1665
|
-
const { startInteractive } = await import("./ui-
|
|
1677
|
+
if (!process.stdin.isTTY) throw new ConfigError(t('Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"'));
|
|
1678
|
+
const { startInteractive } = await import("./ui-MESB34TF.js");
|
|
1666
1679
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
|
|
1667
1680
|
}
|
|
1668
1681
|
main().then(
|