@botconnector/bccli 0.4.0-beta.15 → 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/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.16" : "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-MESB34TF.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,111 @@ 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
+ function hanging(key, marker, body, width, padding = 0) {
555
+ const textWidth = Math.max(10, width - padding - displayWidth(marker) - 1);
556
+ return /* @__PURE__ */ jsxs(Box, { paddingLeft: padding, children: [
557
+ /* @__PURE__ */ jsx(Box, { flexShrink: 0, marginRight: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: marker }) }),
558
+ /* @__PURE__ */ jsx(Box, { width: textWidth, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { children: body }) })
559
+ ] }, key);
560
+ }
561
+ function Markdown({ text, indent = 2 }) {
562
+ const { stdout } = useStdout();
563
+ const width = Math.max(20, (stdout?.columns ?? 80) - indent - 1);
564
+ const lines = text.split("\n");
241
565
  const rows = [];
242
- text.split("\n").forEach((line, i) => {
566
+ let inCode = false;
567
+ let indents = [];
568
+ const depth = (spaces) => {
569
+ while (indents.length && spaces < indents.at(-1)) indents.pop();
570
+ if (!indents.length || spaces > indents.at(-1)) indents.push(spaces);
571
+ return indents.length - 1;
572
+ };
573
+ for (let i = 0; i < lines.length; i++) {
574
+ const line = lines[i];
243
575
  if (line.trimStart().startsWith("```")) {
244
576
  inCode = !inCode;
245
- return;
577
+ continue;
246
578
  }
247
- rows.push(
248
- inCode ? /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: ` ${line}` }, i) : /* @__PURE__ */ jsx(Text, { children: line ? inline(line) : " " }, i)
249
- );
250
- });
579
+ if (inCode) {
580
+ rows.push(
581
+ /* @__PURE__ */ jsx(Text, { color: color("cyan"), children: ` ${line}` }, i)
582
+ );
583
+ continue;
584
+ }
585
+ const parsed = parseTable(lines, i);
586
+ if (parsed) {
587
+ layoutTable(parsed.table, width).forEach((tableLine, n) => {
588
+ rows.push(/* @__PURE__ */ jsx(Text, { children: tableLine.length ? tableLine.map(segment) : " " }, `${i}-${n}`));
589
+ });
590
+ i = parsed.end - 1;
591
+ continue;
592
+ }
593
+ const heading = HEADING.exec(line);
594
+ if (heading) {
595
+ const level = heading[1].length;
596
+ rows.push(
597
+ /* @__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)
598
+ );
599
+ continue;
600
+ }
601
+ if (RULE.test(line)) {
602
+ rows.push(
603
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(Math.min(width, 80)) }, i)
604
+ );
605
+ continue;
606
+ }
607
+ const quote = QUOTE.exec(line);
608
+ if (quote) {
609
+ const depth2 = quote[1].replace(/\s/g, "").length;
610
+ rows.push(hanging(i, "\u258E".repeat(depth2), /* @__PURE__ */ jsx(Text, { italic: true, children: inline(quote[2]) }), width));
611
+ continue;
612
+ }
613
+ const bullet = BULLET.exec(line);
614
+ if (bullet) {
615
+ const padding = Math.min(bullet[1].replace(/\t/g, " ").length, 16);
616
+ const level = depth(padding);
617
+ const task = /^\[([ xX])\]\s+(.*)$/.exec(bullet[2]);
618
+ rows.push(
619
+ task ? hanging(i, task[1] === " " ? "\u2610" : "\u2611", inline(task[2]), width, padding) : hanging(i, BULLETS[Math.min(level, BULLETS.length - 1)], inline(bullet[2]), width, padding)
620
+ );
621
+ continue;
622
+ }
623
+ const numbered = NUMBERED.exec(line);
624
+ if (numbered) {
625
+ const padding = Math.min(numbered[1].replace(/\t/g, " ").length, 16);
626
+ depth(padding);
627
+ rows.push(hanging(i, `${numbered[2]}.`, inline(numbered[3]), width, padding));
628
+ continue;
629
+ }
630
+ if (line.trim()) indents = [];
631
+ rows.push(/* @__PURE__ */ jsx(Text, { children: line ? inline(line) : " " }, i));
632
+ }
251
633
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows });
252
634
  }
