@botconnector/bccli 0.4.0-beta.13 → 0.4.0-beta.15
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-KV27KTOX.js → chunk-K5J2GGXT.js} +11 -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 +141 -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-JD5YWGPE.js → ui-HVH3TR3I.js} +218 -192
- 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);
|
|
@@ -471,18 +475,22 @@ function createFetchTool(opts = {}) {
|
|
|
471
475
|
${input.url}
|
|
472
476
|
${prompt}`;
|
|
473
477
|
const hit = recall(key);
|
|
474
|
-
if (hit)
|
|
478
|
+
if (hit) {
|
|
479
|
+
ctx.refundFetch?.();
|
|
480
|
+
return { output: hit, display: withCost(hit, t("focused excerpt \xB7 cache")) };
|
|
481
|
+
}
|
|
475
482
|
const out = await extractWithKeenable(keenableURL, input.url, prompt, ctx.signal);
|
|
476
483
|
if (out) {
|
|
477
|
-
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.]
|
|
478
485
|
${out}`;
|
|
479
486
|
remember(key, output2, output2.length);
|
|
480
|
-
return { output: output2, display: withCost(output2, "
|
|
487
|
+
return { output: output2, display: withCost(output2, t("focused excerpt (Keenable)")) };
|
|
481
488
|
}
|
|
482
489
|
}
|
|
483
490
|
let page = recall(`p
|
|
484
491
|
${input.url}`);
|
|
485
492
|
const cached = !!page;
|
|
493
|
+
if (cached) ctx.refundFetch?.();
|
|
486
494
|
if (!page) {
|
|
487
495
|
const loaded = await loadPage(input.url, ctx.signal);
|
|
488
496
|
if ("error" in loaded) return { output: loaded.error, isError: true };
|
|
@@ -495,23 +503,23 @@ ${input.url}`, page, page.text.length);
|
|
|
495
503
|
if (prompt && !input.offset) {
|
|
496
504
|
const picked = pickRelevant(text, prompt);
|
|
497
505
|
if (picked) {
|
|
498
|
-
const output2 = `[
|
|
506
|
+
const output2 = `[Most relevant excerpt from ${input.url} for "${prompt}" (${text.length} characters total). Full page: fetch without a prompt.]
|
|
499
507
|
${picked}`;
|
|
500
|
-
return { output: output2, display: withCost(output2,
|
|
508
|
+
return { output: output2, display: withCost(output2, `${t("focused excerpt (local)")}${via}`) };
|
|
501
509
|
}
|
|
502
510
|
}
|
|
503
511
|
const offset = input.offset ?? 0;
|
|
504
512
|
if (offset >= text.length && text.length > 0) {
|
|
505
|
-
return { output: `offset ${offset}
|
|
513
|
+
return { output: `offset ${offset} is past the end of the page (${text.length} characters).`, isError: true };
|
|
506
514
|
}
|
|
507
515
|
const end = Math.min(offset + MAX_CHARS, text.length);
|
|
508
516
|
let output = text.slice(offset, end);
|
|
509
517
|
if (end < text.length || truncated) {
|
|
510
518
|
const total = truncated ? `${text.length}+` : text.length;
|
|
511
519
|
output += `
|
|
512
|
-
\u2026 [
|
|
520
|
+
\u2026 [truncated: characters ${offset}-${end} of ${total}. Continue with offset=${end}, or use prompt for a focused excerpt.]`;
|
|
513
521
|
}
|
|
514
|
-
const size = truncated ? "
|
|
522
|
+
const size = truncated ? t("over 5 MB, truncated") : t("{n} characters", { n: text.length });
|
|
515
523
|
return { output, display: withCost(output, `${size}${via}`) };
|
|
516
524
|
}
|
|
517
525
|
});
|
|
@@ -542,19 +550,19 @@ async function loadPage(inputUrl, signal) {
|
|
|
542
550
|
const next = new URL(location, url);
|
|
543
551
|
if (next.host !== url.host) {
|
|
544
552
|
await res.body?.cancel();
|
|
545
|
-
return { error: `Redirect
|
|
553
|
+
return { error: `Redirect to another host: ${next.href}. Call fetch again with that URL if needed (permission will be requested).` };
|
|
546
554
|
}
|
|
547
555
|
await res.body?.cancel();
|
|
548
556
|
url = next;
|
|
549
557
|
}
|
|
550
558
|
} catch (error) {
|
|
551
|
-
return { error: `
|
|
559
|
+
return { error: `Failed to fetch ${inputUrl}: ${describeFetchError(error)}` };
|
|
552
560
|
}
|
|
553
|
-
if (!res) return { error: `
|
|
561
|
+
if (!res) return { error: `Failed to fetch ${inputUrl}` };
|
|
554
562
|
const { text: body, truncated } = await readCapped(res);
|
|
555
563
|
const type = res.headers.get("content-type") ?? "";
|
|
556
564
|
const text = type.includes("html") ? htmlToText(body) : body;
|
|
557
|
-
if (!res.ok) return { error: `HTTP ${res.status}
|
|
565
|
+
if (!res.ok) return { error: `HTTP ${res.status} from ${inputUrl}: ${text.slice(0, 500)}` };
|
|
558
566
|
return { text, truncated, at: Date.now() };
|
|
559
567
|
}
|
|
560
568
|
var fetchTool = createFetchTool();
|
|
@@ -574,10 +582,10 @@ var globTool = defineTool({
|
|
|
574
582
|
async run(input, ctx) {
|
|
575
583
|
const root = resolvePath(ctx.cwd, input.path ?? ".");
|
|
576
584
|
const files = (await fg(input.pattern, { cwd: root, ignore: ignorePatterns(root), onlyFiles: true, dot: true })).sort();
|
|
577
|
-
if (!files.length) return { output: "
|
|
585
|
+
if (!files.length) return { output: "No matching files." };
|
|
578
586
|
const shown = files.slice(0, 500);
|
|
579
587
|
const more = files.length > shown.length ? `
|
|
580
|
-
\u2026 ${files.length - shown.length}
|
|
588
|
+
\u2026 ${files.length - shown.length} more files` : "";
|
|
581
589
|
return { output: shown.join("\n") + more, display: `${files.length} file` };
|
|
582
590
|
}
|
|
583
591
|
});
|
|
@@ -639,11 +647,11 @@ var grepTool = defineTool({
|
|
|
639
647
|
try {
|
|
640
648
|
new RegExp(input.pattern);
|
|
641
649
|
} catch (error) {
|
|
642
|
-
return { output: `
|
|
650
|
+
return { output: `Invalid regex: ${error.message}`, isError: true };
|
|
643
651
|
}
|
|
644
652
|
const matches = await grepRg(input.pattern, opts) ?? await grepJs(input.pattern, opts);
|
|
645
|
-
if (!matches.length) return { output: "
|
|
646
|
-
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 }) };
|
|
647
655
|
}
|
|
648
656
|
});
|
|
649
657
|
|
|
@@ -667,25 +675,25 @@ var readTool = defineTool({
|
|
|
667
675
|
try {
|
|
668
676
|
buffer = await readFile3(abs);
|
|
669
677
|
} catch (error) {
|
|
670
|
-
return { output: `
|
|
678
|
+
return { output: `Cannot read ${input.path}: ${errorCode(error)}`, isError: true };
|
|
671
679
|
}
|
|
672
680
|
if (buffer.subarray(0, 8e3).includes(0)) {
|
|
673
|
-
return { output: `${input.path}
|
|
681
|
+
return { output: `${input.path} is a binary file; not read.`, isError: true };
|
|
674
682
|
}
|
|
675
683
|
const lines = buffer.toString("utf8").split(/\r?\n/);
|
|
676
684
|
const start = (input.offset ?? 1) - 1;
|
|
677
685
|
const limit = input.limit ?? 2e3;
|
|
678
686
|
const slice = lines.slice(start, start + limit);
|
|
679
687
|
const body = slice.map((line, i) => {
|
|
680
|
-
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;
|
|
681
689
|
return `${String(start + i + 1).padStart(6)} ${text}`;
|
|
682
690
|
}).join("\n");
|
|
683
691
|
const remaining = lines.length - start - slice.length;
|
|
684
692
|
ctx.readFiles.add(abs);
|
|
685
693
|
return {
|
|
686
694
|
output: remaining > 0 ? `${body}
|
|
687
|
-
\u2026 ${remaining}
|
|
688
|
-
display:
|
|
695
|
+
\u2026 ${remaining} more lines (use offset)` : body,
|
|
696
|
+
display: t("{n} lines", { n: slice.length })
|
|
689
697
|
};
|
|
690
698
|
}
|
|
691
699
|
});
|
|
@@ -706,7 +714,7 @@ var writeTool = defineTool({
|
|
|
706
714
|
target: (input) => input.path,
|
|
707
715
|
async validate(input, ctx) {
|
|
708
716
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
709
|
-
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;
|
|
710
718
|
},
|
|
711
719
|
async preview(input, ctx) {
|
|
712
720
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
@@ -716,18 +724,18 @@ var writeTool = defineTool({
|
|
|
716
724
|
async run(input, ctx) {
|
|
717
725
|
const abs = resolvePath(ctx.cwd, input.path);
|
|
718
726
|
if (existsSync(abs) && !ctx.readFiles.has(abs)) {
|
|
719
|
-
return { output: `${input.path}
|
|
727
|
+
return { output: `${input.path} already exists. Read it with read before overwriting it.`, isError: true };
|
|
720
728
|
}
|
|
721
729
|
try {
|
|
722
730
|
await ctx.checkpoint?.(abs);
|
|
723
731
|
await mkdir(dirname(abs), { recursive: true });
|
|
724
732
|
await writeFile2(abs, input.content);
|
|
725
733
|
} catch (error) {
|
|
726
|
-
return { output: `
|
|
734
|
+
return { output: `Failed to write ${input.path}: ${errorCode(error)}`, isError: true };
|
|
727
735
|
}
|
|
728
736
|
ctx.readFiles.add(abs);
|
|
729
737
|
const lines = input.content.split("\n").length;
|
|
730
|
-
return { output: `
|
|
738
|
+
return { output: `Wrote ${input.path} (${lines} lines).`, display: t("{lines} lines written", { lines }) };
|
|
731
739
|
}
|
|
732
740
|
});
|
|
733
741
|
|
|
@@ -743,7 +751,7 @@ function toolDefinitions(tools) {
|
|
|
743
751
|
// src/webBudget.ts
|
|
744
752
|
var KEEP_TOKENS = 4e4;
|
|
745
753
|
var PRUNE_MIN_TOKENS = 2e4;
|
|
746
|
-
var STUB = "[
|
|
754
|
+
var STUB = "[old tool result removed:";
|
|
747
755
|
var tokens = (text) => Math.ceil(text.length / 4);
|
|
748
756
|
var isStub = (content) => content.startsWith(STUB);
|
|
749
757
|
function pruneOldFetches(messages) {
|
|
@@ -774,7 +782,7 @@ function pruneOldFetches(messages) {
|
|
|
774
782
|
if (oldTokens <= PRUNE_MIN_TOKENS) return false;
|
|
775
783
|
for (const i of old) {
|
|
776
784
|
const m = messages[i];
|
|
777
|
-
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.]` };
|
|
778
786
|
}
|
|
779
787
|
return true;
|
|
780
788
|
}
|
|
@@ -790,6 +798,10 @@ var WebBudget = class {
|
|
|
790
798
|
startTurn() {
|
|
791
799
|
this.fetches = 0;
|
|
792
800
|
}
|
|
801
|
+
/** Gives back a reservation, e.g. when the fetch was served from cache and cost nothing. */
|
|
802
|
+
refund() {
|
|
803
|
+
if (this.fetches > 0) this.fetches--;
|
|
804
|
+
}
|
|
793
805
|
reset() {
|
|
794
806
|
this.fetches = 0;
|
|
795
807
|
this.chars = 0;
|
|
@@ -797,10 +809,10 @@ var WebBudget = class {
|
|
|
797
809
|
/** Reserves one fetch; returns the refusal to show the model when over budget. */
|
|
798
810
|
take() {
|
|
799
811
|
if (this.fetches >= this.perTurn) {
|
|
800
|
-
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.`;
|
|
801
813
|
}
|
|
802
814
|
if (this.chars >= this.sessionChars) {
|
|
803
|
-
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.`;
|
|
804
816
|
}
|
|
805
817
|
this.fetches++;
|
|
806
818
|
return void 0;
|
|
@@ -857,7 +869,7 @@ var Agent = class {
|
|
|
857
869
|
this.definitions = toolDefinitions(tools);
|
|
858
870
|
}
|
|
859
871
|
isParallelSafe(call) {
|
|
860
|
-
const tool = this.turnTools.find((
|
|
872
|
+
const tool = this.turnTools.find((t2) => t2.name === call.name);
|
|
861
873
|
if (!tool?.parallelSafe) return false;
|
|
862
874
|
try {
|
|
863
875
|
const parsed = tool.schema.safeParse(JSON.parse(call.arguments || "{}"));
|
|
@@ -893,9 +905,9 @@ var Agent = class {
|
|
|
893
905
|
reasoning: this.reasoning
|
|
894
906
|
});
|
|
895
907
|
this.clear();
|
|
896
|
-
this.push({ role: "user", content: `
|
|
908
|
+
this.push({ role: "user", content: `Summary of the previous conversation:
|
|
897
909
|
${completion.text}` });
|
|
898
|
-
this.push({ role: "assistant", content: "
|
|
910
|
+
this.push({ role: "assistant", content: "OK, I will continue from this summary." });
|
|
899
911
|
this.onEvent({ type: "compacted" });
|
|
900
912
|
}
|
|
901
913
|
async run(text, signal) {
|
|
@@ -909,7 +921,7 @@ ${completion.text}` });
|
|
|
909
921
|
for (let step = 0; step < this.maxSteps; step++) {
|
|
910
922
|
if (step > 0 && this.lastInputTokens > this.contextWindow * 0.8) {
|
|
911
923
|
await this.compact(signal);
|
|
912
|
-
this.push({ role: "user", content: `
|
|
924
|
+
this.push({ role: "user", content: `Continue this task using the summary above: ${text}` });
|
|
913
925
|
}
|
|
914
926
|
pruneOldFetches(this.messages);
|
|
915
927
|
let completion = await this.provider.chat({
|
|
@@ -950,7 +962,7 @@ ${completion.text}` });
|
|
|
950
962
|
this.onEvent({ type: "textReplace", text: completion.text });
|
|
951
963
|
this.onEvent({
|
|
952
964
|
type: "error",
|
|
953
|
-
message: "
|
|
965
|
+
message: t("The model got stuck repeating text, so the answer was stopped. Try again or switch models with /model.")
|
|
954
966
|
});
|
|
955
967
|
return;
|
|
956
968
|
}
|
|
@@ -962,7 +974,7 @@ ${completion.text}` });
|
|
|
962
974
|
let i = 0;
|
|
963
975
|
while (i < calls.length) {
|
|
964
976
|
if (signal.aborted) {
|
|
965
|
-
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." });
|
|
966
978
|
this.onEvent({ type: "aborted" });
|
|
967
979
|
return;
|
|
968
980
|
}
|
|
@@ -991,7 +1003,7 @@ ${completion.text}` });
|
|
|
991
1003
|
this.onEvent({
|
|
992
1004
|
type: "error",
|
|
993
1005
|
message: noTools ? `${message}
|
|
994
|
-
|
|
1006
|
+
${t("This model may not support tool calling. Try another model with /model.")}` : message
|
|
995
1007
|
});
|
|
996
1008
|
}
|
|
997
1009
|
}
|
|
@@ -1001,17 +1013,17 @@ Model ini sepertinya tidak mendukung tool calling. Coba model lain dengan /model
|
|
|
1001
1013
|
this.onEvent({ type: "toolEnd", id: call.id, tool: call.name, output, isError: true });
|
|
1002
1014
|
return output;
|
|
1003
1015
|
};
|
|
1004
|
-
const tool = this.turnTools.find((
|
|
1005
|
-
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(", ")}`);
|
|
1006
1018
|
let args;
|
|
1007
1019
|
try {
|
|
1008
1020
|
args = JSON.parse(call.arguments || "{}");
|
|
1009
1021
|
} catch {
|
|
1010
|
-
return fail(`
|
|
1022
|
+
return fail(`Arguments are not valid JSON: ${call.arguments.slice(0, 200)}`);
|
|
1011
1023
|
}
|
|
1012
1024
|
const parsed = tool.schema.safeParse(args);
|
|
1013
1025
|
if (!parsed.success) {
|
|
1014
|
-
return fail(`
|
|
1026
|
+
return fail(`Invalid arguments: ${parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
1015
1027
|
}
|
|
1016
1028
|
const input = parsed.data;
|
|
1017
1029
|
const target = tool.target(input);
|
|
@@ -1025,6 +1037,7 @@ Model ini sepertinya tidak mendukung tool calling. Coba model lain dengan /model
|
|
|
1025
1037
|
emit: (event) => this.onEvent(event),
|
|
1026
1038
|
ask: (req) => this.askPermission(req),
|
|
1027
1039
|
checkpoint: this.opts.checkpoint,
|
|
1040
|
+
refundFetch: () => this.webBudget.refund(),
|
|
1028
1041
|
addUsage: (u) => {
|
|
1029
1042
|
this.totalUsage.inputTokens += u.inputTokens;
|
|
1030
1043
|
this.totalUsage.outputTokens += u.outputTokens;
|
|
@@ -1052,7 +1065,7 @@ Model ini sepertinya tidak mendukung tool calling. Coba model lain dengan /model
|
|
|
1052
1065
|
decision = answer === "no" ? "deny" : "allow";
|
|
1053
1066
|
}
|
|
1054
1067
|
if (decision === "deny") {
|
|
1055
|
-
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.";
|
|
1056
1069
|
this.onEvent({ type: "toolEnd", id: call.id, tool: tool.name, output, isError: true });
|
|
1057
1070
|
return output;
|
|
1058
1071
|
}
|
|
@@ -1092,7 +1105,7 @@ var CheckpointStore = class {
|
|
|
1092
1105
|
while (this.turns() > MAX_TURNS) this.history.shift();
|
|
1093
1106
|
}
|
|
1094
1107
|
turns() {
|
|
1095
|
-
return this.history.filter((
|
|
1108
|
+
return this.history.filter((t2) => t2.size).length;
|
|
1096
1109
|
}
|
|
1097
1110
|
async undo() {
|
|
1098
1111
|
while (this.history.length && !this.history.at(-1)?.size) this.history.pop();
|
|
@@ -1138,7 +1151,7 @@ function mcpToolName(server, tool, taken) {
|
|
|
1138
1151
|
function withTimeout(promise, ms) {
|
|
1139
1152
|
let timer;
|
|
1140
1153
|
const timeout = new Promise((_, reject) => {
|
|
1141
|
-
timer = setTimeout(() => reject(new Error(
|
|
1154
|
+
timer = setTimeout(() => reject(new Error(t("timeout after {n} seconds", { n: Math.round(ms / 1e3) }))), ms);
|
|
1142
1155
|
});
|
|
1143
1156
|
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
1144
1157
|
}
|
|
@@ -1175,7 +1188,7 @@ var McpManager = class {
|
|
|
1175
1188
|
});
|
|
1176
1189
|
return;
|
|
1177
1190
|
}
|
|
1178
|
-
entry.tools = tools.map((
|
|
1191
|
+
entry.tools = tools.map((t2) => this.wrap(spec.name, client, t2));
|
|
1179
1192
|
entry.state = { ...entry.state, status: "ready", tools: entry.tools.length };
|
|
1180
1193
|
} catch (error) {
|
|
1181
1194
|
entry.state = { ...entry.state, status: "error", error: error.message };
|
|
@@ -1199,9 +1212,9 @@ var McpManager = class {
|
|
|
1199
1212
|
async run(input, ctx) {
|
|
1200
1213
|
try {
|
|
1201
1214
|
const result = await client.callTool({ name: tool.name, arguments: input }, void 0, { signal: ctx.signal });
|
|
1202
|
-
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)";
|
|
1203
1216
|
return { output: output.length > 5e4 ? `${output.slice(0, 5e4)}
|
|
1204
|
-
\u2026 [
|
|
1217
|
+
\u2026 [truncated]` : output, isError: !!result.isError };
|
|
1205
1218
|
} catch (error) {
|
|
1206
1219
|
return { output: `Server MCP ${server} error: ${error.message}`, isError: true };
|
|
1207
1220
|
}
|
|
@@ -1212,8 +1225,8 @@ var McpManager = class {
|
|
|
1212
1225
|
const entry = this.servers.get(name);
|
|
1213
1226
|
if (!entry) return;
|
|
1214
1227
|
this.servers.delete(name);
|
|
1215
|
-
for (const
|
|
1216
|
-
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));
|
|
1217
1230
|
await entry.client?.close().catch(() => {
|
|
1218
1231
|
});
|
|
1219
1232
|
this.opts.onChange?.();
|
|
@@ -1240,15 +1253,15 @@ function createExitPlanTool(opts) {
|
|
|
1240
1253
|
description: "Plan mode only: present the finished plan to the user for approval. If approved you may start implementing it.",
|
|
1241
1254
|
schema: z10.object({ plan: z10.string().describe("The plan, in markdown") }),
|
|
1242
1255
|
kind: "read",
|
|
1243
|
-
target: () => "
|
|
1256
|
+
target: () => t("plan"),
|
|
1244
1257
|
async run(input) {
|
|
1245
|
-
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 };
|
|
1246
1259
|
const decision = await opts.interaction.approvePlan(input.plan);
|
|
1247
1260
|
if (decision === "no") {
|
|
1248
|
-
return { output: "
|
|
1261
|
+
return { output: "The user has not approved yet. Ask what needs to change, revise the plan, then call exit_plan again." };
|
|
1249
1262
|
}
|
|
1250
1263
|
opts.permissions.mode = decision;
|
|
1251
|
-
return { output: `
|
|
1264
|
+
return { output: `Plan approved. The mode is now ${decision}. Start carrying out the plan now.` };
|
|
1252
1265
|
}
|
|
1253
1266
|
});
|
|
1254
1267
|
}
|
|
@@ -1265,7 +1278,7 @@ function createSkillTool(skills) {
|
|
|
1265
1278
|
target: (input) => input.name,
|
|
1266
1279
|
async run(input) {
|
|
1267
1280
|
const skill = skills.find((s) => s.name === input.name);
|
|
1268
|
-
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 };
|
|
1269
1282
|
const { body } = parseFrontmatter(readFileSync(skill.file, "utf8"));
|
|
1270
1283
|
return { output: `Base directory for this skill: ${skill.dir}
|
|
1271
1284
|
|
|
@@ -1325,12 +1338,12 @@ function createWebSearchTool(opts) {
|
|
|
1325
1338
|
}
|
|
1326
1339
|
}
|
|
1327
1340
|
if (!results.length) {
|
|
1328
|
-
return { output: errors.length ? `Web search
|
|
1341
|
+
return { output: errors.length ? `Web search failed (${errors.join("; ")}).` : "No results.", isError: errors.length > 0 };
|
|
1329
1342
|
}
|
|
1330
1343
|
const output = results.map((r, i) => `${i + 1}. ${r.title}
|
|
1331
1344
|
${r.url}${r.snippet ? `
|
|
1332
1345
|
${r.snippet}` : ""}`).join("\n");
|
|
1333
|
-
return { output, display:
|
|
1346
|
+
return { output, display: t("{n} results", { n: results.length }) };
|
|
1334
1347
|
}
|
|
1335
1348
|
});
|
|
1336
1349
|
}
|
|
@@ -1356,16 +1369,16 @@ ${list}`,
|
|
|
1356
1369
|
const allowed = byName.get(input.agent)?.tools;
|
|
1357
1370
|
if (!allowed) return false;
|
|
1358
1371
|
const base = opts.baseTools();
|
|
1359
|
-
return allowed.every((name) => base.find((
|
|
1372
|
+
return allowed.every((name) => base.find((t2) => t2.name === name)?.kind === "read");
|
|
1360
1373
|
},
|
|
1361
1374
|
async run(input, ctx) {
|
|
1362
1375
|
const def = byName.get(input.agent);
|
|
1363
|
-
if (!def) return { output: `Agent "${input.agent}"
|
|
1364
|
-
const base = opts.baseTools().filter((
|
|
1365
|
-
const unknown = (def.tools ?? []).filter((n) => !base.some((
|
|
1366
|
-
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 };
|
|
1367
1380
|
const allowed = def.tools;
|
|
1368
|
-
const tools = allowed ? base.filter((
|
|
1381
|
+
const tools = allowed ? base.filter((t2) => allowed.includes(t2.name)) : base;
|
|
1369
1382
|
let provider;
|
|
1370
1383
|
try {
|
|
1371
1384
|
provider = def.model ? opts.providerFor(def.model) : opts.provider();
|
|
@@ -1398,14 +1411,14 @@ ${def.prompt}`,
|
|
|
1398
1411
|
await child.run(input.prompt, ctx.signal);
|
|
1399
1412
|
ctx.addUsage?.(child.totalUsage);
|
|
1400
1413
|
const tokens2 = child.totalUsage.inputTokens + child.totalUsage.outputTokens;
|
|
1401
|
-
const display =
|
|
1402
|
-
if (outcome?.type === "error") return { output: `Subagent ${def.name}
|
|
1403
|
-
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 };
|
|
1404
1417
|
const last = [...child.messages].reverse().find((m) => m.role === "assistant" && m.content);
|
|
1405
|
-
const report = last && typeof last.content === "string" ? last.content : "(
|
|
1418
|
+
const report = last && typeof last.content === "string" ? last.content : "(no report)";
|
|
1406
1419
|
const suffix = outcome?.type === "stepLimit" ? `
|
|
1407
1420
|
|
|
1408
|
-
(
|
|
1421
|
+
(The subagent stopped at its ${def.maxSteps ?? 50}-step limit.)` : "";
|
|
1409
1422
|
return { output: report + suffix, display };
|
|
1410
1423
|
}
|
|
1411
1424
|
});
|
|
@@ -1435,12 +1448,12 @@ function createTodoTool(store) {
|
|
|
1435
1448
|
kind: "read",
|
|
1436
1449
|
target: (input) => `${input.todos.length} item`,
|
|
1437
1450
|
async run(input) {
|
|
1438
|
-
if (input.todos.filter((
|
|
1439
|
-
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 };
|
|
1440
1453
|
}
|
|
1441
1454
|
store.set(input.todos);
|
|
1442
|
-
const done = input.todos.filter((
|
|
1443
|
-
return { output: `Todo
|
|
1455
|
+
const done = input.todos.filter((t2) => t2.status === "completed").length;
|
|
1456
|
+
return { output: `Todo updated: ${done}/${input.todos.length} completed.` };
|
|
1444
1457
|
}
|
|
1445
1458
|
});
|
|
1446
1459
|
}
|
|
@@ -1459,7 +1472,7 @@ function createRuntime(opts) {
|
|
|
1459
1472
|
};
|
|
1460
1473
|
const provider = makeProvider(modelRef);
|
|
1461
1474
|
const mode = opts.args.allowAll ? "allowAll" : opts.args.permissionMode ?? config.permissionMode;
|
|
1462
|
-
const rules = [...config.allow, ...opts.args.allowedTools.map((
|
|
1475
|
+
const rules = [...config.allow, ...opts.args.allowedTools.map((t2) => TOOL_RULES[t2] ?? t2)];
|
|
1463
1476
|
const permissions = new Permissions(mode, rules, opts.cwd);
|
|
1464
1477
|
const roots = { cwd: opts.cwd, home, userHome: opts.userHome ?? homedir() };
|
|
1465
1478
|
const skills = loadSkills(roots);
|
|
@@ -1493,7 +1506,7 @@ function createRuntime(opts) {
|
|
|
1493
1506
|
const task = createTaskTool({
|
|
1494
1507
|
agents: [...BUILTIN_AGENTS, ...agentDefs],
|
|
1495
1508
|
// Subagents get whatever the main agent has right now (incl. MCP tools), minus task itself.
|
|
1496
|
-
baseTools: () => agent.tools.filter((
|
|
1509
|
+
baseTools: () => agent.tools.filter((t2) => t2.name !== "task"),
|
|
1497
1510
|
permissions,
|
|
1498
1511
|
provider: () => agent.provider,
|
|
1499
1512
|
providerFor: makeProvider,
|
|
@@ -1591,33 +1604,42 @@ function createRuntime(opts) {
|
|
|
1591
1604
|
}
|
|
1592
1605
|
|
|
1593
1606
|
// src/version.ts
|
|
1594
|
-
var VERSION = true ? "0.4.0-beta.
|
|
1607
|
+
var VERSION = true ? "0.4.0-beta.15" : "0.0.0-dev";
|
|
1595
1608
|
|
|
1596
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
|
+
}
|
|
1597
1618
|
async function main() {
|
|
1619
|
+
chooseLanguage(process.argv.slice(2));
|
|
1598
1620
|
const args = parseCliArgs(process.argv.slice(2));
|
|
1599
1621
|
if (args.version) {
|
|
1600
1622
|
console.log(VERSION);
|
|
1601
1623
|
return 0;
|
|
1602
1624
|
}
|
|
1603
1625
|
if (args.help) {
|
|
1604
|
-
console.log(
|
|
1626
|
+
console.log(helpText());
|
|
1605
1627
|
return 0;
|
|
1606
1628
|
}
|
|
1607
1629
|
const cwd = process.cwd();
|
|
1608
1630
|
if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
|
|
1609
1631
|
if (args.command === "mcp") {
|
|
1610
|
-
const { runMcpCommand } = await import("./mcpCli-
|
|
1611
|
-
const { readSecret } = await import("./login-
|
|
1632
|
+
const { runMcpCommand } = await import("./mcpCli-QJE7P76I.js");
|
|
1633
|
+
const { readSecret } = await import("./login-O2BQX6LZ.js");
|
|
1612
1634
|
return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1613
1635
|
}
|
|
1614
1636
|
if (args.command === "provider") {
|
|
1615
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
1616
|
-
const { readSecret } = await import("./login-
|
|
1637
|
+
const { runProviderCommand } = await import("./providerCli-3FJAUH7C.js");
|
|
1638
|
+
const { readSecret } = await import("./login-O2BQX6LZ.js");
|
|
1617
1639
|
return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1618
1640
|
}
|
|
1619
1641
|
if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
|
|
1620
|
-
const { runIntegrationCommand } = await import("./integrationCli-
|
|
1642
|
+
const { runIntegrationCommand } = await import("./integrationCli-RQO3HHQE.js");
|
|
1621
1643
|
return runIntegrationCommand(args, {
|
|
1622
1644
|
env: process.env,
|
|
1623
1645
|
cwd,
|
|
@@ -1639,11 +1661,11 @@ async function main() {
|
|
|
1639
1661
|
} catch {
|
|
1640
1662
|
}
|
|
1641
1663
|
if (args.print) {
|
|
1642
|
-
if (!args.prompt) throw new ConfigError('
|
|
1643
|
-
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");
|
|
1644
1666
|
const plan = serversToStart(rt.home, cwd);
|
|
1645
1667
|
for (const s of plan.needTrust) {
|
|
1646
|
-
console.error(
|
|
1668
|
+
console.error(t('Project MCP server "{name}" skipped (not approved yet; run interactive bccli once to approve it).', { name: s.name }));
|
|
1647
1669
|
}
|
|
1648
1670
|
await rt.startMcp(plan.start);
|
|
1649
1671
|
try {
|
|
@@ -1652,8 +1674,8 @@ async function main() {
|
|
|
1652
1674
|
await rt.mcp.stop();
|
|
1653
1675
|
}
|
|
1654
1676
|
}
|
|
1655
|
-
if (!process.stdin.isTTY) throw new ConfigError('
|
|
1656
|
-
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-HVH3TR3I.js");
|
|
1657
1679
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
|
|
1658
1680
|
}
|
|
1659
1681
|
main().then(
|