@botconnector/bccli 0.4.0-beta.15 → 0.4.0-beta.17

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/dist/cli.js CHANGED
@@ -1604,7 +1604,7 @@ function createRuntime(opts) {
1604
1604
  }
1605
1605
 
1606
1606
  // src/version.ts
1607
- var VERSION = true ? "0.4.0-beta.15" : "0.0.0-dev";
1607
+ var VERSION = true ? "0.4.0-beta.17" : "0.0.0-dev";
1608
1608
 
1609
1609
  // src/cli.ts
1610
1610
  function chooseLanguage(argv) {
@@ -1675,7 +1675,7 @@ async function main() {
1675
1675
  }
1676
1676
  }
1677
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");
1678
+ const { startInteractive } = await import("./ui-RNP272MP.js");
1679
1679
  return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
1680
1680
  }
1681
1681
  main().then(
@@ -215,7 +215,308 @@ function parseMemoryArgs(args) {
215
215
  }
216
216
 
217
217
  // src/ui/Markdown.tsx
218
- import { Box, Text } from "ink";
218
+ import { Box, Text, useStdout } from "ink";
219
+
220
+ // src/ui/table.ts
221
+ var WIDE = [
222
+ [4352, 4447],
223
+ [8986, 8987],
224
+ [9193, 9196],
225
+ [9200, 9200],
226
+ [9203, 9203],
227
+ [9725, 9726],
228
+ [9748, 9749],
229
+ [9800, 9811],
230
+ [9855, 9855],
231
+ [9875, 9875],
232
+ [9889, 9889],
233
+ [9898, 9899],
234
+ [9917, 9918],
235
+ [9924, 9925],
236
+ [9934, 9934],
237
+ [9940, 9940],
238
+ [9962, 9962],
239
+ [9970, 9971],
240
+ [9973, 9973],
241
+ [9978, 9978],
242
+ [9981, 9981],
243
+ [9989, 9989],
244
+ [9994, 9995],
245
+ [10024, 10024],
246
+ [10060, 10060],
247
+ [10062, 10062],
248
+ [10067, 10069],
249
+ [10071, 10071],
250
+ [10133, 10135],
251
+ [10160, 10160],
252
+ [10175, 10175],
253
+ [11035, 11036],
254
+ [11088, 11088],
255
+ [11093, 11093],
256
+ [11904, 42191],
257
+ [44032, 55203],
258
+ [63744, 64255],
259
+ [65072, 65135],
260
+ [65280, 65376],
261
+ [65504, 65510],
262
+ [127744, 128591],
263
+ [128640, 128767],
264
+ [129280, 129791],
265
+ [131072, 262141]
266
+ ];
267
+ var ZERO = [
268
+ [768, 879],
269
+ [6832, 6911],
270
+ [7616, 7679],
271
+ [8203, 8207],
272
+ [8400, 8447],
273
+ [65024, 65039],
274
+ [65279, 65279],
275
+ [917760, 917999]
276
+ ];
277
+ var inRanges = (cp, ranges) => ranges.some(([a, b]) => cp >= a && cp <= b);
278
+ function charWidth(cp) {
279
+ if (cp < 32 || cp >= 127 && cp < 160) return 0;
280
+ if (cp < 768) return 1;
281
+ if (inRanges(cp, ZERO)) return 0;
282
+ return inRanges(cp, WIDE) ? 2 : 1;
283
+ }
284
+ function displayWidth(text) {
285
+ let width = 0;
286
+ for (const ch of text) width += charWidth(ch.codePointAt(0));
287
+ return width;
288
+ }
289
+ var segsWidth = (segs) => segs.reduce((sum, s) => sum + displayWidth(s.text), 0);
290
+ var INLINE = /(`[^`]+`|\*\*[^*]+\*\*|~~[^~]+~~|!?\[[^\]\n]+\]\([^)\s]+\)|(?<![\w*])\*(?![\s*])[^*\n]+?(?<![\s*])\*(?![\w*])|(?<!\w)_(?![\s_])[^_\n]+?(?<![\s_])_(?!\w))/g;
291
+ function parseInline(text) {
292
+ const segs = [];
293
+ for (const part of text.split(INLINE)) {
294
+ if (part === "") continue;
295
+ if (part.length > 2 && part.startsWith("`") && part.endsWith("`")) segs.push({ text: part.slice(1, -1), style: "code" });
296
+ else if (part.length > 4 && part.startsWith("**") && part.endsWith("**")) segs.push({ text: part.slice(2, -2), style: "bold" });
297
+ else if (part.length > 4 && part.startsWith("~~") && part.endsWith("~~")) segs.push({ text: part.slice(2, -2), style: "strike" });
298
+ else if (/^!?\[[^\]\n]+\]\([^)\s]+\)$/.test(part)) {
299
+ const m = /^(!?)\[([^\]]+)\]\(([^)\s]+)\)$/.exec(part);
300
+ const [, image, label, url] = m;
301
+ segs.push({ text: label, style: image ? "plain" : "link" });
302
+ if (label !== url && !url.startsWith("#")) segs.push({ text: ` (${url})`, style: "dim" });
303
+ } else if (part.length > 2 && (part.startsWith("*") && part.endsWith("*") || part.startsWith("_") && part.endsWith("_"))) {
304
+ segs.push({ text: part.slice(1, -1), style: "italic" });
305
+ } else segs.push({ text: part, style: "plain" });
306
+ }
307
+ return segs;
308
+ }
309
+ function splitRow(line) {
310
+ let s = line.trim();
311
+ if (s.startsWith("|")) s = s.slice(1);
312
+ if (s.endsWith("|") && !s.endsWith("\\|")) s = s.slice(0, -1);
313
+ const cells = [];
314
+ let current = "";
315
+ for (let i = 0; i < s.length; i++) {
316
+ if (s[i] === "\\" && s[i + 1] === "|") {
317
+ current += "|";
318
+ i++;
319
+ } else if (s[i] === "|") {
320
+ cells.push(current);
321
+ current = "";
322
+ } else current += s[i];
323
+ }
324
+ cells.push(current);
325
+ return cells.map((c) => c.trim());
326
+ }
327
+ var SEPARATOR = /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;
328
+ var isSeparator = (line) => line.includes("|") && SEPARATOR.test(line);
329
+ var cell = (raw) => parseInline(raw.replace(/<br\s*\/?>/gi, "\n"));
330
+ function parseTable(lines, start) {
331
+ if (start + 1 >= lines.length || !lines[start].includes("|") || !isSeparator(lines[start + 1])) return void 0;
332
+ const header = splitRow(lines[start]);
333
+ const sep = splitRow(lines[start + 1]);
334
+ if (sep.length !== header.length) return void 0;
335
+ const body = [];
336
+ let end = start + 2;
337
+ while (end < lines.length && lines[end].trim() && lines[end].includes("|")) body.push(splitRow(lines[end++]));
338
+ const columns = Math.max(header.length, ...body.map((r) => r.length));
339
+ const pad2 = (row, fill) => [...row, ...Array.from({ length: columns - row.length }, () => fill)];
340
+ const align = pad2(
341
+ sep.map((s) => s.startsWith(":") && s.endsWith(":") ? "center" : s.endsWith(":") ? "right" : "left"),
342
+ "left"
343
+ );
344
+ return { table: { header: pad2(header, "").map(cell), align, rows: body.map((r) => pad2(r, "").map(cell)) }, end };
345
+ }
346
+ function tokenize(segs) {
347
+ const tokens = [];
348
+ let word = [];
349
+ const endWord = () => {
350
+ if (word.length) tokens.push(word);
351
+ word = [];
352
+ };
353
+ for (const seg of segs) {
354
+ for (const piece of seg.text.match(/\n|[^\S\n]+|[^\s]+/g) ?? []) {
355
+ if (piece === "\n") {
356
+ endWord();
357
+ tokens.push("br");
358
+ } else if (/^\s+$/.test(piece)) endWord();
359
+ else word.push({ text: piece, style: seg.style });
360
+ }
361
+ }
362
+ endWord();
363
+ return tokens;
364
+ }
365
+ function splitWord(word, width) {
366
+ const pieces = [];
367
+ let current = [];
368
+ let used = 0;
369
+ for (const seg of word) {
370
+ let text = "";
371
+ for (const ch of seg.text) {
372
+ const w = charWidth(ch.codePointAt(0));
373
+ if (used + w > width && used > 0) {
374
+ if (text) current.push({ text, style: seg.style });
375
+ pieces.push(current);
376
+ current = [];
377
+ text = "";
378
+ used = 0;
379
+ }
380
+ text += ch;
381
+ used += w;
382
+ }
383
+ if (text) current.push({ text, style: seg.style });
384
+ }
385
+ if (current.length) pieces.push(current);
386
+ return pieces;
387
+ }
388
+ function wrap(tokens, width) {
389
+ const lines = [];
390
+ let line = [];
391
+ let used = 0;
392
+ const flush = () => {
393
+ lines.push(line);
394
+ line = [];
395
+ used = 0;
396
+ };
397
+ for (const token of tokens) {
398
+ if (token === "br") {
399
+ flush();
400
+ continue;
401
+ }
402
+ const w = segsWidth(token);
403
+ if (w > width) {
404
+ if (used > 0) flush();
405
+ const pieces = splitWord(token, width);
406
+ for (const piece of pieces.slice(0, -1)) {
407
+ line = piece;
408
+ flush();
409
+ }
410
+ line = pieces.at(-1) ?? [];
411
+ used = segsWidth(line);
412
+ } else if (used === 0) {
413
+ line = [...token];
414
+ used = w;
415
+ } else if (used + 1 + w <= width) {
416
+ line.push({ text: " ", style: "plain" }, ...token);
417
+ used += 1 + w;
418
+ } else {
419
+ flush();
420
+ line = [...token];
421
+ used = w;
422
+ }
423
+ }
424
+ flush();
425
+ return lines;
426
+ }
427
+ var SEP = " \u2502 ";
428
+ var RULE_JOIN = "\u2500\u253C\u2500";
429
+ var MAX_MIN_WIDTH = 12;
430
+ var dim = (text) => ({ text, style: "dim" });
431
+ function rtrim(line) {
432
+ const out = [...line];
433
+ while (out.length) {
434
+ const last = out[out.length - 1];
435
+ const text = last.text.trimEnd();
436
+ if (text) {
437
+ out[out.length - 1] = { ...last, text };
438
+ break;
439
+ }
440
+ out.pop();
441
+ }
442
+ return out;
443
+ }
444
+ var bold = (segs) => segs.map((s) => s.style === "plain" ? { ...s, style: "bold" } : s);
445
+ function pad(segs, width, align, last) {
446
+ const space = Math.max(0, width - segsWidth(segs));
447
+ const left = align === "right" ? space : align === "center" ? Math.floor(space / 2) : 0;
448
+ const right = last ? 0 : space - left;
449
+ return [...left ? [{ text: " ".repeat(left), style: "plain" }] : [], ...segs, ...right ? [{ text: " ".repeat(right), style: "plain" }] : []];
450
+ }
451
+ function columnWidths(table, available) {
452
+ const columns = table.align.length;
453
+ const all = [table.header, ...table.rows];
454
+ const natural = [];
455
+ const minimum = [];
456
+ for (let c = 0; c < columns; c++) {
457
+ let widest = 1;
458
+ let longestWord = 1;
459
+ for (const row of all) {
460
+ const tokens = tokenize(row[c]);
461
+ for (const line of wrap(tokens, Number.POSITIVE_INFINITY)) widest = Math.max(widest, segsWidth(line));
462
+ for (const token of tokens) if (token !== "br") longestWord = Math.max(longestWord, segsWidth(token));
463
+ }
464
+ natural.push(widest);
465
+ minimum.push(Math.min(longestWord, MAX_MIN_WIDTH, widest));
466
+ }
467
+ if (minimum.reduce((a, b) => a + b, 0) > available) return void 0;
468
+ const widths = [...natural];
469
+ let total = widths.reduce((a, b) => a + b, 0);
470
+ while (total > available) {
471
+ let pick = -1;
472
+ for (let c = 0; c < columns; c++) if (widths[c] > minimum[c] && (pick < 0 || widths[c] > widths[pick])) pick = c;
473
+ if (pick < 0) return void 0;
474
+ widths[pick]--;
475
+ total--;
476
+ }
477
+ return widths;
478
+ }
479
+ function stacked(table, width) {
480
+ const lines = [];
481
+ table.rows.forEach((row, r) => {
482
+ if (r > 0) lines.push([dim("\u2500".repeat(Math.min(width, 40)))]);
483
+ row.forEach((value, c) => {
484
+ const label = [...bold(table.header[c]), { text: ": ", style: "plain" }, ...value];
485
+ lines.push(...wrap(tokenize(label), width));
486
+ });
487
+ });
488
+ return lines.length ? lines : [bold(table.header.flat())];
489
+ }
490
+ function layoutTable(table, width) {
491
+ const columns = table.align.length;
492
+ const available = Math.max(columns, width - (columns - 1) * SEP.length);
493
+ const widths = columnWidths(table, available);
494
+ if (!widths) return stacked(table, Math.max(10, width));
495
+ const renderRow = (cells, header) => {
496
+ const wrapped = cells.map((segs, c) => wrap(tokenize(header ? bold(segs) : segs), widths[c]));
497
+ const height = Math.max(...wrapped.map((w) => w.length));
498
+ const lines = [];
499
+ for (let l = 0; l < height; l++) {
500
+ const line = [];
501
+ wrapped.forEach((w, c) => {
502
+ if (c > 0) line.push(dim(SEP));
503
+ line.push(...pad(w[l] ?? [], widths[c], table.align[c], c === columns - 1));
504
+ });
505
+ lines.push(rtrim(line));
506
+ }
507
+ return { lines, height };
508
+ };
509
+ const rule = [dim(widths.map((w) => "\u2500".repeat(w)).join(RULE_JOIN))];
510
+ const head = renderRow(table.header, true);
511
+ const body = table.rows.map((r) => renderRow(r, false));
512
+ const wrappedRows = body.some((b) => b.height > 1);
513
+ const out = [...head.lines, rule];
514
+ body.forEach((b, i) => {
515
+ if (wrappedRows && i > 0) out.push(rule);
516
+ out.push(...b.lines);
517
+ });
518
+ return out;
519
+ }
219
520
 
220
521
  // src/ui/theme.ts
221
522
  function color(name) {
@@ -224,30 +525,103 @@ function color(name) {
224
525
  var ACCENT = "green";
225
526
 
226
527
  // src/ui/Markdown.tsx
227
- import { jsx } from "react/jsx-runtime";
228
- function inline(line) {
229
- return line.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).map((part, i) => {
230
- if (part.length > 4 && part.startsWith("**") && part.endsWith("**")) {
231
- return /* @__PURE__ */ jsx(Text, { bold: true, children: part.slice(2, -2) }, i);
232
- }
233
- if (part.length > 2 && part.startsWith("`") && part.endsWith("`")) {
234
- return /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: part.slice(1, -1) }, i);
235
- }
236
- return part;
237
- });
528
+ import { jsx, jsxs } from "react/jsx-runtime";
529
+ function segment(seg, key) {
530
+ switch (seg.style) {
531
+ case "bold":
532
+ return /* @__PURE__ */ jsx(Text, { bold: true, children: seg.text }, key);
533
+ case "italic":
534
+ return /* @__PURE__ */ jsx(Text, { italic: true, children: seg.text }, key);
535
+ case "strike":
536
+ return /* @__PURE__ */ jsx(Text, { strikethrough: true, children: seg.text }, key);
537
+ case "link":
538
+ return /* @__PURE__ */ jsx(Text, { underline: true, color: color("cyan"), children: seg.text }, key);
539
+ case "code":
540
+ return /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: seg.text }, key);
541
+ case "dim":
542
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: seg.text }, key);
543
+ default:
544
+ return seg.text;
545
+ }
238
546
  }
239
- function Markdown({ text }) {
240
- let inCode = false;
547
+ var inline = (line) => parseInline(line).map(segment);
548
+ var HEADING = /^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$/;
549
+ var RULE = /^\s{0,3}([-*_])(?:\s*\1){2,}\s*$/;
550
+ var QUOTE = /^\s{0,3}((?:>\s?)+)(.*)$/;
551
+ var BULLET = /^(\s*)[-*+]\s+(.*)$/;
552
+ var NUMBERED = /^(\s*)(\d{1,9})[.)]\s+(.*)$/;
553
+ var BULLETS = ["\u2022", "\u25E6", "\u25AA"];
554
+ var bulletFor = (spaces) => BULLETS[spaces === 0 ? 0 : spaces <= 4 ? 1 : 2];
555
+ function hanging(key, marker, body, width, padding = 0) {
556
+ const textWidth = Math.max(10, width - padding - displayWidth(marker) - 1);
557
+ return /* @__PURE__ */ jsxs(Box, { paddingLeft: padding, children: [
558
+ /* @__PURE__ */ jsx(Box, { flexShrink: 0, marginRight: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: marker }) }),
559
+ /* @__PURE__ */ jsx(Box, { width: textWidth, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { children: body }) })
560
+ ] }, key);
561
+ }
562
+ function Markdown({ text, indent = 2 }) {
563
+ const { stdout } = useStdout();
564
+ const width = Math.max(20, (stdout?.columns ?? 80) - indent - 1);
565
+ const lines = text.split("\n");
241
566
  const rows = [];
242
- text.split("\n").forEach((line, i) => {
567
+ let inCode = false;
568
+ for (let i = 0; i < lines.length; i++) {
569
+ const line = lines[i];
243
570
  if (line.trimStart().startsWith("```")) {
244
571
  inCode = !inCode;
245
- return;
572
+ continue;
246
573
  }