253
635
 
@@ -259,7 +641,7 @@ import { useState } from "react";
259
641
  var isFocusReport = (input) => input === "[I" || input === "[O";
260
642
 
261
643
  // src/ui/LinePrompt.tsx
262
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
644
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
263
645
  function LinePrompt({ label, mask, onSubmit, onCancel }) {
264
646
  const [value, setValue] = useState("");
265
647
  useInput((input, key) => {
@@ -269,7 +651,7 @@ function LinePrompt({ label, mask, onSubmit, onCancel }) {
269
651
  else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow && !isFocusReport(input)) setValue((v) => v + input.replace(/[\r\n]/g, ""));
270
652
  });
271
653
  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: [
654
+ return /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: /* @__PURE__ */ jsxs2(Text2, { children: [
273
655
  `${label}: `,
274
656
  shown,
275
657
  /* @__PURE__ */ jsx2(Text2, { inverse: true, children: " " }),
@@ -280,7 +662,7 @@ function LinePrompt({ label, mask, onSubmit, onCancel }) {
280
662
  // src/ui/ListPicker.tsx
281
663
  import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
282
664
  import { useState as useState2 } from "react";
283
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
665
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
284
666
  var VISIBLE = 12;
285
667
  function ListPicker({ title, items, onPick }) {
286
668
  const [filter, setFilter] = useState2("");
@@ -301,9 +683,9 @@ function ListPicker({ title, items, onPick }) {
301
683
  }
302
684
  });
303
685
  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: [
686
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
305
687
  /* @__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: [
688
+ 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
689
  `${start + i === cursor ? "\u203A" : " "} ${item.label}`,
308
690
  item.hint ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: ` ${item.hint}` }) : null
309
691
  ] }, item.id)),
@@ -314,7 +696,7 @@ function ListPicker({ title, items, onPick }) {
314
696
  // src/ui/ModelPicker.tsx
315
697
  import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
316
698
  import { useState as useState3 } from "react";
317
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
699
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
318
700
  var VISIBLE2 = 14;
319
701
  function ModelPicker({ groups, current, onPick }) {
320
702
  const [filter, setFilter] = useState3("");
@@ -346,7 +728,7 @@ function ModelPicker({ groups, current, onPick }) {
346
728
  }
347
729
  });
348
730
  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: [
731
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
350
732
  /* @__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
733
  rows.slice(start, start + VISIBLE2).map(
352
734
  (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 +741,7 @@ function ModelPicker({ groups, current, onPick }) {
359
741
  // src/ui/ProviderMenu.tsx
360
742
  import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
361
743
  import { useState as useState4 } from "react";
362
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
744
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
363
745
  function ProviderMenu({ entries, onPick }) {
364
746
  const rows = [...entries.map((e) => e.id), "custom"];
365
747
  const [index, setIndex] = useState4(0);
@@ -369,9 +751,9 @@ function ProviderMenu({ entries, onPick }) {
369
751
  else if (key.return) onPick(rows[index]);
370
752
  else if (key.escape) onPick(void 0);
371
753
  });
372
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
754
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
373
755
  /* @__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: [
756
+ entries.map((e, i) => /* @__PURE__ */ jsxs5(Text5, { color: i === index ? color("green") : void 0, children: [
375
757
  `${i === index ? "\u203A" : " "} ${e.ready ? "\u2713" : "\u25CB"} ${e.name}`,
376
758
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: ` ${e.baseURL}` })
377
759
  ] }, e.id)),
@@ -394,7 +776,7 @@ function DiffView({ diff }) {
394
776
  }
395
777
 
396
778
  // src/ui/PermissionPrompt.tsx
397
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
779
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
398
780
  var VERB = { edit: "edit", write: "write", bash: "run", fetch: "fetch" };
399
781
  function PermissionPrompt({
400
782
  request,
@@ -409,10 +791,10 @@ function PermissionPrompt({
409
791
  });
410
792
  const rules = request.sessionRules ?? [];
411
793
  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: [
794
+ return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
413
795
  /* @__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
796
  request.preview ? /* @__PURE__ */ jsx7(DiffView, { diff: request.preview }) : null,
415
- /* @__PURE__ */ jsxs5(Text7, { children: [
797
+ /* @__PURE__ */ jsxs6(Text7, { children: [
416
798
  /* @__PURE__ */ jsx7(Text7, { color: color("green"), children: t("[y] yes") }),
417
799
  " ",
418
800
  sessionLabel ? /* @__PURE__ */ jsx7(Text7, { color: color("cyan"), children: `[a] ${sessionLabel} ` }) : null,
@@ -440,7 +822,7 @@ function completeFile(value, cwd) {
440
822
  }
441
823
 
442
824
  // src/ui/PromptInput.tsx
443
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
825
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
444
826
  function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
445
827
  const [value, setValue] = useState5("");
446
828
  const [historyIndex, setHistoryIndex] = useState5(null);
@@ -514,8 +896,8 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
514
896
  },
515
897
  { isActive: !disabled }
516
898
  );
517
- return /* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", children: [
518
- /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs6(Text8, { children: [
899
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
900
+ /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs7(Text8, { children: [
519
901
  /* @__PURE__ */ jsx8(Text8, { color: color("green"), children: "> " }),
520
902
  value,
521
903
  disabled ? "" : /* @__PURE__ */ jsx8(Text8, { inverse: true, children: " " })
@@ -559,7 +941,7 @@ function StatusBar({ mode, tokens, busy, model, reasoning = "auto" }) {
559
941
  // src/ui/McpMenu.tsx
560
942
  import { Box as Box9, Text as Text11, useInput as useInput7 } from "ink";
561
943
  import { useState as useState7 } from "react";
562
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
944
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
563
945
  var MARK = { ready: "\u2713", error: "\u2717", starting: "\u2026", off: "\u25CB" };
564
946
  function McpMenu({ items, onPick }) {
565
947
  const [index, setIndex] = useState7(0);
@@ -569,9 +951,9 @@ function McpMenu({ items, onPick }) {
569
951
  else if (key.return) onPick(items[index]?.name);
570
952
  else if (key.escape) onPick(void 0);
571
953
  });
572
- return /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
954
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
573
955
  /* @__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: [
956
+ items.map((item, i) => /* @__PURE__ */ jsxs8(Text11, { color: i === index ? color("green") : void 0, children: [
575
957
  `${i === index ? "\u203A" : " "} ${MARK[item.status]} ${item.name.padEnd(12)}`,
576
958
  /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: item.status === "error" ? ` ${item.error ?? ""}` : ` ${item.description}` })
577
959
  ] }, item.name))
@@ -580,7 +962,7 @@ function McpMenu({ items, onPick }) {
580
962
 
581
963
  // src/ui/PlanApproval.tsx
582
964
  import { Box as Box10, Text as Text12, useInput as useInput8 } from "ink";
583
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
965
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
584
966
  function PlanApproval({ plan, onAnswer }) {
585
967
  useInput8((input, key) => {
586
968
  const k2 = input.toLowerCase();
@@ -588,10 +970,10 @@ function PlanApproval({ plan, onAnswer }) {
588
970
  else if (k2 === "y") onAnswer("default");
589
971
  else if (k2 === "n" || key.escape) onAnswer("no");
590
972
  });
591
- return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
973
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
592
974
  /* @__PURE__ */ jsx12(Text12, { bold: true, children: t("Plan from the agent") }),
593
- /* @__PURE__ */ jsx12(Markdown, { text: plan }),
594
- /* @__PURE__ */ jsxs8(Text12, { children: [
975
+ /* @__PURE__ */ jsx12(Markdown, { text: plan, indent: 5 }),
976
+ /* @__PURE__ */ jsxs9(Text12, { children: [
595
977
  /* @__PURE__ */ jsx12(Text12, { color: color("green"), children: t("[a] yes, auto-edit") }),
596
978
  " ",
597
979
  /* @__PURE__ */ jsx12(Text12, { color: color("cyan"), children: t("[y] yes, ask at each step") }),
@@ -612,26 +994,26 @@ function TodoList({ items }) {
612
994
 
613
995
  // src/ui/ToolBlock.tsx
614
996
  import { Box as Box12, Text as Text14 } from "ink";
615
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
997
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
616
998
  var PREVIEW_LINES = 5;
617
999
  function ToolBlock({ tool, target, output, display, isError, done, expanded, sub }) {
618
1000
  const isTask = tool === "task";
619
1001
  const isDiff = !!display && /^\s*\d+ [+\- ] /.test(display);
620
1002
  const lines = (output ?? "").split("\n");
621
1003
  const shown = expanded ? lines : lines.slice(0, PREVIEW_LINES);
622
- return /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 2, children: [
623
- /* @__PURE__ */ jsxs9(Text14, { children: [
1004
+ return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 2, children: [
1005
+ /* @__PURE__ */ jsxs10(Text14, { children: [
624
1006
  /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : done ? color("green") : color("yellow"), children: "\u23BF " }),
625
1007
  /* @__PURE__ */ jsx14(Text14, { bold: true, children: toolLabel(tool) }),
626
1008
  /* @__PURE__ */ jsx14(Text14, { children: ` ${target}` }),
627
1009
  display && !isDiff && !isTask ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ` (${display})` }) : null
628
1010
  ] }),
629
- sub?.length ? /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 3, children: [
1011
+ sub?.length ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 3, children: [
630
1012
  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
1013
  sub.length > 6 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} earlier steps", { n: sub.length - 6 }) }) : null
632
1014
  ] }) : null,
633
1015
  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: [
1016
+ 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
1017
  shown.map((line, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: !isError, color: isError ? color("red") : void 0, children: line }, i)),
636
1018
  lines.length > shown.length ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} more lines (ctrl+o)", { n: lines.length - shown.length }) }) : null
637
1019
  ] }) : null
@@ -659,8 +1041,9 @@ function finishedCut(text) {
659
1041
  for (const line of lines.slice(0, -1)) {
660
1042
  if (TOOL_MARKUP.test(line)) break;
661
1043
  if (line.trimStart().startsWith("```")) inFence = !inFence;
1044
+ const tableRow = !inFence && !line.trimStart().startsWith("```") && line.includes("|") && line.trim() !== "";
662
1045
  pos += line.length + 1;
663
- if (!inFence) cut = pos - 1;
1046
+ if (!inFence && !tableRow) cut = pos - 1;
664
1047
  }
665
1048
  return cut;
666
1049
  }
@@ -725,7 +1108,7 @@ function applyEvent(t2, event) {
725
1108
  }
726
1109
 
727
1110
  // src/ui/App.tsx
728
- import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1111
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
729
1112
  function helpText(runtime) {
730
1113
  const custom = runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name));
731
1114
  return [
@@ -1317,7 +1700,7 @@ ${t2.output}`);
1317
1700
  const renderEntry = (e) => {
1318
1701
  switch (e.kind) {
1319
1702
  case "header":
1320
- return /* @__PURE__ */ jsx15(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs10(Text15, { children: [
1703
+ return /* @__PURE__ */ jsx15(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text15, { children: [
1321
1704
  /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), bold: true, children: " \u273B " }),
1322
1705
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: `BCCLI ${version}` }),
1323
1706
  /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: ` \xB7 ${runtime.modelRef} (${runtime.providerLabel()}) \xB7 ${cwd}` })
@@ -1329,7 +1712,7 @@ ${t2.output}`);
1329
1712
  return e.text ? /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Markdown, { text: e.text }) }, e.id) : null;
1330
1713
  }
1331
1714
  if (!e.text.trim()) return null;
1332
- return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, children: [
1715
+ return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, children: [
1333
1716
  /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), children: "\u25CF " }),
1334
1717
  /* @__PURE__ */ jsx15(Markdown, { text: e.text.replace(/^\s+/, "") })
1335
1718
  ] }, e.id);
@@ -1340,7 +1723,7 @@ ${t2.output}`);
1340
1723
  const lines = text.split("\n").length;
1341
1724
  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
1725
  }
1343
- return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, flexDirection: "column", children: [
1726
+ return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, flexDirection: "column", children: [
1344
1727
  /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking (ctrl+t to hide)") }),
1345
1728
  /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, italic: true, children: text }) })
1346
1729
  ] }, e.id);
@@ -1351,7 +1734,7 @@ ${t2.output}`);
1351
1734
  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
1735
  }
1353
1736
  };
1354
- return /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", children: [
1737
+ return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
1355
1738
  /* @__PURE__ */ jsx15(Static, { items: transcript.done, children: renderEntry }),
1356
1739
  transcript.live.map(renderEntry),
1357
1740
  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.16",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {