@wrongstack/tui 0.7.0 → 0.7.3

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/index.js CHANGED
@@ -313,6 +313,667 @@ function FleetPanel({ entries, totalCost, roster }) {
313
313
  }
314
314
  );
315
315
  }
316
+ function StatusBar({
317
+ model,
318
+ version,
319
+ state,
320
+ tokenCounter,
321
+ hint,
322
+ queueCount = 0,
323
+ yolo = false,
324
+ autonomy,
325
+ elapsedMs,
326
+ todos,
327
+ plan,
328
+ fleet,
329
+ fleetAgents,
330
+ git,
331
+ subagentCount = 0,
332
+ context,
333
+ projectName,
334
+ processCount,
335
+ hiddenItems,
336
+ eternalStage,
337
+ goalSummary
338
+ }) {
339
+ const hiddenSet = new Set(hiddenItems);
340
+ const usage = tokenCounter?.total();
341
+ const cost = tokenCounter?.estimateCost();
342
+ const cache2 = tokenCounter?.cacheStats();
343
+ const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
344
+ const hasSecondLine = yolo || autonomy && autonomy !== "off" || elapsedMs !== void 0 || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0;
345
+ const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
346
+ const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity;
347
+ return /* @__PURE__ */ jsxs(
348
+ Box,
349
+ {
350
+ flexDirection: "column",
351
+ paddingX: 1,
352
+ borderStyle: "single",
353
+ borderTop: true,
354
+ borderBottom: false,
355
+ borderLeft: false,
356
+ borderRight: false,
357
+ children: [
358
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
359
+ version ? /* @__PURE__ */ jsxs(Fragment, { children: [
360
+ /* @__PURE__ */ jsxs(Text, { children: [
361
+ /* @__PURE__ */ jsx(Text, { color: "blue", bold: true, children: "WS" }),
362
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
363
+ " v",
364
+ version
365
+ ] })
366
+ ] }),
367
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" })
368
+ ] }) : null,
369
+ /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
370
+ "\u25CF ",
371
+ stateLabel
372
+ ] }),
373
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
374
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: model }),
375
+ context && context.max > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
376
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
377
+ /* @__PURE__ */ jsx(ContextChip, { ctx: context })
378
+ ] }) : null,
379
+ usage ? /* @__PURE__ */ jsxs(Fragment, { children: [
380
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
381
+ /* @__PURE__ */ jsxs(Text, { children: [
382
+ "\u2191",
383
+ " ",
384
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: fmtTok(usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0)) }),
385
+ " ",
386
+ "\u2193 ",
387
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: fmtTok(usage.output) })
388
+ ] })
389
+ ] }) : null,
390
+ cache2 && cache2.hitRatio > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
391
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
392
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
393
+ "cache ",
394
+ (cache2.hitRatio * 100).toFixed(0),
395
+ "%"
396
+ ] })
397
+ ] }) : null,
398
+ cost && cost.total > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
399
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
400
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
401
+ "$",
402
+ cost.total.toFixed(4)
403
+ ] })
404
+ ] }) : null,
405
+ queueCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
406
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
407
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
408
+ "\u231B queued: ",
409
+ queueCount
410
+ ] })
411
+ ] }) : null,
412
+ typeof processCount === "number" && processCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
413
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
414
+ /* @__PURE__ */ jsxs(Text, { color: "red", children: [
415
+ "\u26A1 ",
416
+ processCount,
417
+ " process",
418
+ processCount === 1 ? "" : "es"
419
+ ] })
420
+ ] }) : null,
421
+ hint ? /* @__PURE__ */ jsxs(Fragment, { children: [
422
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
423
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
424
+ ] }) : null
425
+ ] }),
426
+ hasSecondLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
427
+ yolo ? /* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "\u26A0 YOLO" }) : null,
428
+ autonomy && autonomy !== "off" ? /* @__PURE__ */ jsxs(Fragment, { children: [
429
+ yolo ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
430
+ /* @__PURE__ */ jsxs(
431
+ Text,
432
+ {
433
+ color: autonomy === "eternal" ? "red" : autonomy === "auto" ? "yellow" : "cyan",
434
+ bold: true,
435
+ children: [
436
+ "\u221E ",
437
+ autonomy.toUpperCase()
438
+ ]
439
+ }
440
+ )
441
+ ] }) : null,
442
+ eternalStage ? /* @__PURE__ */ jsxs(Fragment, { children: [
443
+ yolo || autonomy && autonomy !== "off" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
444
+ /* @__PURE__ */ jsx(EternalStageChip, { stage: eternalStage })
445
+ ] }) : null,
446
+ elapsedMs !== void 0 && !hiddenSet.has("elapsed") ? /* @__PURE__ */ jsxs(Fragment, { children: [
447
+ yolo || autonomy && autonomy !== "off" || eternalStage ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
448
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
449
+ "\u23F1 ",
450
+ fmtElapsed(elapsedMs)
451
+ ] })
452
+ ] }) : null,
453
+ projectName ? /* @__PURE__ */ jsxs(Fragment, { children: [
454
+ yolo || elapsedMs !== void 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
455
+ /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
456
+ "\u{1F4C1} ",
457
+ projectName
458
+ ] })
459
+ ] }) : null,
460
+ goalSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
461
+ yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
462
+ /* @__PURE__ */ jsxs(Text, { color: goalSummary.goalState === "active" ? "green" : goalSummary.goalState === "paused" ? "yellow" : goalSummary.goalState === "completed" ? "green" : "dim", children: [
463
+ "\u{1F3AF} ",
464
+ goalSummary.goal.length > 40 ? `${goalSummary.goal.slice(0, 37)}\u2026` : goalSummary.goal,
465
+ " [",
466
+ goalSummary.goalState,
467
+ "] (iter ",
468
+ goalSummary.iterations,
469
+ ")"
470
+ ] })
471
+ ] }) : null,
472
+ git ? /* @__PURE__ */ jsxs(Fragment, { children: [
473
+ yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
474
+ /* @__PURE__ */ jsxs(Text, { children: [
475
+ /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
476
+ "\u2387 ",
477
+ git.branch
478
+ ] }),
479
+ git.added > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
480
+ " +",
481
+ git.added
482
+ ] }) : null,
483
+ git.deleted > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
484
+ " -",
485
+ git.deleted
486
+ ] }) : null,
487
+ git.untracked > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
488
+ " ?",
489
+ git.untracked
490
+ ] }) : null
491
+ ] })
492
+ ] }) : null
493
+ ] }) : null,
494
+ hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
495
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsxs(Text, { children: [
496
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
497
+ todos.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
498
+ "\u231B",
499
+ todos.inProgress
500
+ ] }) : null,
501
+ todos.inProgress > 0 && (todos.pending > 0 || todos.completed > 0) ? " " : "",
502
+ todos.pending > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
503
+ "\u2610",
504
+ todos.pending
505
+ ] }) : null,
506
+ todos.pending > 0 && todos.completed > 0 ? " " : "",
507
+ todos.completed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
508
+ "\u2713",
509
+ todos.completed
510
+ ] }) : null
511
+ ] }) : null,
512
+ plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsxs(Fragment, { children: [
513
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
514
+ /* @__PURE__ */ jsxs(Text, { children: [
515
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u{1F4CB} " }),
516
+ plan.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
517
+ "\u231B",
518
+ plan.inProgress
519
+ ] }) : null,
520
+ plan.inProgress > 0 && (plan.open > 0 || plan.done > 0) ? " " : "",
521
+ plan.open > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
522
+ "\u2610",
523
+ plan.open
524
+ ] }) : null,
525
+ plan.open > 0 && plan.done > 0 ? " " : "",
526
+ plan.done > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
527
+ "\u2713",
528
+ plan.done
529
+ ] }) : null
530
+ ] })
531
+ ] }) : null,
532
+ fleetHasActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
533
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
534
+ fleet ? /* @__PURE__ */ jsxs(Text, { children: [
535
+ /* @__PURE__ */ jsx(Text, { color: "blue", children: "\u{1F310} " }),
536
+ fleet.running > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
537
+ "\u25B6",
538
+ fleet.running
539
+ ] }) : null,
540
+ fleet.running > 0 && (fleet.pending > 0 || fleet.idle > 0 || fleet.completed > 0) ? " " : "",
541
+ fleet.pending > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
542
+ "\u2610",
543
+ fleet.pending
544
+ ] }) : null,
545
+ fleet.pending > 0 && (fleet.idle > 0 || fleet.completed > 0) ? " " : "",
546
+ fleet.idle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
547
+ "\xB7",
548
+ fleet.idle,
549
+ "idle"
550
+ ] }) : null,
551
+ fleet.idle > 0 && fleet.completed > 0 ? " " : "",
552
+ fleet.completed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
553
+ "\u2713",
554
+ fleet.completed
555
+ ] }) : null
556
+ ] }) : /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
557
+ "\u{1F310} ",
558
+ subagentCount,
559
+ " agent",
560
+ subagentCount === 1 ? "" : "s"
561
+ ] })
562
+ ] }) : null
563
+ ] }) : null,
564
+ fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
565
+ // biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
566
+ /* @__PURE__ */ jsxs(Text, { children: [
567
+ /* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
568
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
569
+ /* @__PURE__ */ jsx(Text, { color: a.running ? "yellow" : void 0, dimColor: !a.running, children: a.running ? "\u25B6" : "\xB7" }),
570
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
571
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed(a.elapsedMs) }),
572
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
573
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
574
+ a.toolCalls,
575
+ "t"
576
+ ] }),
577
+ a.tool ? /* @__PURE__ */ jsxs(Fragment, { children: [
578
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
579
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: a.tool })
580
+ ] }) : null,
581
+ a.extensions && a.extensions > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
582
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
583
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
584
+ "\u26A1\xD7",
585
+ a.extensions
586
+ ] })
587
+ ] }) : null
588
+ ] }, i)
589
+ )) }) : null
590
+ ]
591
+ }
592
+ );
593
+ }
594
+ function EternalStageChip({
595
+ stage
596
+ }) {
597
+ switch (stage.phase) {
598
+ case "idle":
599
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2B1C idle" });
600
+ case "decide":
601
+ return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
602
+ "\u2B07 decide: ",
603
+ stage.reason
604
+ ] });
605
+ case "execute":
606
+ return /* @__PURE__ */ jsxs(Text, { color: "green", children: [
607
+ "\u25B6 ",
608
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "execute" }),
609
+ stage.task ? `(${stage.task})` : ""
610
+ ] });
611
+ case "reflect":
612
+ return /* @__PURE__ */ jsxs(Text, { color: stage.status === "success" ? "green" : stage.status === "failure" ? "red" : "yellow", children: [
613
+ "\u21A9 reflect: ",
614
+ stage.status
615
+ ] });
616
+ case "sleep":
617
+ return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
618
+ "\u{1F4A4} sleep ",
619
+ Math.round(stage.ms / 1e3),
620
+ "s"
621
+ ] });
622
+ case "paused":
623
+ return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u23F8 paused" });
624
+ case "stopped":
625
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25A0 stopped" });
626
+ case "error":
627
+ return /* @__PURE__ */ jsxs(Text, { color: "red", children: [
628
+ "\u26A0 error: ",
629
+ stage.message
630
+ ] });
631
+ }
632
+ }
633
+ function ContextChip({ ctx }) {
634
+ const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
635
+ const pct = Math.round(ratio * 100);
636
+ const color = ratio >= 0.85 ? "red" : ratio >= 0.65 ? "yellow" : "cyan";
637
+ return /* @__PURE__ */ jsxs(Text, { children: [
638
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "ctx " }),
639
+ /* @__PURE__ */ jsx(Text, { color, children: renderProgress(ratio, 10) }),
640
+ /* @__PURE__ */ jsxs(Text, { color, children: [
641
+ " ",
642
+ pct,
643
+ "%"
644
+ ] }),
645
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
646
+ " ",
647
+ "(",
648
+ fmtTok(ctx.used),
649
+ "/",
650
+ fmtTok(ctx.max),
651
+ ")"
652
+ ] })
653
+ ] });
654
+ }
655
+ function stateChip(state, fleetRunning) {
656
+ if (state === "idle" && fleetRunning > 0) {
657
+ return { label: `agents \u25B6${fleetRunning}`, color: "magenta" };
658
+ }
659
+ if (state === "idle") return { label: "idle", color: "cyan" };
660
+ if (state === "aborting") return { label: "aborting\u2026", color: "yellow" };
661
+ return { label: "thinking\u2026", color: "green" };
662
+ }
663
+ var FILLED = "\u2588";
664
+ var EMPTY = "\u2591";
665
+ function renderProgress(ratio, width) {
666
+ const clamped = Math.max(0, Math.min(1, ratio));
667
+ const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
668
+ const capped = Math.min(width, filled);
669
+ return FILLED.repeat(capped) + EMPTY.repeat(width - capped);
670
+ }
671
+ function fmtTok(n) {
672
+ if (n < 1e3) return String(n);
673
+ if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 1 : 0)}k`;
674
+ return `${(n / 1e6).toFixed(1)}M`;
675
+ }
676
+ function fmtElapsed(ms) {
677
+ const totalSec = Math.floor(ms / 1e3);
678
+ const h = Math.floor(totalSec / 3600);
679
+ const m = Math.floor(totalSec % 3600 / 60);
680
+ const s = totalSec % 60;
681
+ if (h > 0) {
682
+ return `${h}:${pad2(m)}:${pad2(s)}`;
683
+ }
684
+ return `${pad2(m)}:${pad2(s)}`;
685
+ }
686
+ function pad2(n) {
687
+ return n < 10 ? `0${n}` : String(n);
688
+ }
689
+ var STATUS = {
690
+ idle: { icon: "\u25CB", color: "gray" },
691
+ running: { icon: "\u25B6", color: "yellow" },
692
+ success: { icon: "\u2713", color: "green" },
693
+ failed: { icon: "\u2717", color: "red" },
694
+ timeout: { icon: "\u23F1", color: "yellow" },
695
+ stopped: { icon: "\u2298", color: "gray" }
696
+ };
697
+ var SPARK = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
698
+ function bucketActivity(recentTools, now, bins = 12, binMs = 2e3) {
699
+ const out = new Array(bins).fill(0);
700
+ const windowStart = now - bins * binMs;
701
+ for (const t of recentTools) {
702
+ if (t.at < windowStart || t.at > now) continue;
703
+ let idx = Math.floor((t.at - windowStart) / binMs);
704
+ if (idx < 0) idx = 0;
705
+ if (idx >= bins) idx = bins - 1;
706
+ out[idx]++;
707
+ }
708
+ return out;
709
+ }
710
+ function sparkline(values) {
711
+ if (values.length === 0) return "";
712
+ const max = Math.max(1, ...values);
713
+ return values.map((v) => {
714
+ if (v <= 0) return SPARK[0];
715
+ const idx = Math.min(SPARK.length - 1, Math.ceil(v / max * (SPARK.length - 1)));
716
+ return SPARK[idx];
717
+ }).join("");
718
+ }
719
+ function fmtTokens(n) {
720
+ if (n < 1e3) return String(n);
721
+ if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
722
+ return `${(n / 1e6).toFixed(1)}M`;
723
+ }
724
+ function FleetMonitor({
725
+ entries,
726
+ totalCost,
727
+ totalTokens,
728
+ maxConcurrent = 4,
729
+ nowTick
730
+ }) {
731
+ const all = Object.values(entries);
732
+ const running = all.filter((e) => e.status === "running");
733
+ const done = all.filter((e) => e.status === "success").length;
734
+ const failed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
735
+ const concurrencyRatio = maxConcurrent > 0 ? running.length / maxConcurrent : 0;
736
+ const maxTools = Math.max(1, ...all.map((e) => e.toolCalls));
737
+ const ordered = [...all].sort((a, b) => {
738
+ const ra = a.status === "running" ? 0 : a.status === "idle" ? 1 : 2;
739
+ const rb = b.status === "running" ? 0 : b.status === "idle" ? 1 : 2;
740
+ if (ra !== rb) return ra - rb;
741
+ return a.startedAt - b.startedAt;
742
+ });
743
+ const shown = ordered.slice(0, 8);
744
+ const events = [];
745
+ for (const e of all) {
746
+ events.push({ at: e.startedAt, icon: "\u25CF", color: "cyan", text: `${e.name} spawned` });
747
+ if (e.status !== "running" && e.status !== "idle") {
748
+ const s = STATUS[e.status];
749
+ events.push({
750
+ at: e.lastEventAt,
751
+ icon: s.icon,
752
+ color: s.color,
753
+ text: `${e.name} ${e.status} (${e.toolCalls}t)`
754
+ });
755
+ }
756
+ if (e.budgetWarning) {
757
+ events.push({
758
+ at: e.budgetWarning.at,
759
+ icon: "\u26A1",
760
+ color: "yellow",
761
+ text: `${e.name} ${e.budgetWarning.kind} ${e.budgetWarning.used}/${e.budgetWarning.limit} \u2014 extending`
762
+ });
763
+ }
764
+ }
765
+ events.sort((a, b) => b.at - a.at);
766
+ const timeline = events.slice(0, 6);
767
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
768
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
769
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "FLEET MONITOR" }),
770
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
771
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
772
+ "\u25B6",
773
+ running.length
774
+ ] }),
775
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
776
+ "\u2713",
777
+ done
778
+ ] }),
779
+ failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
780
+ "\u2717",
781
+ failed
782
+ ] }) : null,
783
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+F to close" })
784
+ ] }),
785
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
786
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "concurrency" }),
787
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
788
+ "[",
789
+ renderProgress(concurrencyRatio, 10),
790
+ "]"
791
+ ] }),
792
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
793
+ running.length,
794
+ "/",
795
+ maxConcurrent
796
+ ] }),
797
+ totalTokens ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
798
+ " ",
799
+ fmtTokens(totalTokens.input),
800
+ "\u2191 ",
801
+ fmtTokens(totalTokens.output),
802
+ "\u2193"
803
+ ] }) : null,
804
+ /* @__PURE__ */ jsx(Text, { color: "green", children: ` $${totalCost.toFixed(3)}` })
805
+ ] }),
806
+ shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No subagents yet \u2014 spawn with /fleet spawn or /fleet dispatch." }) : null,
807
+ shown.map((e) => {
808
+ const s = STATUS[e.status];
809
+ const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : e.status;
810
+ const spark = sparkline(bucketActivity(e.recentTools, nowTick));
811
+ const tool = e.currentTool?.name ?? e.recentTools[e.recentTools.length - 1]?.name ?? "";
812
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
813
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
814
+ /* @__PURE__ */ jsx(Text, { color: s.color, bold: true, children: s.icon }),
815
+ /* @__PURE__ */ jsx(Text, { bold: true, children: e.name.padEnd(12).slice(0, 12) }),
816
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(7).slice(0, 7) }),
817
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: renderProgress(e.toolCalls / maxTools, 10) }),
818
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
819
+ "L",
820
+ e.iterations,
821
+ " ",
822
+ e.toolCalls,
823
+ "t"
824
+ ] }),
825
+ e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
826
+ "\u26A1\xD7",
827
+ e.extensions
828
+ ] }) : null
829
+ ] }),
830
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
831
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
832
+ /* @__PURE__ */ jsx(Text, { color: "green", children: spark }),
833
+ tool ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: tool }) : null
834
+ ] })
835
+ ] }, e.id);
836
+ }),
837
+ timeline.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
838
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "timeline" }),
839
+ timeline.map((ev, i) => (
840
+ // biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
841
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
842
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
843
+ /* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
844
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
845
+ ] }, i)
846
+ ))
847
+ ] }) : null
848
+ ] });
849
+ }
850
+ var STATUS2 = {
851
+ idle: { icon: "\u25CB", color: "gray" },
852
+ running: { icon: "\u25B6", color: "yellow" },
853
+ success: { icon: "\u2713", color: "green" },
854
+ failed: { icon: "\u2717", color: "red" },
855
+ timeout: { icon: "\u23F1", color: "yellow" },
856
+ stopped: { icon: "\u2298", color: "gray" }
857
+ };
858
+ function fmtTokens2(n) {
859
+ if (n < 1e3) return String(n);
860
+ if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
861
+ return `${(n / 1e6).toFixed(1)}M`;
862
+ }
863
+ function AgentsMonitor({
864
+ entries,
865
+ totalCost,
866
+ totalTokens,
867
+ nowTick
868
+ }) {
869
+ const all = Object.values(entries);
870
+ const running = all.filter((e) => e.status === "running");
871
+ const done = all.filter((e) => e.status === "success").length;
872
+ const failed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
873
+ const maxTools = Math.max(1, ...all.map((e) => e.toolCalls));
874
+ const ordered = [...all].sort((a, b) => {
875
+ const ra = a.status === "running" ? 0 : a.status === "idle" ? 1 : 2;
876
+ const rb = b.status === "running" ? 0 : b.status === "idle" ? 1 : 2;
877
+ if (ra !== rb) return ra - rb;
878
+ return a.startedAt - b.startedAt;
879
+ });
880
+ const shown = ordered.slice(0, 20);
881
+ const events = [];
882
+ for (const e of all) {
883
+ events.push({ at: e.startedAt, icon: "\u25CF", color: "cyan", text: `${e.name} spawned` });
884
+ if (e.status !== "running" && e.status !== "idle") {
885
+ const s = STATUS2[e.status];
886
+ events.push({
887
+ at: e.lastEventAt,
888
+ icon: s.icon,
889
+ color: s.color,
890
+ text: `${e.name} ${e.status} (${e.toolCalls}t)`
891
+ });
892
+ }
893
+ if (e.budgetWarning) {
894
+ events.push({
895
+ at: e.budgetWarning.at,
896
+ icon: "\u26A1",
897
+ color: "yellow",
898
+ text: `${e.name} ${e.budgetWarning.kind} ${e.budgetWarning.used}/${e.budgetWarning.limit} \u2014 extending`
899
+ });
900
+ }
901
+ }
902
+ events.sort((a, b) => b.at - a.at);
903
+ const timeline = events.slice(0, 6);
904
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
905
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
906
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "AGENTS MONITOR" }),
907
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
908
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
909
+ "\u25B6",
910
+ running.length
911
+ ] }),
912
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
913
+ "\u2713",
914
+ done
915
+ ] }),
916
+ failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
917
+ "\u2717",
918
+ failed
919
+ ] }) : null,
920
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+Shift+M to close" })
921
+ ] }),
922
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
923
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "agents" }),
924
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: all.length }),
925
+ totalTokens ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
926
+ fmtTokens2(totalTokens.input),
927
+ "\u2191 ",
928
+ fmtTokens2(totalTokens.output),
929
+ "\u2193"
930
+ ] }) : null,
931
+ /* @__PURE__ */ jsx(Text, { color: "green", children: ` $${totalCost.toFixed(3)}` })
932
+ ] }),
933
+ shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No subagents yet \u2014 spawn with /spawn or /fleet dispatch." }) : null,
934
+ shown.map((e) => {
935
+ const s = STATUS2[e.status];
936
+ const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : e.status;
937
+ const spark = sparkline(bucketActivity(e.recentTools, nowTick));
938
+ const tool = e.currentTool?.name ?? e.recentTools[e.recentTools.length - 1]?.name ?? "";
939
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
940
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
941
+ /* @__PURE__ */ jsx(Text, { color: s.color, bold: true, children: s.icon }),
942
+ /* @__PURE__ */ jsx(Text, { bold: true, children: e.name.padEnd(14).slice(0, 14) }),
943
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(8).slice(0, 8) }),
944
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: renderProgress(e.toolCalls / maxTools, 10) }),
945
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
946
+ "L",
947
+ e.iterations,
948
+ " ",
949
+ e.toolCalls,
950
+ "t"
951
+ ] }),
952
+ e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
953
+ "\u26A1\xD7",
954
+ e.extensions
955
+ ] }) : null
956
+ ] }),
957
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
958
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
959
+ /* @__PURE__ */ jsx(Text, { color: "green", children: spark }),
960
+ tool ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: tool }) : null
961
+ ] })
962
+ ] }, e.id);
963
+ }),
964
+ timeline.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
965
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "timeline" }),
966
+ timeline.map((ev, i) => (
967
+ // biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
968
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
969
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
970
+ /* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
971
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
972
+ ] }, i)
973
+ ))
974
+ ] }) : null
975
+ ] });
976
+ }
316
977
 
317
978
  // src/markdown-table.ts
318
979
  function renderMarkdownTables(text, maxWidth) {
@@ -602,10 +1263,16 @@ function Entry({
602
1263
  switch (entry.kind) {
603
1264
  case "user":
604
1265
  return /* @__PURE__ */ jsxs(Text, { children: [
605
- /* @__PURE__ */ jsx(Text, { color: entry.queued ? "yellow" : "cyan", children: entry.queued ? "\u231B" : "\u203A" }),
606
- " ",
607
- /* @__PURE__ */ jsx(Text, { dimColor: entry.queued ?? false, children: entry.text }),
608
- entry.queued ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (queued)" }) : null
1266
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "USER: " }),
1267
+ /* @__PURE__ */ jsx(Text, { color: "white", children: entry.text }),
1268
+ entry.queued ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (queued)" }) : null,
1269
+ entry.pasteContent ? /* @__PURE__ */ jsxs(Fragment, { children: [
1270
+ entry.text ? "\n" : null,
1271
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1272
+ " \u21B3 ",
1273
+ entry.pasteContent
1274
+ ] })
1275
+ ] }) : null
609
1276
  ] });
610
1277
  case "assistant":
611
1278
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
@@ -632,7 +1299,7 @@ function Entry({
632
1299
  parts.push(fmtBytes2(entry.outputBytes));
633
1300
  }
634
1301
  if (entry.outputTokens && entry.outputTokens > 0) {
635
- parts.push(`\u2248${fmtTok(entry.outputTokens)} tok`);
1302
+ parts.push(`\u2248${fmtTok2(entry.outputTokens)} tok`);
636
1303
  }
637
1304
  return parts.join(" \xB7 ");
638
1305
  })();
@@ -751,7 +1418,7 @@ function shortenPath(p, max) {
751
1418
  if (p.length <= max) return p;
752
1419
  return `\u2026${p.slice(p.length - (max - 1))}`;
753
1420
  }
754
- function fmtTok(n) {
1421
+ function fmtTok2(n) {
755
1422
  if (!Number.isFinite(n) || n <= 0) return "0";
756
1423
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
757
1424
  if (n >= 1e3) return `${(n / 1e3).toFixed(n >= 1e4 ? 0 : 1)}k`;
@@ -1361,623 +2028,279 @@ function parseUnifiedDiff(diff, maxLines) {
1361
2028
  function stringOf(v) {
1362
2029
  return typeof v === "string" && v.length > 0 ? v : void 0;
1363
2030
  }
1364
- function numOf(v) {
1365
- return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1366
- }
1367
- function tryParseJson(s) {
1368
- const t = s.trimStart();
1369
- if (!t.startsWith("{") && !t.startsWith("[")) return void 0;
1370
- try {
1371
- return JSON.parse(s);
1372
- } catch {
1373
- return void 0;
1374
- }
1375
- }
1376
- function scanNumberedRange(text) {
1377
- let first;
1378
- let last;
1379
- let count = 0;
1380
- for (const line of text.split("\n")) {
1381
- const m = line.match(/^\s*(\d+)→/);
1382
- if (m?.[1]) {
1383
- const n = Number.parseInt(m[1], 10);
1384
- if (Number.isFinite(n)) {
1385
- if (first === void 0) first = n;
1386
- last = n;
1387
- count++;
1388
- }
1389
- }
1390
- }
1391
- return { first, last, count };
1392
- }
1393
- function countLines(text) {
1394
- if (!text) return 0;
1395
- return text.replace(/\n$/, "").split("\n").length;
1396
- }
1397
- function fmtBytes2(n) {
1398
- if (n < 1024) return `${n}B`;
1399
- if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
1400
- return `${(n / (1024 * 1024)).toFixed(1)}MB`;
1401
- }
1402
- function truncMid(s, max) {
1403
- if (s.length <= max) return s;
1404
- return `${s.slice(0, max - 1)}\u2026`;
1405
- }
1406
- function isHomeEnd(data) {
1407
- if (data === "\x1B[H" || data === "\x1B[1~" || data === "\x1BOH" || data === "\x1B[7~")
1408
- return "home";
1409
- if (data === "\x1B[F" || data === "\x1B[4~" || data === "\x1BOF" || data === "\x1B[8~")
1410
- return "end";
1411
- return null;
1412
- }
1413
- var EMPTY_KEY = {
1414
- upArrow: false,
1415
- downArrow: false,
1416
- leftArrow: false,
1417
- rightArrow: false,
1418
- return: false,
1419
- escape: false,
1420
- ctrl: false,
1421
- meta: false,
1422
- shift: false,
1423
- tab: false,
1424
- backspace: false,
1425
- delete: false,
1426
- pageUp: false,
1427
- pageDown: false,
1428
- home: false,
1429
- end: false
1430
- };
1431
- function Input({
1432
- prompt = "\u203A ",
1433
- value,
1434
- cursor,
1435
- placeholders,
1436
- disabled,
1437
- hint,
1438
- onKey
1439
- }) {
1440
- useInput((input, key) => {
1441
- if (disabled) return;
1442
- onKey(input, key);
1443
- });
1444
- const { stdin } = useStdin();
1445
- useEffect(() => {
1446
- if (!stdin || disabled) return;
1447
- const handleData = (data) => {
1448
- const kind = isHomeEnd(data.toString());
1449
- if (kind === "home") onKey("", { ...EMPTY_KEY, home: true });
1450
- else if (kind === "end") onKey("", { ...EMPTY_KEY, end: true });
1451
- };
1452
- stdin.on("data", handleData);
1453
- return () => {
1454
- stdin.off("data", handleData);
1455
- };
1456
- }, [stdin, disabled, onKey]);
1457
- const before = value.slice(0, cursor);
1458
- const at = value.slice(cursor, cursor + 1) || " ";
1459
- const after = value.slice(cursor + 1);
1460
- const promptColor = disabled ? "red" : "cyan";
1461
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1462
- placeholders.map((p, i) => (
1463
- // biome-ignore lint/suspicious/noArrayIndexKey: placeholders are append-only, index is stable
1464
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1465
- " \u21B3 ",
1466
- p
1467
- ] }, i)
1468
- )),
1469
- /* @__PURE__ */ jsxs(Text, { children: [
1470
- /* @__PURE__ */ jsx(Text, { color: promptColor, children: prompt }),
1471
- before,
1472
- /* @__PURE__ */ jsx(Text, { inverse: true, children: at }),
1473
- after
1474
- ] }),
1475
- hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
1476
- ] });
1477
- }
1478
- function fmtElapsed(ms) {
1479
- if (ms < 1e3) return `${ms}ms`;
1480
- if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
1481
- const m = Math.floor(ms / 6e4);
1482
- const s = Math.floor(ms % 6e4 / 1e3);
1483
- return `${m}m${s.toString().padStart(2, "0")}s`;
1484
- }
1485
- function fmtBytes3(n) {
1486
- if (n < 1024) return `${n}B`;
1487
- return `${(n / 1024).toFixed(1)}KB`;
1488
- }
1489
- function fmtRecentTool2(tool) {
1490
- const status = tool.ok === false ? "fail" : "ok";
1491
- const name = tool.name.length > 18 ? `${tool.name.slice(0, 17)}...` : tool.name;
1492
- const parts = [status, name];
1493
- if (typeof tool.durationMs === "number") parts.push(fmtElapsed(tool.durationMs));
1494
- if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes3(tool.outputBytes));
1495
- if (typeof tool.outputLines === "number" && tool.outputLines > 0) parts.push(`${tool.outputLines}L`);
1496
- return parts.join(" ");
1497
- }
1498
- function fmtRecentMessage2(message) {
1499
- const text = message.text.replace(/\s+/g, " ");
1500
- return text.length > 48 ? `${text.slice(0, 47)}...` : text;
1501
- }
1502
- function LiveActivityStrip({
1503
- entries,
1504
- nowTick,
1505
- maxRows = 4
1506
- }) {
1507
- const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
1508
- if (running.length === 0) return null;
1509
- const now = Date.now();
1510
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1511
- running.map((e) => {
1512
- const toolElapsed = e.currentTool ? now - e.currentTool.startedAt : 0;
1513
- const taskElapsed = now - e.startedAt;
1514
- const toolSeg = e.currentTool ? `\u2192 ${e.currentTool.name} (${fmtElapsed(toolElapsed)})` : "idle between tools";
1515
- const recentTools = (e.recentTools ?? []).slice(-2).map(fmtRecentTool2).join(" | ");
1516
- const messageText = e.streamingText.trim() || (e.recentMessages ?? []).slice(-1).map(fmtRecentMessage2).join("");
1517
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1518
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25CF" }),
1519
- /* @__PURE__ */ jsx(Text, { children: e.name.slice(0, 14).padEnd(14) }),
1520
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
1521
- /* @__PURE__ */ jsx(Text, { color: e.currentTool ? "green" : "yellow", children: toolSeg }),
1522
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
1523
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1524
- e.iterations,
1525
- "it ",
1526
- e.toolCalls,
1527
- "tc \xB7 ",
1528
- fmtElapsed(taskElapsed)
1529
- ] }),
1530
- recentTools ? /* @__PURE__ */ jsxs(Fragment, { children: [
1531
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
1532
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1533
- "last: ",
1534
- recentTools
1535
- ] })
1536
- ] }) : null,
1537
- messageText ? /* @__PURE__ */ jsxs(Fragment, { children: [
1538
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
1539
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1540
- "msg: ",
1541
- fmtRecentMessage2({ text: messageText})
1542
- ] })
1543
- ] }) : null
1544
- ] }, e.id);
1545
- }),
1546
- Object.values(entries).filter((e) => e.status === "running").length > maxRows ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1547
- "\u2026+",
1548
- Object.values(entries).filter((e) => e.status === "running").length - maxRows,
1549
- " more"
1550
- ] }) }) : null
1551
- ] });
2031
+ function numOf(v) {
2032
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1552
2033
  }
1553
- var AUTONOMY_OPTIONS = [
1554
- { mode: "off", label: "OFF", description: "Agent stops after each turn (normal interactive mode)", color: "green" },
1555
- { mode: "suggest", label: "SUGGEST", description: "Shows next-step suggestions after each turn", color: "cyan" },
1556
- { mode: "auto", label: "AUTO", description: "Self-driving \u2014 agent picks next step and continues", color: "yellow" },
1557
- { mode: "eternal", label: "ETERNAL", description: "Goal-driven loop \u2014 requires /goal set first", color: "red" },
1558
- { mode: "eternal-parallel", label: "PARALLEL", description: "Fan-out 4\u20138 subagents per tick \u2014 requires /goal", color: "magenta" }
1559
- ];
1560
- function AutonomyPicker({ options, selected, hint }) {
1561
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1562
- /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
1563
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
1564
- options.map((opt, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? opt.color : void 0, inverse: i === selected, children: [
1565
- i === selected ? "\u203A " : " ",
1566
- /* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
1567
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
1568
- ] }, opt.mode)),
1569
- hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
1570
- ] });
2034
+ function tryParseJson(s) {
2035
+ const t = s.trimStart();
2036
+ if (!t.startsWith("{") && !t.startsWith("[")) return void 0;
2037
+ try {
2038
+ return JSON.parse(s);
2039
+ } catch {
2040
+ return void 0;
2041
+ }
1571
2042
  }
1572
- function ModelPicker({
1573
- step,
1574
- providerOptions,
1575
- modelOptions,
1576
- selected,
1577
- pickedProviderId,
1578
- hint
1579
- }) {
1580
- if (step === "provider") {
1581
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1582
- /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
1583
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
1584
- providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : providerOptions.map((p, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
1585
- i === selected ? "\u203A " : " ",
1586
- /* @__PURE__ */ jsx(Text, { bold: true, children: p.id.padEnd(28) }),
1587
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1588
- " [",
1589
- p.family,
1590
- "]"
1591
- ] }),
1592
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1593
- " ",
1594
- p.models.length,
1595
- " model",
1596
- p.models.length === 1 ? "" : "s"
1597
- ] })
1598
- ] }, p.id)),
1599
- hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
1600
- ] });
2043
+ function scanNumberedRange(text) {
2044
+ let first;
2045
+ let last;
2046
+ let count = 0;
2047
+ for (const line of text.split("\n")) {
2048
+ const m = line.match(/^\s*(\d+)→/);
2049
+ if (m?.[1]) {
2050
+ const n = Number.parseInt(m[1], 10);
2051
+ if (Number.isFinite(n)) {
2052
+ if (first === void 0) first = n;
2053
+ last = n;
2054
+ count++;
2055
+ }
2056
+ }
1601
2057
  }
1602
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1603
- /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
1604
- "\u2501\u2501 Switch model \u2014 Step 2/2: Pick model (",
1605
- pickedProviderId,
1606
- ") \u2501\u2501"
1607
- ] }),
1608
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit" }),
1609
- modelOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no models known for this provider)" }) : modelOptions.map((id, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
1610
- i === selected ? "\u203A " : " ",
1611
- id
1612
- ] }, id)),
1613
- hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
1614
- ] });
2058
+ return { first, last, count };
1615
2059
  }
1616
- function SlashMenu({ query, matches, selected }) {
1617
- const placeholder = query ? `/${query}` : "/";
1618
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
1619
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1620
- placeholder || "/",
1621
- " \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
1622
- ] }),
1623
- matches.map((m, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
1624
- i === selected ? "\u203A " : " ",
1625
- /* @__PURE__ */ jsx(Text, { bold: true, children: m.name }),
1626
- m.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1627
- " ",
1628
- m.argsHint
1629
- ] }) : null,
1630
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1631
- " \u2014 ",
1632
- m.description
1633
- ] })
1634
- ] }, m.name)),
1635
- matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
1636
- ] });
2060
+ function countLines(text) {
2061
+ if (!text) return 0;
2062
+ return text.replace(/\n$/, "").split("\n").length;
1637
2063
  }
1638
- function StatusBar({
1639
- model,
1640
- state,
1641
- tokenCounter,
2064
+ function fmtBytes2(n) {
2065
+ if (n < 1024) return `${n}B`;
2066
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
2067
+ return `${(n / (1024 * 1024)).toFixed(1)}MB`;
2068
+ }
2069
+ function truncMid(s, max) {
2070
+ if (s.length <= max) return s;
2071
+ return `${s.slice(0, max - 1)}\u2026`;
2072
+ }
2073
+ function isHomeEnd(data) {
2074
+ if (data === "\x1B[H" || data === "\x1B[1~" || data === "\x1BOH" || data === "\x1B[7~")
2075
+ return "home";
2076
+ if (data === "\x1B[F" || data === "\x1B[4~" || data === "\x1BOF" || data === "\x1B[8~")
2077
+ return "end";
2078
+ return null;
2079
+ }
2080
+ var EMPTY_KEY = {
2081
+ upArrow: false,
2082
+ downArrow: false,
2083
+ leftArrow: false,
2084
+ rightArrow: false,
2085
+ return: false,
2086
+ escape: false,
2087
+ ctrl: false,
2088
+ meta: false,
2089
+ shift: false,
2090
+ tab: false,
2091
+ backspace: false,
2092
+ delete: false,
2093
+ pageUp: false,
2094
+ pageDown: false,
2095
+ home: false,
2096
+ end: false
2097
+ };
2098
+ function Input({
2099
+ prompt = "\u203A ",
2100
+ value,
2101
+ cursor,
2102
+ placeholders,
2103
+ disabled,
1642
2104
  hint,
1643
- queueCount = 0,
1644
- yolo = false,
1645
- autonomy,
1646
- elapsedMs,
1647
- todos,
1648
- plan,
1649
- fleet,
1650
- fleetAgents,
1651
- git,
1652
- subagentCount = 0,
1653
- context,
1654
- projectName,
1655
- processCount,
1656
- hiddenItems,
1657
- eternalStage,
1658
- goalSummary
2105
+ onKey
1659
2106
  }) {
1660
- const hiddenSet = new Set(hiddenItems);
1661
- const usage = tokenCounter?.total();
1662
- const cost = tokenCounter?.estimateCost();
1663
- const cache2 = tokenCounter?.cacheStats();
1664
- const stateColor = state === "idle" ? "cyan" : state === "aborting" ? "yellow" : "green";
1665
- const stateLabel = state === "idle" ? "idle" : state === "aborting" ? "aborting\u2026" : "thinking\u2026";
1666
- const hasSecondLine = yolo || autonomy && autonomy !== "off" || elapsedMs !== void 0 || git !== null && git !== void 0 || projectName !== void 0 && projectName.length > 0 || goalSummary !== null && goalSummary !== void 0;
1667
- const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
1668
- const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity;
1669
- return /* @__PURE__ */ jsxs(
1670
- Box,
1671
- {
1672
- flexDirection: "column",
1673
- paddingX: 1,
1674
- borderStyle: "single",
1675
- borderTop: true,
1676
- borderBottom: false,
1677
- borderLeft: false,
1678
- borderRight: false,
1679
- children: [
1680
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
1681
- /* @__PURE__ */ jsxs(Text, { color: stateColor, children: [
1682
- "\u25CF ",
1683
- stateLabel
1684
- ] }),
1685
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1686
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: model }),
1687
- context && context.max > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1688
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1689
- /* @__PURE__ */ jsx(ContextChip, { ctx: context })
1690
- ] }) : null,
1691
- usage ? /* @__PURE__ */ jsxs(Fragment, { children: [
1692
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1693
- /* @__PURE__ */ jsxs(Text, { children: [
1694
- "\u2191",
1695
- " ",
1696
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: fmtTok2(usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0)) }),
1697
- " ",
1698
- "\u2193 ",
1699
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: fmtTok2(usage.output) })
1700
- ] })
1701
- ] }) : null,
1702
- cache2 && cache2.hitRatio > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1703
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1704
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1705
- "cache ",
1706
- (cache2.hitRatio * 100).toFixed(0),
1707
- "%"
1708
- ] })
1709
- ] }) : null,
1710
- cost && cost.total > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1711
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1712
- /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1713
- "$",
1714
- cost.total.toFixed(4)
1715
- ] })
1716
- ] }) : null,
1717
- queueCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1718
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1719
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1720
- "\u231B queued: ",
1721
- queueCount
1722
- ] })
1723
- ] }) : null,
1724
- typeof processCount === "number" && processCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1725
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1726
- /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1727
- "\u26A1 ",
1728
- processCount,
1729
- " process",
1730
- processCount === 1 ? "" : "es"
1731
- ] })
1732
- ] }) : null,
1733
- hint ? /* @__PURE__ */ jsxs(Fragment, { children: [
1734
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
1735
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
1736
- ] }) : null
2107
+ useInput((input, key) => {
2108
+ if (disabled) return;
2109
+ onKey(input, key);
2110
+ });
2111
+ const { stdin } = useStdin();
2112
+ useEffect(() => {
2113
+ if (!stdin || disabled) return;
2114
+ const handleData = (data) => {
2115
+ const kind = isHomeEnd(data.toString());
2116
+ if (kind === "home") onKey("", { ...EMPTY_KEY, home: true });
2117
+ else if (kind === "end") onKey("", { ...EMPTY_KEY, end: true });
2118
+ };
2119
+ stdin.on("data", handleData);
2120
+ return () => {
2121
+ stdin.off("data", handleData);
2122
+ };
2123
+ }, [stdin, disabled, onKey]);
2124
+ const before = value.slice(0, cursor);
2125
+ const at = value.slice(cursor, cursor + 1) || " ";
2126
+ const after = value.slice(cursor + 1);
2127
+ const promptColor = disabled ? "red" : "cyan";
2128
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2129
+ placeholders.map((p, i) => (
2130
+ // biome-ignore lint/suspicious/noArrayIndexKey: placeholders are append-only, index is stable
2131
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2132
+ " \u21B3 ",
2133
+ p
2134
+ ] }, i)
2135
+ )),
2136
+ /* @__PURE__ */ jsxs(Text, { children: [
2137
+ /* @__PURE__ */ jsx(Text, { color: promptColor, children: prompt }),
2138
+ before,
2139
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: at }),
2140
+ after
2141
+ ] }),
2142
+ hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
2143
+ ] });
2144
+ }
2145
+ function fmtElapsed2(ms) {
2146
+ if (ms < 1e3) return `${ms}ms`;
2147
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
2148
+ const m = Math.floor(ms / 6e4);
2149
+ const s = Math.floor(ms % 6e4 / 1e3);
2150
+ return `${m}m${s.toString().padStart(2, "0")}s`;
2151
+ }
2152
+ function fmtBytes3(n) {
2153
+ if (n < 1024) return `${n}B`;
2154
+ return `${(n / 1024).toFixed(1)}KB`;
2155
+ }
2156
+ function fmtRecentTool2(tool) {
2157
+ const status = tool.ok === false ? "fail" : "ok";
2158
+ const name = tool.name.length > 18 ? `${tool.name.slice(0, 17)}...` : tool.name;
2159
+ const parts = [status, name];
2160
+ if (typeof tool.durationMs === "number") parts.push(fmtElapsed2(tool.durationMs));
2161
+ if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes3(tool.outputBytes));
2162
+ if (typeof tool.outputLines === "number" && tool.outputLines > 0) parts.push(`${tool.outputLines}L`);
2163
+ return parts.join(" ");
2164
+ }
2165
+ function fmtRecentMessage2(message) {
2166
+ const text = message.text.replace(/\s+/g, " ");
2167
+ return text.length > 48 ? `${text.slice(0, 47)}...` : text;
2168
+ }
2169
+ function LiveActivityStrip({
2170
+ entries,
2171
+ nowTick,
2172
+ maxRows = 4
2173
+ }) {
2174
+ const running = Object.values(entries).filter((e) => e.status === "running").sort((a, b) => a.startedAt - b.startedAt).slice(0, maxRows);
2175
+ if (running.length === 0) return null;
2176
+ const now = Date.now();
2177
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
2178
+ running.map((e) => {
2179
+ const toolElapsed = e.currentTool ? now - e.currentTool.startedAt : 0;
2180
+ const taskElapsed = now - e.startedAt;
2181
+ const toolSeg = e.currentTool ? `\u2192 ${e.currentTool.name} (${fmtElapsed2(toolElapsed)})` : "idle between tools";
2182
+ const recentTools = (e.recentTools ?? []).slice(-2).map(fmtRecentTool2).join(" | ");
2183
+ const messageText = e.streamingText.trim() || (e.recentMessages ?? []).slice(-1).map(fmtRecentMessage2).join("");
2184
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
2185
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25CF" }),
2186
+ /* @__PURE__ */ jsx(Text, { children: e.name.slice(0, 14).padEnd(14) }),
2187
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
2188
+ /* @__PURE__ */ jsx(Text, { color: e.currentTool ? "green" : "yellow", children: toolSeg }),
2189
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
2190
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2191
+ e.iterations,
2192
+ "it ",
2193
+ e.toolCalls,
2194
+ "tc \xB7 ",
2195
+ fmtElapsed2(taskElapsed)
1737
2196
  ] }),
1738
- hasSecondLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
1739
- yolo ? /* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "\u26A0 YOLO" }) : null,
1740
- autonomy && autonomy !== "off" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1741
- yolo ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1742
- /* @__PURE__ */ jsxs(
1743
- Text,
1744
- {
1745
- color: autonomy === "eternal" ? "red" : autonomy === "auto" ? "yellow" : "cyan",
1746
- bold: true,
1747
- children: [
1748
- "\u221E ",
1749
- autonomy.toUpperCase()
1750
- ]
1751
- }
1752
- )
1753
- ] }) : null,
1754
- eternalStage ? /* @__PURE__ */ jsxs(Fragment, { children: [
1755
- yolo || autonomy && autonomy !== "off" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1756
- /* @__PURE__ */ jsx(EternalStageChip, { stage: eternalStage })
1757
- ] }) : null,
1758
- elapsedMs !== void 0 && !hiddenSet.has("elapsed") ? /* @__PURE__ */ jsxs(Fragment, { children: [
1759
- yolo || autonomy && autonomy !== "off" || eternalStage ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1760
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1761
- "\u23F1 ",
1762
- fmtElapsed2(elapsedMs)
1763
- ] })
1764
- ] }) : null,
1765
- projectName ? /* @__PURE__ */ jsxs(Fragment, { children: [
1766
- yolo || elapsedMs !== void 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1767
- /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
1768
- "\u{1F4C1} ",
1769
- projectName
1770
- ] })
1771
- ] }) : null,
1772
- goalSummary ? /* @__PURE__ */ jsxs(Fragment, { children: [
1773
- yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1774
- /* @__PURE__ */ jsxs(Text, { color: goalSummary.goalState === "active" ? "green" : goalSummary.goalState === "paused" ? "yellow" : goalSummary.goalState === "completed" ? "green" : "dim", children: [
1775
- "\u{1F3AF} ",
1776
- goalSummary.goal.length > 40 ? `${goalSummary.goal.slice(0, 37)}\u2026` : goalSummary.goal,
1777
- " [",
1778
- goalSummary.goalState,
1779
- "] (iter ",
1780
- goalSummary.iterations,
1781
- ")"
1782
- ] })
1783
- ] }) : null,
1784
- git ? /* @__PURE__ */ jsxs(Fragment, { children: [
1785
- yolo || elapsedMs !== void 0 || projectName ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1786
- /* @__PURE__ */ jsxs(Text, { children: [
1787
- /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
1788
- "\u2387 ",
1789
- git.branch
1790
- ] }),
1791
- git.added > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1792
- " +",
1793
- git.added
1794
- ] }) : null,
1795
- git.deleted > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1796
- " -",
1797
- git.deleted
1798
- ] }) : null,
1799
- git.untracked > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1800
- " ?",
1801
- git.untracked
1802
- ] }) : null
1803
- ] })
1804
- ] }) : null
1805
- ] }) : null,
1806
- hasThirdLine ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
1807
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsxs(Text, { children: [
1808
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "todos " }),
1809
- todos.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1810
- "\u231B",
1811
- todos.inProgress
1812
- ] }) : null,
1813
- todos.inProgress > 0 && (todos.pending > 0 || todos.completed > 0) ? " " : "",
1814
- todos.pending > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1815
- "\u2610",
1816
- todos.pending
1817
- ] }) : null,
1818
- todos.pending > 0 && todos.completed > 0 ? " " : "",
1819
- todos.completed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1820
- "\u2713",
1821
- todos.completed
1822
- ] }) : null
1823
- ] }) : null,
1824
- plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsxs(Fragment, { children: [
1825
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1826
- /* @__PURE__ */ jsxs(Text, { children: [
1827
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u{1F4CB} " }),
1828
- plan.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1829
- "\u231B",
1830
- plan.inProgress
1831
- ] }) : null,
1832
- plan.inProgress > 0 && (plan.open > 0 || plan.done > 0) ? " " : "",
1833
- plan.open > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1834
- "\u2610",
1835
- plan.open
1836
- ] }) : null,
1837
- plan.open > 0 && plan.done > 0 ? " " : "",
1838
- plan.done > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1839
- "\u2713",
1840
- plan.done
1841
- ] }) : null
1842
- ] })
1843
- ] }) : null,
1844
- fleetHasActivity ? /* @__PURE__ */ jsxs(Fragment, { children: [
1845
- todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1846
- fleet ? /* @__PURE__ */ jsxs(Text, { children: [
1847
- /* @__PURE__ */ jsx(Text, { color: "blue", children: "\u{1F310} " }),
1848
- fleet.running > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1849
- "\u25B6",
1850
- fleet.running
1851
- ] }) : null,
1852
- fleet.running > 0 && (fleet.pending > 0 || fleet.idle > 0 || fleet.completed > 0) ? " " : "",
1853
- fleet.pending > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1854
- "\u2610",
1855
- fleet.pending
1856
- ] }) : null,
1857
- fleet.pending > 0 && (fleet.idle > 0 || fleet.completed > 0) ? " " : "",
1858
- fleet.idle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1859
- "\xB7",
1860
- fleet.idle,
1861
- "idle"
1862
- ] }) : null,
1863
- fleet.idle > 0 && fleet.completed > 0 ? " " : "",
1864
- fleet.completed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1865
- "\u2713",
1866
- fleet.completed
1867
- ] }) : null
1868
- ] }) : /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
1869
- "\u{1F310} ",
1870
- subagentCount,
1871
- " agent",
1872
- subagentCount === 1 ? "" : "s"
1873
- ] })
1874
- ] }) : null
2197
+ recentTools ? /* @__PURE__ */ jsxs(Fragment, { children: [
2198
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
2199
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2200
+ "last: ",
2201
+ recentTools
2202
+ ] })
1875
2203
  ] }) : null,
1876
- fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
1877
- // biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
1878
- /* @__PURE__ */ jsxs(Text, { children: [
1879
- /* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
1880
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
1881
- /* @__PURE__ */ jsx(Text, { color: a.running ? "yellow" : void 0, dimColor: !a.running, children: a.running ? "\u25B6" : "\xB7" }),
1882
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
1883
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed2(a.elapsedMs) }),
1884
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
1885
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1886
- a.toolCalls,
1887
- "t"
1888
- ] })
1889
- ] }, i)
1890
- )) }) : null
1891
- ]
1892
- }
1893
- );
2204
+ messageText ? /* @__PURE__ */ jsxs(Fragment, { children: [
2205
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
2206
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2207
+ "msg: ",
2208
+ fmtRecentMessage2({ text: messageText})
2209
+ ] })
2210
+ ] }) : null
2211
+ ] }, e.id);
2212
+ }),
2213
+ Object.values(entries).filter((e) => e.status === "running").length > maxRows ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2214
+ "\u2026+",
2215
+ Object.values(entries).filter((e) => e.status === "running").length - maxRows,
2216
+ " more"
2217
+ ] }) }) : null
2218
+ ] });
2219
+ }
2220
+ var AUTONOMY_OPTIONS = [
2221
+ { mode: "off", label: "OFF", description: "Agent stops after each turn (normal interactive mode)", color: "green" },
2222
+ { mode: "suggest", label: "SUGGEST", description: "Shows next-step suggestions after each turn", color: "cyan" },
2223
+ { mode: "auto", label: "AUTO", description: "Self-driving \u2014 agent picks next step and continues", color: "yellow" },
2224
+ { mode: "eternal", label: "ETERNAL", description: "Goal-driven loop \u2014 requires /goal set first", color: "red" },
2225
+ { mode: "eternal-parallel", label: "PARALLEL", description: "Fan-out 4\u20138 subagents per tick \u2014 requires /goal", color: "magenta" }
2226
+ ];
2227
+ function AutonomyPicker({ options, selected, hint }) {
2228
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
2229
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
2230
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
2231
+ options.map((opt, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? opt.color : void 0, inverse: i === selected, children: [
2232
+ i === selected ? "\u203A " : " ",
2233
+ /* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
2234
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
2235
+ ] }, opt.mode)),
2236
+ hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
2237
+ ] });
1894
2238
  }
1895
- function EternalStageChip({
1896
- stage
2239
+ function ModelPicker({
2240
+ step,
2241
+ providerOptions,
2242
+ modelOptions,
2243
+ selected,
2244
+ pickedProviderId,
2245
+ hint
1897
2246
  }) {
1898
- switch (stage.phase) {
1899
- case "idle":
1900
- return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2B1C idle" });
1901
- case "decide":
1902
- return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1903
- "\u2B07 decide: ",
1904
- stage.reason
1905
- ] });
1906
- case "execute":
1907
- return /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1908
- "\u25B6 ",
1909
- /* @__PURE__ */ jsx(Text, { bold: true, children: "execute" }),
1910
- stage.task ? `(${stage.task})` : ""
1911
- ] });
1912
- case "reflect":
1913
- return /* @__PURE__ */ jsxs(Text, { color: stage.status === "success" ? "green" : stage.status === "failure" ? "red" : "yellow", children: [
1914
- "\u21A9 reflect: ",
1915
- stage.status
1916
- ] });
1917
- case "sleep":
1918
- return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1919
- "\u{1F4A4} sleep ",
1920
- Math.round(stage.ms / 1e3),
1921
- "s"
1922
- ] });
1923
- case "paused":
1924
- return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u23F8 paused" });
1925
- case "stopped":
1926
- return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25A0 stopped" });
1927
- case "error":
1928
- return /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1929
- "\u26A0 error: ",
1930
- stage.message
1931
- ] });
2247
+ if (step === "provider") {
2248
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
2249
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Switch model \u2014 Step 1/2: Pick provider \u2501\u2501" }),
2250
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
2251
+ providerOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : providerOptions.map((p, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
2252
+ i === selected ? "\u203A " : " ",
2253
+ /* @__PURE__ */ jsx(Text, { bold: true, children: p.id.padEnd(28) }),
2254
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2255
+ " [",
2256
+ p.family,
2257
+ "]"
2258
+ ] }),
2259
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2260
+ " ",
2261
+ p.models.length,
2262
+ " model",
2263
+ p.models.length === 1 ? "" : "s"
2264
+ ] })
2265
+ ] }, p.id)),
2266
+ hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
2267
+ ] });
1932
2268
  }
1933
- }
1934
- function ContextChip({ ctx }) {
1935
- const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
1936
- const pct = Math.round(ratio * 100);
1937
- const color = ratio >= 0.85 ? "red" : ratio >= 0.65 ? "yellow" : "cyan";
1938
- return /* @__PURE__ */ jsxs(Text, { children: [
1939
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "ctx " }),
1940
- /* @__PURE__ */ jsx(Text, { color, children: renderProgress(ratio, 10) }),
1941
- /* @__PURE__ */ jsxs(Text, { color, children: [
1942
- " ",
1943
- pct,
1944
- "%"
2269
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
2270
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
2271
+ "\u2501\u2501 Switch model \u2014 Step 2/2: Pick model (",
2272
+ pickedProviderId,
2273
+ ") \u2501\u2501"
1945
2274
  ] }),
1946
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1947
- " ",
1948
- "(",
1949
- fmtTok2(ctx.used),
1950
- "/",
1951
- fmtTok2(ctx.max),
1952
- ")"
1953
- ] })
2275
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit" }),
2276
+ modelOptions.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(no models known for this provider)" }) : modelOptions.map((id, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
2277
+ i === selected ? "\u203A " : " ",
2278
+ id
2279
+ ] }, id)),
2280
+ hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
1954
2281
  ] });
1955
2282
  }
1956
- var FILLED = "\u2588";
1957
- var EMPTY = "\u2591";
1958
- function renderProgress(ratio, width) {
1959
- const clamped = Math.max(0, Math.min(1, ratio));
1960
- const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
1961
- const capped = Math.min(width, filled);
1962
- return FILLED.repeat(capped) + EMPTY.repeat(width - capped);
1963
- }
1964
- function fmtTok2(n) {
1965
- if (n < 1e3) return String(n);
1966
- if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 1 : 0)}k`;
1967
- return `${(n / 1e6).toFixed(1)}M`;
1968
- }
1969
- function fmtElapsed2(ms) {
1970
- const totalSec = Math.floor(ms / 1e3);
1971
- const h = Math.floor(totalSec / 3600);
1972
- const m = Math.floor(totalSec % 3600 / 60);
1973
- const s = totalSec % 60;
1974
- if (h > 0) {
1975
- return `${h}:${pad2(m)}:${pad2(s)}`;
1976
- }
1977
- return `${pad2(m)}:${pad2(s)}`;
1978
- }
1979
- function pad2(n) {
1980
- return n < 10 ? `0${n}` : String(n);
2283
+ function SlashMenu({ query, matches, selected }) {
2284
+ const placeholder = query ? `/${query}` : "/";
2285
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
2286
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2287
+ placeholder || "/",
2288
+ " \u2014 \u2191/\u2193 select, Enter dispatch, Tab autocomplete, Esc close"
2289
+ ] }),
2290
+ matches.map((m, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? "cyan" : void 0, inverse: i === selected, children: [
2291
+ i === selected ? "\u203A " : " ",
2292
+ /* @__PURE__ */ jsx(Text, { bold: true, children: m.name }),
2293
+ m.argsHint ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2294
+ " ",
2295
+ m.argsHint
2296
+ ] }) : null,
2297
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2298
+ " \u2014 ",
2299
+ m.description
2300
+ ] })
2301
+ ] }, m.name)),
2302
+ matches.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No matching commands" })
2303
+ ] });
1981
2304
  }
1982
2305
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
1983
2306
  "node_modules",
@@ -2057,6 +2380,19 @@ async function searchFiles(root, query, limit = 8) {
2057
2380
  scored.sort((a, b) => a.score - b.score);
2058
2381
  return scored.slice(0, limit).map((x) => x.path);
2059
2382
  }
2383
+
2384
+ // src/paste-accumulator.ts
2385
+ var BEGIN = "[200~";
2386
+ var END = "[201~";
2387
+ var BEGIN_RE = /\x1b?\[200~/g;
2388
+ var END_RE = /\x1b?\[201~/g;
2389
+ function feedPaste(accum, input) {
2390
+ if (accum === null && !input.includes(BEGIN)) return null;
2391
+ const piece = input.replace(BEGIN_RE, "").replace(END_RE, "");
2392
+ const next = (accum ?? "") + piece;
2393
+ if (input.includes(END)) return { accum: null, complete: next };
2394
+ return { accum: next, complete: null };
2395
+ }
2060
2396
  async function readGitInfo(cwd) {
2061
2397
  const [branchRes, numstatRes, statusRes] = await Promise.all([
2062
2398
  runGit(cwd, ["branch", "--show-current"]),
@@ -2298,20 +2634,31 @@ function reducer(state, action) {
2298
2634
  case "setBuffer":
2299
2635
  return { ...state, buffer: action.buffer, cursor: action.cursor };
2300
2636
  case "addPlaceholder":
2301
- return { ...state, placeholders: [...state.placeholders, action.ph] };
2637
+ return {
2638
+ ...state,
2639
+ placeholders: [...state.placeholders, action.ph],
2640
+ placeholderContents: [...state.placeholderContents, action.content ?? ""]
2641
+ };
2302
2642
  case "removeLastPlaceholder":
2303
2643
  if (state.placeholders.length === 0) return state;
2304
- return { ...state, placeholders: state.placeholders.slice(0, -1) };
2644
+ return {
2645
+ ...state,
2646
+ placeholders: state.placeholders.slice(0, -1),
2647
+ placeholderContents: state.placeholderContents.slice(0, -1)
2648
+ };
2305
2649
  case "clearInput":
2306
2650
  return {
2307
2651
  ...state,
2308
2652
  buffer: "",
2309
2653
  cursor: 0,
2310
2654
  placeholders: [],
2655
+ placeholderContents: [],
2311
2656
  historyIndex: 0,
2312
2657
  picker: { open: false, query: "", matches: [], selected: 0 },
2313
2658
  slashPicker: { open: false, query: "", matches: [], selected: 0 }
2314
2659
  };
2660
+ case "clearPlaceholdersOnly":
2661
+ return { ...state, placeholders: [], placeholderContents: [] };
2315
2662
  case "clearHistory": {
2316
2663
  const last = state.entries[state.entries.length - 1];
2317
2664
  return {
@@ -2732,12 +3079,39 @@ function reducer(state, action) {
2732
3079
  }
2733
3080
  };
2734
3081
  }
3082
+ case "fleetBudgetExtended": {
3083
+ const cur = state.fleet[action.id];
3084
+ if (!cur) return state;
3085
+ return {
3086
+ ...state,
3087
+ fleet: {
3088
+ ...state.fleet,
3089
+ [action.id]: {
3090
+ ...cur,
3091
+ // The director sends the authoritative cumulative count; trust it
3092
+ // over a local increment so a dropped event can't desync the badge.
3093
+ extensions: action.totalExtensions,
3094
+ lastEventAt: Date.now()
3095
+ }
3096
+ }
3097
+ };
3098
+ }
2735
3099
  case "fleetCost": {
2736
- return { ...state, fleetCost: action.cost };
3100
+ return {
3101
+ ...state,
3102
+ fleetCost: action.cost,
3103
+ fleetTokens: action.input !== void 0 || action.output !== void 0 ? { input: action.input ?? state.fleetTokens.input, output: action.output ?? state.fleetTokens.output } : state.fleetTokens
3104
+ };
2737
3105
  }
2738
3106
  case "setStreamFleet": {
2739
3107
  return { ...state, streamFleet: action.enabled };
2740
3108
  }
3109
+ case "toggleMonitor": {
3110
+ return { ...state, monitorOpen: !state.monitorOpen };
3111
+ }
3112
+ case "toggleAgentsMonitor": {
3113
+ return { ...state, agentsMonitorOpen: !state.agentsMonitorOpen };
3114
+ }
2741
3115
  case "checkpointReceived": {
2742
3116
  const existing = state.checkpoints.find((c) => c.promptIndex === action.cp.promptIndex);
2743
3117
  if (existing) return state;
@@ -2859,7 +3233,7 @@ function App({
2859
3233
  }, [statuslineHiddenItems]);
2860
3234
  useEffect(() => {
2861
3235
  setStatuslineHiddenItems(hiddenItems);
2862
- }, [setStatuslineHiddenItems]);
3236
+ }, [setStatuslineHiddenItems, hiddenItems]);
2863
3237
  const projectRoot = agent.ctx.projectRoot;
2864
3238
  useEffect(() => {
2865
3239
  if (!projectRoot) return;
@@ -2898,6 +3272,7 @@ function App({
2898
3272
  buffer: "",
2899
3273
  cursor: 0,
2900
3274
  placeholders: [],
3275
+ placeholderContents: [],
2901
3276
  streamingText: "",
2902
3277
  toolStream: null,
2903
3278
  status: "idle",
@@ -2925,7 +3300,10 @@ function App({
2925
3300
  contextChipVersion: 0,
2926
3301
  fleet: {},
2927
3302
  fleetCost: 0,
3303
+ fleetTokens: { input: 0, output: 0 },
2928
3304
  streamFleet: true,
3305
+ monitorOpen: false,
3306
+ agentsMonitorOpen: false,
2929
3307
  checkpoints: [],
2930
3308
  rewindOverlay: null,
2931
3309
  eternalStage: null,
@@ -2935,7 +3313,10 @@ function App({
2935
3313
  if (builderRef.current === null) {
2936
3314
  builderRef.current = new InputBuilder({ store: attachments });
2937
3315
  }
3316
+ const pasteAccumRef = useRef(null);
3317
+ const pasteFlushTimerRef = useRef(null);
2938
3318
  const activeCtrlRef = useRef(null);
3319
+ const exitRequestedRef = useRef(false);
2939
3320
  const inputGateRef = useRef(false);
2940
3321
  const lastEnterAtRef = useRef(0);
2941
3322
  const projectName = React2.useMemo(() => {
@@ -2964,6 +3345,10 @@ function App({
2964
3345
  draftRef.current = { buffer: "", cursor: 0 };
2965
3346
  dispatch({ type: "clearInput" });
2966
3347
  };
3348
+ const clearPlaceholdersOnly = () => {
3349
+ draftRef.current = { buffer: "", cursor: 0 };
3350
+ dispatch({ type: "clearPlaceholdersOnly" });
3351
+ };
2967
3352
  const startedAtRef = useRef(Date.now());
2968
3353
  const [nowTick, setNowTick] = React2.useState(Date.now());
2969
3354
  useEffect(() => {
@@ -3048,7 +3433,11 @@ function App({
3048
3433
  color: lbl.color,
3049
3434
  elapsedMs: Math.max(0, nowTick - e.startedAt),
3050
3435
  toolCalls: e.toolCalls,
3051
- running: e.status === "running"
3436
+ running: e.status === "running",
3437
+ // Last/current action, so the 4th line shows what each agent is
3438
+ // doing right now (e.g. "▶ 12s · 8t · bash") rather than just counts.
3439
+ tool: e.currentTool?.name,
3440
+ extensions: e.extensions
3052
3441
  };
3053
3442
  });
3054
3443
  }, [state.fleet, nowTick]);
@@ -3398,6 +3787,20 @@ function App({
3398
3787
  slashRegistry.unregister("rewind");
3399
3788
  };
3400
3789
  }, [slashRegistry, handleRewindTo]);
3790
+ useEffect(() => {
3791
+ const cmd = {
3792
+ name: "agents",
3793
+ description: "Toggle the agents monitor overlay.",
3794
+ async run() {
3795
+ dispatch({ type: "toggleAgentsMonitor" });
3796
+ return { message: void 0 };
3797
+ }
3798
+ };
3799
+ slashRegistry.register(cmd);
3800
+ return () => {
3801
+ slashRegistry.unregister("agents");
3802
+ };
3803
+ }, [slashRegistry]);
3401
3804
  useEffect(() => {
3402
3805
  if (!getPickableProviders || !switchProviderAndModel) return;
3403
3806
  const cmd = {
@@ -3415,6 +3818,23 @@ function App({
3415
3818
  slashRegistry.unregister("model");
3416
3819
  };
3417
3820
  }, [slashRegistry, getPickableProviders, switchProviderAndModel]);
3821
+ useEffect(() => {
3822
+ const cmd = {
3823
+ name: "agents",
3824
+ description: "Open or close the agents monitor overlay.",
3825
+ async run(args) {
3826
+ if (args.trim().toLowerCase() === "monitor") {
3827
+ dispatch({ type: "toggleAgentsMonitor" });
3828
+ return { message: "Agents monitor toggled." };
3829
+ }
3830
+ return { message: "Usage: /agents monitor" };
3831
+ }
3832
+ };
3833
+ slashRegistry.register(cmd);
3834
+ return () => {
3835
+ slashRegistry.unregister("agents");
3836
+ };
3837
+ }, [slashRegistry]);
3418
3838
  useEffect(() => {
3419
3839
  if (!switchAutonomy) return;
3420
3840
  const cmd = {
@@ -3441,7 +3861,7 @@ function App({
3441
3861
  flushTimerRef.current = null;
3442
3862
  };
3443
3863
  const offDelta = events.on("provider.text_delta", (e) => {
3444
- const text = e.text.replace(/\x1b\[200~|\x1b\[201~/g, "");
3864
+ const text = e.text.replace(/\x1b?\[200~|\x1b?\[201~/g, "");
3445
3865
  streamingTextRef.current += text;
3446
3866
  pendingDeltaRef.current += text;
3447
3867
  if (!flushTimerRef.current) flushTimerRef.current = setTimeout(flush, FLUSH_MS);
@@ -3632,6 +4052,20 @@ function App({
3632
4052
  }
3633
4053
  });
3634
4054
  });
4055
+ const offBudgetExtended = events.on("subagent.budget_extended", (e) => {
4056
+ const lbl = labelFor(e.subagentId);
4057
+ dispatch({ type: "fleetBudgetExtended", id: e.subagentId, totalExtensions: e.totalExtensions });
4058
+ dispatch({
4059
+ type: "addEntry",
4060
+ entry: {
4061
+ kind: "subagent",
4062
+ agentLabel: lbl.label,
4063
+ agentColor: lbl.color,
4064
+ icon: "\u26A1",
4065
+ text: `extended ${e.kind} \u2192 ${e.newLimit} (\xD7${e.totalExtensions})`
4066
+ }
4067
+ });
4068
+ });
3635
4069
  const offIterationSummary = events.on("subagent.iteration_summary", (e) => {
3636
4070
  const lbl = labelFor(e.subagentId);
3637
4071
  const costStr = e.costUsd > 0 ? ` \xB7 ${e.costUsd.toFixed(3)}` : "";
@@ -3664,6 +4098,7 @@ function App({
3664
4098
  offStarted();
3665
4099
  offCompleted();
3666
4100
  offBudgetWarning();
4101
+ offBudgetExtended();
3667
4102
  offIterationSummary();
3668
4103
  offTool();
3669
4104
  };
@@ -3735,6 +4170,8 @@ function App({
3735
4170
  useEffect(() => {
3736
4171
  if (fleetStreamController) fleetStreamController.enabled = state.streamFleet;
3737
4172
  }, [state.streamFleet, fleetStreamController]);
4173
+ const lastEscAtRef = useRef(0);
4174
+ const ESC_DOUBLE_PRESS_MS = 1e3;
3738
4175
  useEffect(() => {
3739
4176
  const d = director;
3740
4177
  if (!d) return;
@@ -3775,7 +4212,7 @@ function App({
3775
4212
  });
3776
4213
  labelFor(s.id, meta?.name ?? s.name);
3777
4214
  }
3778
- dispatch({ type: "fleetCost", cost: d.snapshot().total.cost });
4215
+ dispatch({ type: "fleetCost", cost: d.snapshot().total.cost, input: d.snapshot().total.input, output: d.snapshot().total.output });
3779
4216
  const seen = new Set(Object.keys(status.subagents));
3780
4217
  const pending = /* @__PURE__ */ new Map();
3781
4218
  let flushTimer = null;
@@ -3885,7 +4322,7 @@ function App({
3885
4322
  break;
3886
4323
  }
3887
4324
  case "provider.response": {
3888
- dispatch({ type: "fleetCost", cost: d.snapshot().total.cost });
4325
+ dispatch({ type: "fleetCost", cost: d.snapshot().total.cost, input: d.snapshot().total.input, output: d.snapshot().total.output });
3889
4326
  break;
3890
4327
  }
3891
4328
  case "session.ended":
@@ -3929,7 +4366,7 @@ function App({
3929
4366
  iterations: payload.result.iterations,
3930
4367
  toolCalls: payload.result.toolCalls
3931
4368
  });
3932
- dispatch({ type: "fleetCost", cost: d.snapshot().total.cost });
4369
+ dispatch({ type: "fleetCost", cost: d.snapshot().total.cost, input: d.snapshot().total.input, output: d.snapshot().total.output });
3933
4370
  if (streamFlushTimer) {
3934
4371
  clearTimeout(streamFlushTimer);
3935
4372
  flushStreamBufs();
@@ -3949,14 +4386,16 @@ function App({
3949
4386
  const current = stateRef.current;
3950
4387
  if (current.interrupts >= 1) {
3951
4388
  getProcessRegistry().killAll({ force: true });
3952
- if (current.interrupts >= 2) {
4389
+ if (exitRequestedRef.current) {
3953
4390
  process.exit(130);
3954
4391
  }
3955
- try {
3956
- process.exit(130);
3957
- } catch {
3958
- }
4392
+ exitRequestedRef.current = true;
3959
4393
  dispatch({ type: "interrupt" });
4394
+ if (director) void director.terminateAll().catch(() => void 0);
4395
+ onExit(130);
4396
+ exit();
4397
+ const hardExit = setTimeout(() => process.exit(130), 400);
4398
+ hardExit.unref?.();
3960
4399
  return;
3961
4400
  }
3962
4401
  dispatch({ type: "interrupt" });
@@ -4008,6 +4447,37 @@ function App({
4008
4447
  });
4009
4448
  }
4010
4449
  } else {
4450
+ const fleetRunning = Object.values(current.fleet).filter(
4451
+ (e) => e.status === "running"
4452
+ ).length;
4453
+ const autonomyRunning = eternalLoopRunningRef.current || parallelLoopRunningRef.current || getEternalEngine?.()?.currentState === "running" || getParallelEngine?.()?.currentState === "running";
4454
+ if (autonomyRunning || fleetRunning > 0) {
4455
+ getEternalEngine?.()?.stop();
4456
+ getParallelEngine?.()?.stop();
4457
+ if (autonomyRunning) switchAutonomy?.("off");
4458
+ if (director) {
4459
+ const cap = new Promise((resolve) => {
4460
+ const t = setTimeout(resolve, 1500);
4461
+ t.unref?.();
4462
+ });
4463
+ void Promise.race([director.terminateAll().catch(() => void 0), cap]);
4464
+ }
4465
+ const killed2 = getProcessRegistry().killAll();
4466
+ const bits = [];
4467
+ if (autonomyRunning) bits.push("autonomy stopped");
4468
+ if (fleetRunning > 0)
4469
+ bits.push(`${fleetRunning} agent${fleetRunning === 1 ? "" : "s"} terminated`);
4470
+ if (killed2.length > 0)
4471
+ bits.push(`${killed2.length} process${killed2.length === 1 ? "" : "es"} killed`);
4472
+ dispatch({
4473
+ type: "addEntry",
4474
+ entry: {
4475
+ kind: "warn",
4476
+ text: `${bits.join(" + ") || "Background work stopped"}. Press Ctrl+C again to exit.`
4477
+ }
4478
+ });
4479
+ return;
4480
+ }
4011
4481
  const killed = getProcessRegistry().killAll();
4012
4482
  const procTag = killed.length > 0 ? ` Killed ${killed.length} process${killed.length === 1 ? "" : "es"}.` : "";
4013
4483
  dispatch({
@@ -4020,11 +4490,64 @@ function App({
4020
4490
  return () => {
4021
4491
  process.off("SIGINT", onSigint);
4022
4492
  };
4023
- }, [director]);
4493
+ }, [director, getEternalEngine, getParallelEngine, switchAutonomy, onExit, exit]);
4494
+ const truncatePastePreview = (text, lines) => {
4495
+ const all = text.split("\n");
4496
+ if (all.length <= lines) return text;
4497
+ const head = all.slice(0, lines).join("\n");
4498
+ return `${head}
4499
+ ... (${all.length - lines} more lines)`;
4500
+ };
4501
+ const commitPaste = async (full) => {
4502
+ const builder = builderRef.current;
4503
+ if (!builder || !full) return;
4504
+ if (builder.wouldCollapse(full) || full.includes("\n")) {
4505
+ const lineCount = full.split("\n").length;
4506
+ const ph = await builder.appendPaste(full);
4507
+ const preview = truncatePastePreview(full, 6);
4508
+ dispatch({
4509
+ type: "addPlaceholder",
4510
+ ph: `${ph ?? "[pasted]"} (${lineCount} lines)`,
4511
+ content: preview
4512
+ });
4513
+ return;
4514
+ }
4515
+ const { buffer, cursor } = draftRef.current;
4516
+ const next = buffer.slice(0, cursor) + full + buffer.slice(cursor);
4517
+ setDraft(next, cursor + full.length);
4518
+ };
4024
4519
  const handleKey = async (input, key) => {
4025
4520
  if (state.status === "aborting" && state.interrupts === 0) return;
4026
4521
  if (state.confirmQueue.length > 0) return;
4027
4522
  if (inputGateRef.current) return;
4523
+ if (key.escape) {
4524
+ const now = Date.now();
4525
+ if (state.buffer.length > 0 && now - lastEscAtRef.current < ESC_DOUBLE_PRESS_MS) {
4526
+ dispatch({ type: "clearInput" });
4527
+ lastEscAtRef.current = 0;
4528
+ return;
4529
+ }
4530
+ lastEscAtRef.current = now;
4531
+ }
4532
+ if (input) {
4533
+ const paste = feedPaste(pasteAccumRef.current, input);
4534
+ if (paste) {
4535
+ pasteAccumRef.current = paste.accum;
4536
+ if (pasteFlushTimerRef.current) clearTimeout(pasteFlushTimerRef.current);
4537
+ if (paste.complete !== null) {
4538
+ pasteFlushTimerRef.current = null;
4539
+ await commitPaste(paste.complete);
4540
+ return;
4541
+ }
4542
+ pasteFlushTimerRef.current = setTimeout(() => {
4543
+ pasteFlushTimerRef.current = null;
4544
+ const full = pasteAccumRef.current;
4545
+ pasteAccumRef.current = null;
4546
+ if (full) void commitPaste(full);
4547
+ }, 250);
4548
+ return;
4549
+ }
4550
+ }
4028
4551
  const isEnter = key.return || input === "\r" || input === "\n";
4029
4552
  if (state.modelPicker.open) {
4030
4553
  if (key.escape) {
@@ -4203,6 +4726,22 @@ function App({
4203
4726
  });
4204
4727
  return;
4205
4728
  }
4729
+ if (key.ctrl && input === "f") {
4730
+ dispatch({ type: "toggleMonitor" });
4731
+ return;
4732
+ }
4733
+ if (key.ctrl && key.shift && input === "M") {
4734
+ dispatch({ type: "toggleAgentsMonitor" });
4735
+ return;
4736
+ }
4737
+ if (key.escape && state.monitorOpen) {
4738
+ dispatch({ type: "toggleMonitor" });
4739
+ return;
4740
+ }
4741
+ if (key.escape && state.agentsMonitorOpen) {
4742
+ dispatch({ type: "toggleAgentsMonitor" });
4743
+ return;
4744
+ }
4206
4745
  if (isEnter) {
4207
4746
  const now = Date.now();
4208
4747
  if (now - lastEnterAtRef.current < 50) return;
@@ -4320,40 +4859,23 @@ function App({
4320
4859
  return;
4321
4860
  }
4322
4861
  if (!input || key.ctrl || key.meta) return;
4323
- let bracketedPaste = false;
4324
- let cleanInput = input;
4325
- if (input.includes("\x1B[200~") || input.includes("\x1B[201~")) {
4326
- cleanInput = input.replace(/\x1b\[200~/g, "").replace(/\x1b\[201~/g, "");
4327
- bracketedPaste = true;
4328
- }
4329
- if (bracketedPaste || cleanInput.length > PASTE_THRESHOLD_CHARS) {
4330
- const builder = builderRef.current;
4331
- if (!builder) return;
4332
- const ph = await builder.appendPaste(cleanInput);
4333
- if (ph) {
4334
- const lineCount = cleanInput.split("\n").length;
4335
- dispatch({ type: "addPlaceholder", ph: `${ph} (${lineCount} lines)` });
4336
- } else if (cleanInput.includes("\n")) {
4337
- const lineCount = cleanInput.split("\n").length;
4338
- dispatch({ type: "addPlaceholder", ph: `[pasted] (${lineCount} lines)` });
4339
- } else {
4340
- const next2 = buffer.slice(0, cursor) + cleanInput + buffer.slice(cursor);
4341
- setDraft(next2, cursor + cleanInput.length);
4342
- }
4862
+ if (input.length > PASTE_THRESHOLD_CHARS) {
4863
+ await commitPaste(input);
4343
4864
  return;
4344
4865
  }
4345
- if (cleanInput.includes("\n")) {
4346
- const normalized = cleanInput.replace(/\r?\n/g, " ");
4866
+ if (input.includes("\n")) {
4867
+ const normalized = input.replace(/\r?\n/g, " ");
4347
4868
  const next2 = buffer.slice(0, cursor) + normalized + buffer.slice(cursor);
4348
4869
  setDraft(next2, cursor + normalized.length);
4349
4870
  return;
4350
4871
  }
4351
- const next = buffer.slice(0, cursor) + cleanInput + buffer.slice(cursor);
4352
- setDraft(next, cursor + cleanInput.length);
4872
+ const next = buffer.slice(0, cursor) + input + buffer.slice(cursor);
4873
+ setDraft(next, cursor + input.length);
4353
4874
  };
4354
4875
  const runBlocks = async (blocks) => {
4355
4876
  const ctrl = new AbortController();
4356
4877
  activeCtrlRef.current = ctrl;
4878
+ dispatch({ type: "resetInterrupts" });
4357
4879
  dispatch({ type: "status", status: "running" });
4358
4880
  try {
4359
4881
  const startedAt = Date.now();
@@ -4611,18 +5133,26 @@ User message:
4611
5133
  }
4612
5134
  if (steering) dispatch({ type: "steerConsume" });
4613
5135
  const displayText = trimmed ? steering ? `\u21AF ${trimmed}` : trimmed : "(attachments only)";
5136
+ const pasteParts = [];
5137
+ for (let i = 0; i < state.placeholders.length; i++) {
5138
+ const label = state.placeholders[i];
5139
+ const content = state.placeholderContents[i] ?? "";
5140
+ pasteParts.push(label);
5141
+ if (content) pasteParts.push(` ${content.split("\n").slice(0, 6).join("\n ")}`);
5142
+ }
5143
+ const pasteContent = pasteParts.length > 0 ? pasteParts.join("\n") : void 0;
4614
5144
  pushSubmittedHistory();
4615
- clearDraft();
5145
+ clearPlaceholdersOnly();
4616
5146
  const blocks = await builder.submit();
4617
5147
  if (state.status !== "idle") {
4618
5148
  dispatch({
4619
5149
  type: "addEntry",
4620
- entry: { kind: "user", text: displayText, queued: true }
5150
+ entry: { kind: "user", text: displayText, queued: true, pasteContent }
4621
5151
  });
4622
5152
  dispatch({ type: "enqueue", item: { displayText, blocks } });
4623
5153
  return;
4624
5154
  }
4625
- dispatch({ type: "addEntry", entry: { kind: "user", text: displayText } });
5155
+ dispatch({ type: "addEntry", entry: { kind: "user", text: displayText, pasteContent } });
4626
5156
  await runBlocks(blocks);
4627
5157
  };
4628
5158
  const bootInjectedRef = useRef(false);
@@ -4749,6 +5279,7 @@ User message:
4749
5279
  StatusBar,
4750
5280
  {
4751
5281
  model: `${liveProvider}/${liveModel}`,
5282
+ version: appVersion,
4752
5283
  state: state.status,
4753
5284
  tokenCounter,
4754
5285
  hint: renderRunningTools(state.runningTools) || state.hint,
@@ -4770,7 +5301,24 @@ User message:
4770
5301
  goalSummary: state.goalSummary
4771
5302
  }
4772
5303
  ),
4773
- director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null
5304
+ state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
5305
+ AgentsMonitor,
5306
+ {
5307
+ entries: state.fleet,
5308
+ totalCost: state.fleetCost,
5309
+ totalTokens: state.fleetTokens,
5310
+ nowTick
5311
+ }
5312
+ ) : null,
5313
+ state.monitorOpen ? /* @__PURE__ */ jsx(
5314
+ FleetMonitor,
5315
+ {
5316
+ entries: state.fleet,
5317
+ totalCost: state.fleetCost,
5318
+ totalTokens: state.fleetTokens,
5319
+ nowTick
5320
+ }
5321
+ ) : director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null
4774
5322
  ] });
4775
5323
  }
4776
5324
  function renderRunningTools(running) {