247
- rows.push(
248
- inCode ? /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: ` ${line}` }, i) : /* @__PURE__ */ jsx(Text, { children: line ? inline(line) : " " }, i)
249
- );
250
- });
574
+ if (inCode) {
575
+ rows.push(
576
+ /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: ` ${line}` }, i)
577
+ );
578
+ continue;
579
+ }
580
+ const parsed = parseTable(lines, i);
581
+ if (parsed) {
582
+ layoutTable(parsed.table, width).forEach((tableLine, n) => {
583
+ rows.push(/* @__PURE__ */ jsx(Text, { children: tableLine.length ? tableLine.map(segment) : " " }, `${i}-${n}`));
584
+ });
585
+ i = parsed.end - 1;
586
+ continue;
587
+ }
588
+ const heading = HEADING.exec(line);
589
+ if (heading) {
590
+ const level = heading[1].length;
591
+ rows.push(
592
+ /* @__PURE__ */ jsx(Text, { bold: true, underline: level === 1, color: level <= 2 ? color(ACCENT) : void 0, children: parseInline(heading[2]).map((s) => s.text).join("") }, i)
593
+ );
594
+ continue;
595
+ }
596
+ if (RULE.test(line)) {
597
+ rows.push(
598
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(Math.min(width, 80)) }, i)
599
+ );
600
+ continue;
601
+ }
602
+ const quote = QUOTE.exec(line);
603
+ if (quote) {
604
+ const depth = quote[1].replace(/\s/g, "").length;
605
+ rows.push(hanging(i, "\u258E".repeat(depth), /* @__PURE__ */ jsx(Text, { italic: true, children: inline(quote[2]) }), width));
606
+ continue;
607
+ }
608
+ const bullet = BULLET.exec(line);
609
+ if (bullet) {
610
+ const padding = Math.min(bullet[1].replace(/\t/g, " ").length, 16);
611
+ const task = /^\[([ xX])\]\s+(.*)$/.exec(bullet[2]);
612
+ rows.push(
613
+ task ? hanging(i, task[1] === " " ? "\u2610" : "\u2611", inline(task[2]), width, padding) : hanging(i, bulletFor(padding), inline(bullet[2]), width, padding)
614
+ );
615
+ continue;
616
+ }
617
+ const numbered = NUMBERED.exec(line);
618
+ if (numbered) {
619
+ const padding = Math.min(numbered[1].replace(/\t/g, " ").length, 16);
620
+ rows.push(hanging(i, `${numbered[2]}.`, inline(numbered[3]), width, padding));
621
+ continue;
622
+ }
623
+ rows.push(/* @__PURE__ */ jsx(Text, { children: line ? inline(line) : " " }, i));
624
+ }
251
625
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows });
252
626
  }
253
627
 
@@ -259,7 +633,7 @@ import { useState } from "react";
259
633
  var isFocusReport = (input) => input === "[I" || input === "[O";
260
634
 
261
635
  // src/ui/LinePrompt.tsx
262
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
636
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
263
637
  function LinePrompt({ label, mask, onSubmit, onCancel }) {
264
638
  const [value, setValue] = useState("");
265
639
  useInput((input, key) => {
@@ -269,7 +643,7 @@ function LinePrompt({ label, mask, onSubmit, onCancel }) {
269
643
  else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow && !isFocusReport(input)) setValue((v) => v + input.replace(/[\r\n]/g, ""));
270
644
  });
271
645
  const shown = mask ? "\u2022".repeat(value.length) : value;
272
- return /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
646
+ return /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: /* @__PURE__ */ jsxs2(Text2, { children: [
273
647
  `${label}: `,
274
648
  shown,
275
649
  /* @__PURE__ */ jsx2(Text2, { inverse: true, children: " " }),
@@ -280,7 +654,7 @@ function LinePrompt({ label, mask, onSubmit, onCancel }) {
280
654
  // src/ui/ListPicker.tsx
281
655
  import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
282
656
  import { useState as useState2 } from "react";
283
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
657
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
284
658
  var VISIBLE = 12;
285
659
  function ListPicker({ title, items, onPick }) {
286
660
  const [filter, setFilter] = useState2("");
@@ -301,9 +675,9 @@ function ListPicker({ title, items, onPick }) {
301
675
  }
302
676
  });
303
677
  const start = Math.max(0, Math.min(cursor - 5, shown.length - VISIBLE));
304
- return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
678
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
305
679
  /* @__PURE__ */ jsx3(Text3, { bold: true, children: t("{title} (\u2191\u2193 enter \xB7 type to filter{filter} \xB7 esc cancel)", { title, filter: filter ? `: ${filter}` : "" }) }),
306
- shown.slice(start, start + VISIBLE).map((item, i) => /* @__PURE__ */ jsxs2(Text3, { color: start + i === cursor && !item.disabled ? color("green") : void 0, dimColor: item.disabled, children: [
680
+ shown.slice(start, start + VISIBLE).map((item, i) => /* @__PURE__ */ jsxs3(Text3, { color: start + i === cursor && !item.disabled ? color("green") : void 0, dimColor: item.disabled, children: [
307
681
  `${start + i === cursor ? "\u203A" : " "} ${item.label}`,
308
682
  item.hint ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: ` ${item.hint}` }) : null
309
683
  ] }, item.id)),
@@ -314,7 +688,7 @@ function ListPicker({ title, items, onPick }) {
314
688
  // src/ui/ModelPicker.tsx
315
689
  import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
316
690
  import { useState as useState3 } from "react";
317
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
691
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
318
692
  var VISIBLE2 = 14;
319
693
  function ModelPicker({ groups, current, onPick }) {
320
694
  const [filter, setFilter] = useState3("");
@@ -346,7 +720,7 @@ function ModelPicker({ groups, current, onPick }) {
346
720
  }
347
721
  });
348
722
  const start = Math.max(0, Math.min(cursor - 5, rows.length - VISIBLE2));
349
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
723
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
350
724
  /* @__PURE__ */ jsx4(Text4, { bold: true, children: t("Choose a model (type to filter{filter} \xB7 \u2191\u2193 enter \xB7 esc cancel)", { filter: filter ? `: ${filter}` : "" }) }),
351
725
  rows.slice(start, start + VISIBLE2).map(
352
726
  (row, i) => row.kind === "header" ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: `\u2500\u2500 ${row.text} ` }, `h${start + i}`) : /* @__PURE__ */ jsx4(Text4, { color: start + i === cursor ? color("green") : void 0, children: `${start + i === cursor ? "\u203A" : " "} ${row.label}${row.ref === current ? " (aktif)" : ""}` }, row.ref)
@@ -359,7 +733,7 @@ function ModelPicker({ groups, current, onPick }) {
359
733
  // src/ui/ProviderMenu.tsx
360
734
  import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
361
735
  import { useState as useState4 } from "react";
362
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
736
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
363
737
  function ProviderMenu({ entries, onPick }) {
364
738
  const rows = [...entries.map((e) => e.id), "custom"];
365
739
  const [index, setIndex] = useState4(0);
@@ -369,9 +743,9 @@ function ProviderMenu({ entries, onPick }) {
369
743
  else if (key.return) onPick(rows[index]);
370
744
  else if (key.escape) onPick(void 0);
371
745
  });
372
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
746
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
373
747
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: t("Provider (\u2191\u2193 enter, esc cancel) \xB7 \u2713 ready \xB7 \u25CB needs API key") }),
374
- entries.map((e, i) => /* @__PURE__ */ jsxs4(Text5, { color: i === index ? color("green") : void 0, children: [
748
+ entries.map((e, i) => /* @__PURE__ */ jsxs5(Text5, { color: i === index ? color("green") : void 0, children: [
375
749
  `${i === index ? "\u203A" : " "} ${e.ready ? "\u2713" : "\u25CB"} ${e.name}`,
376
750
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: ` ${e.baseURL}` })
377
751
  ] }, e.id)),
@@ -394,7 +768,7 @@ function DiffView({ diff }) {
394
768
  }
395
769
 
396
770
  // src/ui/PermissionPrompt.tsx
397
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
771
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
398
772
  var VERB = { edit: "edit", write: "write", bash: "run", fetch: "fetch" };
399
773
  function PermissionPrompt({
400
774
  request,
@@ -409,10 +783,10 @@ function PermissionPrompt({
409
783
  });
410
784
  const rules = request.sessionRules ?? [];
411
785
  const sessionLabel = !rules.length ? null : request.kind === "edit" ? t("yes for all edits in this project, this session") : t("yes this session for {rules}", { rules: rules.join(", ") });
412
- return /* @__PURE__ */ jsxs5(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
786
+ return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
413
787
  /* @__PURE__ */ jsx7(Text7, { bold: true, children: `${request.agent ? `[${request.agent}] ` : ""}${t("Allow {verb} {target}?", { verb: t(VERB[request.tool] ?? request.tool), target: request.target })}` }),
414
788
  request.preview ? /* @__PURE__ */ jsx7(DiffView, { diff: request.preview }) : null,
415
- /* @__PURE__ */ jsxs5(Text7, { children: [
789
+ /* @__PURE__ */ jsxs6(Text7, { children: [
416
790
  /* @__PURE__ */ jsx7(Text7, { color: color("green"), children: t("[y] yes") }),
417
791
  " ",
418
792
  sessionLabel ? /* @__PURE__ */ jsx7(Text7, { color: color("cyan"), children: `[a] ${sessionLabel} ` }) : null,
@@ -440,7 +814,7 @@ function completeFile(value, cwd) {
440
814
  }
441
815
 
442
816
  // src/ui/PromptInput.tsx
443
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
817
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
444
818
  function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
445
819
  const [value, setValue] = useState5("");
446
820
  const [historyIndex, setHistoryIndex] = useState5(null);
@@ -514,8 +888,8 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
514
888
  },
515
889
  { isActive: !disabled }
516
890
  );
517
- return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", children: [
518
- /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs6(Text8, { children: [
891
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
892
+ /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs7(Text8, { children: [
519
893
  /* @__PURE__ */ jsx8(Text8, { color: color("green"), children: "> " }),
520
894
  value,
521
895
  disabled ? "" : /* @__PURE__ */ jsx8(Text8, { inverse: true, children: " " })
@@ -559,7 +933,7 @@ function StatusBar({ mode, tokens, busy, model, reasoning = "auto" }) {
559
933
  // src/ui/McpMenu.tsx
560
934
  import { Box as Box9, Text as Text11, useInput as useInput7 } from "ink";
561
935
  import { useState as useState7 } from "react";
562
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
936
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
563
937
  var MARK = { ready: "\u2713", error: "\u2717", starting: "\u2026", off: "\u25CB" };
564
938
  function McpMenu({ items, onPick }) {
565
939
  const [index, setIndex] = useState7(0);
@@ -569,9 +943,9 @@ function McpMenu({ items, onPick }) {
569
943
  else if (key.return) onPick(items[index]?.name);
570
944
  else if (key.escape) onPick(void 0);
571
945
  });
572
- return /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
946
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
573
947
  /* @__PURE__ */ jsx11(Text11, { bold: true, children: t("MCP servers (enter: install / remove \xB7 esc close) \xB7 \u2713 active \u25CB not installed \u2717 error") }),
574
- items.map((item, i) => /* @__PURE__ */ jsxs7(Text11, { color: i === index ? color("green") : void 0, children: [
948
+ items.map((item, i) => /* @__PURE__ */ jsxs8(Text11, { color: i === index ? color("green") : void 0, children: [
575
949
  `${i === index ? "\u203A" : " "} ${MARK[item.status]} ${item.name.padEnd(12)}`,
576
950
  /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: item.status === "error" ? ` ${item.error ?? ""}` : ` ${item.description}` })
577
951
  ] }, item.name))
@@ -580,7 +954,7 @@ function McpMenu({ items, onPick }) {
580
954
 
581
955
  // src/ui/PlanApproval.tsx
582
956
  import { Box as Box10, Text as Text12, useInput as useInput8 } from "ink";
583
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
957
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
584
958
  function PlanApproval({ plan, onAnswer }) {
585
959
  useInput8((input, key) => {
586
960
  const k2 = input.toLowerCase();
@@ -588,10 +962,10 @@ function PlanApproval({ plan, onAnswer }) {
588
962
  else if (k2 === "y") onAnswer("default");
589
963
  else if (k2 === "n" || key.escape) onAnswer("no");
590
964
  });
591
- return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
965
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
592
966
  /* @__PURE__ */ jsx12(Text12, { bold: true, children: t("Plan from the agent") }),
593
- /* @__PURE__ */ jsx12(Markdown, { text: plan }),
594
- /* @__PURE__ */ jsxs8(Text12, { children: [
967
+ /* @__PURE__ */ jsx12(Markdown, { text: plan, indent: 5 }),
968
+ /* @__PURE__ */ jsxs9(Text12, { children: [
595
969
  /* @__PURE__ */ jsx12(Text12, { color: color("green"), children: t("[a] yes, auto-edit") }),
596
970
  " ",
597
971
  /* @__PURE__ */ jsx12(Text12, { color: color("cyan"), children: t("[y] yes, ask at each step") }),
@@ -612,26 +986,26 @@ function TodoList({ items }) {
612
986
 
613
987
  // src/ui/ToolBlock.tsx
614
988
  import { Box as Box12, Text as Text14 } from "ink";
615
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
989
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
616
990
  var PREVIEW_LINES = 5;
617
991
  function ToolBlock({ tool, target, output, display, isError, done, expanded, sub }) {
618
992
  const isTask = tool === "task";
619
993
  const isDiff = !!display && /^\s*\d+ [+\- ] /.test(display);
620
994
  const lines = (output ?? "").split("\n");
621
995
  const shown = expanded ? lines : lines.slice(0, PREVIEW_LINES);
622
- return /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 2, children: [
623
- /* @__PURE__ */ jsxs9(Text14, { children: [
996
+ return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 2, children: [
997
+ /* @__PURE__ */ jsxs10(Text14, { children: [
624
998
  /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : done ? color("green") : color("yellow"), children: "\u23BF " }),
625
999
  /* @__PURE__ */ jsx14(Text14, { bold: true, children: toolLabel(tool) }),
626
1000
  /* @__PURE__ */ jsx14(Text14, { children: ` ${target}` }),
627
1001
  display && !isDiff && !isTask ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ` (${display})` }) : null
628
1002
  ] }),
629
- sub?.length ? /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 3, children: [
1003
+ sub?.length ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 3, children: [
630
1004
  sub.slice(-6).map((s) => /* @__PURE__ */ jsx14(Text14, { dimColor: s.done && !s.isError, color: s.isError ? color("red") : void 0, children: `\u23BF ${toolLabel(s.tool)} ${s.target}` }, s.id)),
631
1005
  sub.length > 6 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} earlier steps", { n: sub.length - 6 }) }) : null
632
1006
  ] }) : null,
633
1007
  isTask && done ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : color("green"), children: `${isError ? t("\u2717 failed") : t("\u2713 done")}${display ? ` \xB7 ${display}` : ""}` }) }) : null,
634
- isDiff ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(DiffView, { diff: display }) }) : output && (isError || tool === "bash") && !(isTask && !isError) ? /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 3, children: [
1008
+ isDiff ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(DiffView, { diff: display }) }) : output && (isError || tool === "bash") && !(isTask && !isError) ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 3, children: [
635
1009
  shown.map((line, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: !isError, color: isError ? color("red") : void 0, children: line }, i)),
636
1010
  lines.length > shown.length ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} more lines (ctrl+o)", { n: lines.length - shown.length }) }) : null
637
1011
  ] }) : null
@@ -659,8 +1033,9 @@ function finishedCut(text) {
659
1033
  for (const line of lines.slice(0, -1)) {
660
1034
  if (TOOL_MARKUP.test(line)) break;
661
1035
  if (line.trimStart().startsWith("```")) inFence = !inFence;
1036
+ const tableRow = !inFence && !line.trimStart().startsWith("```") && line.includes("|") && line.trim() !== "";
662
1037
  pos += line.length + 1;
663
- if (!inFence) cut = pos - 1;
1038
+ if (!inFence && !tableRow) cut = pos - 1;
664
1039
  }
665
1040
  return cut;
666
1041
  }
@@ -725,7 +1100,7 @@ function applyEvent(t2, event) {
725
1100
  }
726
1101
 
727
1102
  // src/ui/App.tsx
728
- import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1103
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
729
1104
  function helpText(runtime) {
730
1105
  const custom = runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name));
731
1106
  return [
@@ -1317,7 +1692,7 @@ ${t2.output}`);
1317
1692
  const renderEntry = (e) => {
1318
1693
  switch (e.kind) {
1319
1694
  case "header":
1320
- return /* @__PURE__ */ jsx15(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs10(Text15, { children: [
1695
+ return /* @__PURE__ */ jsx15(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text15, { children: [
1321
1696
  /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), bold: true, children: " \u273B " }),
1322
1697
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: `BCCLI ${version}` }),
1323
1698
  /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: ` \xB7 ${runtime.modelRef} (${runtime.providerLabel()}) \xB7 ${cwd}` })
@@ -1329,7 +1704,7 @@ ${t2.output}`);
1329
1704
  return e.text ? /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Markdown, { text: e.text }) }, e.id) : null;
1330
1705
  }
1331
1706
  if (!e.text.trim()) return null;
1332
- return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, children: [
1707
+ return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, children: [
1333
1708
  /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), children: "\u25CF " }),
1334
1709
  /* @__PURE__ */ jsx15(Markdown, { text: e.text.replace(/^\s+/, "") })
1335
1710
  ] }, e.id);
@@ -1340,7 +1715,7 @@ ${t2.output}`);
1340
1715
  const lines = text.split("\n").length;
1341
1716
  return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking \xB7 {n} lines \xB7 ctrl+t to show", { n: lines }) }) }, e.id);
1342
1717
  }
1343
- return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, flexDirection: "column", children: [
1718
+ return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, flexDirection: "column", children: [
1344
1719
  /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking (ctrl+t to hide)") }),
1345
1720
  /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, italic: true, children: text }) })
1346
1721
  ] }, e.id);
@@ -1351,7 +1726,7 @@ ${t2.output}`);
1351
1726
  return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: e.tone === "error" ? color("red") : e.tone === "warn" ? color("yellow") : void 0, dimColor: e.tone === "info", children: e.text }) }, e.id);
1352
1727
  }
1353
1728
  };
1354
- return /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", children: [
1729
+ return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
1355
1730
  /* @__PURE__ */ jsx15(Static, { items: transcript.done, children: renderEntry }),
1356
1731
  transcript.live.map(renderEntry),
1357
1732
  busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: t("Thinking"), startedAt }) }) : null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.15",
3
+ "version": "0.4.0-beta.17",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {