@wrongstack/tui 0.41.0 → 0.54.1

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
@@ -54,6 +54,7 @@ function StatusBar({
54
54
  git,
55
55
  subagentCount = 0,
56
56
  context,
57
+ brain,
57
58
  projectName,
58
59
  processCount,
59
60
  hiddenItems,
@@ -79,7 +80,8 @@ function StatusBar({
79
80
  const { label: stateLabel, color: stateColor } = stateChip(state, fleet?.running ?? 0);
80
81
  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;
81
82
  const fleetHasActivity = fleet && (fleet.running > 0 || fleet.idle > 0 || fleet.pending > 0 || fleet.completed > 0) || subagentCount > 0;
82
- const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity;
83
+ const hasBrainActivity = !!brain && brain.state !== "idle";
84
+ const hasThirdLine = todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity || hasBrainActivity;
83
85
  return /* @__PURE__ */ jsxs(
84
86
  Box,
85
87
  {
@@ -316,6 +318,10 @@ function StatusBar({
316
318
  " agent",
317
319
  subagentCount === 1 ? "" : "s"
318
320
  ] })
321
+ ] }) : null,
322
+ hasBrainActivity && brain ? /* @__PURE__ */ jsxs(Fragment, { children: [
323
+ todos && (todos.pending > 0 || todos.inProgress > 0 || todos.completed > 0) || plan && (plan.open > 0 || plan.inProgress > 0 || plan.done > 0) || fleetHasActivity ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
324
+ /* @__PURE__ */ jsx(BrainChip, { brain })
319
325
  ] }) : null
320
326
  ] }) : null,
321
327
  fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
@@ -348,6 +354,18 @@ function StatusBar({
348
354
  }
349
355
  );
350
356
  }
357
+ function BrainChip({ brain }) {
358
+ const color = brain.state === "denied" ? "red" : brain.state === "ask_human" ? "yellow" : brain.state === "deciding" ? "magenta" : "cyan";
359
+ const label = brain.state === "deciding" ? "deciding" : brain.state === "ask_human" ? "human" : brain.state;
360
+ const scope = brain.source ? ` ${brain.source}` : "";
361
+ const summary = brain.summary ? ` \xB7 ${brain.summary.slice(0, 40)}` : "";
362
+ return /* @__PURE__ */ jsxs(Text, { color, children: [
363
+ "\u{1F9E0} ",
364
+ label,
365
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: scope }),
366
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: summary })
367
+ ] });
368
+ }
351
369
  function EternalStageChip({
352
370
  stage
353
371
  }) {
@@ -376,6 +394,25 @@ function EternalStageChip({
376
394
  ]
377
395
  }
378
396
  );
397
+ case "decompose":
398
+ return /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2B07 decompose" });
399
+ case "fanout":
400
+ return /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
401
+ "\u21C4 fanout: ",
402
+ stage.slots
403
+ ] });
404
+ case "await":
405
+ return /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
406
+ "\u23F3 await: ",
407
+ stage.taskIds.length
408
+ ] });
409
+ case "aggregate":
410
+ return /* @__PURE__ */ jsxs(Text, { color: stage.goalComplete ? "green" : "magenta", children: [
411
+ "\u21A9 aggregate: ",
412
+ stage.successCount,
413
+ "/",
414
+ stage.total
415
+ ] });
379
416
  case "sleep":
380
417
  return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
381
418
  "\u{1F4A4} sleep ",
@@ -734,6 +771,9 @@ function fmtTokens2(n) {
734
771
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
735
772
  return `${(n / 1e6).toFixed(1)}M`;
736
773
  }
774
+ function fmtExactTokens(n) {
775
+ return `${Math.round(n).toLocaleString("en-US")} tok`;
776
+ }
737
777
  function snippet(s2, max = 72) {
738
778
  const oneLine2 = s2.replace(/\s+/g, " ").trim();
739
779
  if (oneLine2.length <= max) return oneLine2;
@@ -831,6 +871,10 @@ function AgentsMonitor({
831
871
  /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
832
872
  /* @__PURE__ */ jsx(Text, { bold: true, children: e.name }),
833
873
  fmtModelLabel(e.provider, e.model) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtModelLabel(e.provider, e.model) }) : null,
874
+ e.ctxMaxTokens && e.ctxMaxTokens > 0 ? /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
875
+ "ctx max ",
876
+ fmtExactTokens(e.ctxMaxTokens)
877
+ ] }) : null,
834
878
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
835
879
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed }),
836
880
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
@@ -952,6 +996,92 @@ function AutonomyPicker({
952
996
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
953
997
  ] });
954
998
  }
999
+ function riskColor(risk) {
1000
+ switch (risk) {
1001
+ case "low":
1002
+ return "green";
1003
+ case "medium":
1004
+ return "cyan";
1005
+ case "high":
1006
+ return "yellow";
1007
+ case "critical":
1008
+ return "red";
1009
+ default:
1010
+ return "white";
1011
+ }
1012
+ }
1013
+ function optionKey(index) {
1014
+ return String.fromCharCode("A".charCodeAt(0) + index);
1015
+ }
1016
+ function contextLines(context) {
1017
+ if (!context?.trim()) return [];
1018
+ return context.trim().split("\n").slice(0, 5);
1019
+ }
1020
+ function BrainDecisionPrompt({
1021
+ requestId,
1022
+ source,
1023
+ risk,
1024
+ question,
1025
+ context,
1026
+ options = [],
1027
+ onAnswer
1028
+ }) {
1029
+ const color = riskColor(risk);
1030
+ const ctx = contextLines(context);
1031
+ useInput((input, key) => {
1032
+ if (!onAnswer) return;
1033
+ if (key.escape || input.toLowerCase() === "d") {
1034
+ onAnswer({ id: requestId, deny: true, text: "Denied by human from TUI." });
1035
+ return;
1036
+ }
1037
+ const ch = input.toLowerCase();
1038
+ const index = ch >= "a" && ch <= "z" ? ch.charCodeAt(0) - "a".charCodeAt(0) : Number(ch) - 1;
1039
+ const option = Number.isInteger(index) && index >= 0 ? options[index] : void 0;
1040
+ if (option) onAnswer({ id: requestId, optionId: option.id, text: option.label });
1041
+ });
1042
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
1043
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "\u{1F9E0} BRAIN REQUIRES HUMAN DECISION" }) }),
1044
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1045
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Source:" }),
1046
+ /* @__PURE__ */ jsx(Text, { children: source }),
1047
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Risk:" }),
1048
+ /* @__PURE__ */ jsx(Text, { color, children: risk })
1049
+ ] }),
1050
+ /* @__PURE__ */ jsx(Text, { color: "white", children: question }),
1051
+ ctx.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1052
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Context:" }),
1053
+ ctx.map((line, index) => (
1054
+ // biome-ignore lint/suspicious/noArrayIndexKey: context lines are static for this prompt render
1055
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: line }, index)
1056
+ ))
1057
+ ] }) : null,
1058
+ options.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1059
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Options:" }),
1060
+ options.slice(0, 6).map((option, index) => {
1061
+ const key = optionKey(index);
1062
+ const optionColor = riskColor(String(option.risk ?? risk));
1063
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1064
+ /* @__PURE__ */ jsxs(Text, { children: [
1065
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
1066
+ "[",
1067
+ key,
1068
+ "]"
1069
+ ] }),
1070
+ " ",
1071
+ /* @__PURE__ */ jsx(Text, { color: optionColor, children: option.label }),
1072
+ option.recommended ? /* @__PURE__ */ jsx(Text, { color: "green", children: " recommended" }) : null
1073
+ ] }),
1074
+ option.consequence ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1075
+ " ",
1076
+ option.consequence
1077
+ ] }) : null
1078
+ ] }, option.id);
1079
+ })
1080
+ ] }) : null,
1081
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1082
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press A/B/C or 1/2/3 to answer; Esc or D denies with the safe default." })
1083
+ ] });
1084
+ }
955
1085
  function CheckpointTimeline({
956
1086
  checkpoints,
957
1087
  selected,
@@ -2318,6 +2448,30 @@ function DiffBlock({ rows, hidden }) {
2318
2448
  hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
2319
2449
  ] });
2320
2450
  }
2451
+ function brainStatusStyle(status) {
2452
+ switch (status) {
2453
+ case "thinking":
2454
+ return { icon: "\u2026", color: "magenta" };
2455
+ case "answered":
2456
+ return { icon: "\u2696", color: "cyan" };
2457
+ case "ask_human":
2458
+ return { icon: "?", color: "yellow" };
2459
+ case "denied":
2460
+ return { icon: "\xD7", color: "red" };
2461
+ }
2462
+ }
2463
+ function brainRiskColor(risk) {
2464
+ switch (risk) {
2465
+ case "low":
2466
+ return "green";
2467
+ case "medium":
2468
+ return "cyan";
2469
+ case "high":
2470
+ return "yellow";
2471
+ case "critical":
2472
+ return "red";
2473
+ }
2474
+ }
2321
2475
  var Entry = React4.memo(function Entry2({
2322
2476
  entry,
2323
2477
  termWidth
@@ -2450,6 +2604,38 @@ var Entry = React4.memo(function Entry2({
2450
2604
  );
2451
2605
  case "turn-summary":
2452
2606
  return /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.text });
2607
+ case "brain": {
2608
+ const statusStyle = brainStatusStyle(entry.status);
2609
+ const riskColor2 = brainRiskColor(entry.risk);
2610
+ return /* @__PURE__ */ jsxs(
2611
+ Box,
2612
+ {
2613
+ flexDirection: "column",
2614
+ marginY: 1,
2615
+ borderStyle: "single",
2616
+ borderTop: false,
2617
+ borderRight: false,
2618
+ borderBottom: false,
2619
+ borderColor: "magenta",
2620
+ paddingLeft: 1,
2621
+ children: [
2622
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
2623
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "BRAIN" }),
2624
+ /* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: statusStyle.icon }),
2625
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.source }),
2626
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
2627
+ /* @__PURE__ */ jsx(Text, { color: riskColor2, children: entry.risk })
2628
+ ] }),
2629
+ /* @__PURE__ */ jsx(Text, { color: "white", children: entry.question }),
2630
+ entry.decision ? /* @__PURE__ */ jsxs(Text, { children: [
2631
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Decision: " }),
2632
+ /* @__PURE__ */ jsx(Text, { color: statusStyle.color, children: entry.decision })
2633
+ ] }) : null,
2634
+ entry.rationale ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.rationale }) : null
2635
+ ]
2636
+ }
2637
+ );
2638
+ }
2453
2639
  case "confirm":
2454
2640
  return /* @__PURE__ */ jsxs(
2455
2641
  Box,
@@ -3583,12 +3769,28 @@ var LiveActivityStrip = React4.memo(function LiveActivityStrip2({
3583
3769
  ] }) }) : null
3584
3770
  ] });
3585
3771
  });
3772
+ var MAX_VISIBLE = 10;
3773
+ function getVisibleWindow(selected, total) {
3774
+ const half = Math.floor(MAX_VISIBLE / 2);
3775
+ let start = selected - half;
3776
+ let end = start + MAX_VISIBLE;
3777
+ if (start < 0) {
3778
+ start = 0;
3779
+ end = Math.min(total, MAX_VISIBLE);
3780
+ }
3781
+ if (end > total) {
3782
+ end = total;
3783
+ start = Math.max(0, end - MAX_VISIBLE);
3784
+ }
3785
+ return { start, end };
3786
+ }
3586
3787
  function ModelPicker({
3587
3788
  step,
3588
3789
  providerOptions,
3589
- modelOptions,
3790
+ filteredOptions,
3590
3791
  selected,
3591
3792
  pickedProviderId,
3793
+ searchQuery,
3592
3794
  hint
3593
3795
  }) {
3594
3796
  if (step === "provider") {
@@ -3613,17 +3815,47 @@ function ModelPicker({
3613
3815
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
3614
3816
  ] });
3615
3817
  }
3818
+ const total = filteredOptions.length;
3819
+ const { start, end } = getVisibleWindow(selected, total);
3820
+ const visibleItems = filteredOptions.slice(start, end);
3821
+ const searchHint = searchQuery ? ` | filter:"${searchQuery}" \u2192 ${total} match${total === 1 ? "" : "es"}` : total > MAX_VISIBLE ? ` (${total} models \u2014 type to filter)` : "";
3616
3822
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
3617
3823
  /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
3618
- "\u2501\u2501 Switch model \u2014 Step 2/2: Pick model (",
3824
+ "\u2501\u2501 Switch model \u2014 Step 2/2: Pick model ",
3825
+ "(",
3619
3826
  pickedProviderId,
3620
- ") \u2501\u2501"
3827
+ searchHint,
3828
+ ")",
3829
+ " \u2501\u2501"
3830
+ ] }),
3831
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit \xB7 type to filter" }),
3832
+ total === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: searchQuery ? `(no models match "${searchQuery}")` : "(no models known for this provider)" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3833
+ start > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
3834
+ "\u25B2 ",
3835
+ start,
3836
+ " above"
3837
+ ] }),
3838
+ visibleItems.map((id, vi) => {
3839
+ const absoluteIndex = start + vi;
3840
+ return /* @__PURE__ */ jsxs(
3841
+ Text,
3842
+ {
3843
+ color: absoluteIndex === selected ? "cyan" : void 0,
3844
+ inverse: absoluteIndex === selected,
3845
+ children: [
3846
+ absoluteIndex === selected ? "\u203A " : " ",
3847
+ id
3848
+ ]
3849
+ },
3850
+ id
3851
+ );
3852
+ }),
3853
+ end < total && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
3854
+ "\u25BC ",
3855
+ total - end,
3856
+ " below"
3857
+ ] })
3621
3858
  ] }),
3622
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit" }),
3623
- 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: [
3624
- i === selected ? "\u203A " : " ",
3625
- id
3626
- ] }, id)),
3627
3859
  hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
3628
3860
  ] });
3629
3861
  }
@@ -4574,6 +4806,21 @@ function reducer(state, action) {
4574
4806
  return { ...state, interrupts: 0 };
4575
4807
  case "hint":
4576
4808
  return { ...state, hint: action.text };
4809
+ case "brainStatus":
4810
+ return {
4811
+ ...state,
4812
+ brain: {
4813
+ state: action.state,
4814
+ source: action.source,
4815
+ risk: action.risk,
4816
+ summary: action.summary,
4817
+ updatedAt: Date.now()
4818
+ }
4819
+ };
4820
+ case "brainPromptSet":
4821
+ return { ...state, brainPrompt: action.prompt };
4822
+ case "brainPromptClear":
4823
+ return { ...state, brainPrompt: null };
4577
4824
  case "pickerOpen":
4578
4825
  return {
4579
4826
  ...state,
@@ -4710,8 +4957,10 @@ function reducer(state, action) {
4710
4957
  step: "provider",
4711
4958
  providerOptions: action.providers,
4712
4959
  modelOptions: [],
4960
+ filteredOptions: [],
4713
4961
  selected: 0,
4714
- hint: void 0
4962
+ hint: void 0,
4963
+ searchQuery: ""
4715
4964
  }
4716
4965
  };
4717
4966
  case "modelPickerClose":
@@ -4722,12 +4971,15 @@ function reducer(state, action) {
4722
4971
  step: "provider",
4723
4972
  providerOptions: [],
4724
4973
  modelOptions: [],
4725
- selected: 0
4974
+ filteredOptions: [],
4975
+ selected: 0,
4976
+ searchQuery: ""
4726
4977
  }
4727
4978
  };
4728
4979
  case "modelPickerMove": {
4729
4980
  if (!state.modelPicker.open) return state;
4730
- const len = state.modelPicker.step === "provider" ? state.modelPicker.providerOptions.length : state.modelPicker.modelOptions.length;
4981
+ const list = state.modelPicker.step === "provider" ? state.modelPicker.providerOptions : state.modelPicker.filteredOptions;
4982
+ const len = list.length;
4731
4983
  if (len === 0) return state;
4732
4984
  const next = (state.modelPicker.selected + action.delta + len) % len;
4733
4985
  return {
@@ -4742,9 +4994,11 @@ function reducer(state, action) {
4742
4994
  ...state.modelPicker,
4743
4995
  step: "model",
4744
4996
  modelOptions: action.models,
4997
+ filteredOptions: action.models,
4745
4998
  selected: 0,
4746
4999
  pickedProviderId: action.providerId,
4747
- hint: void 0
5000
+ hint: void 0,
5001
+ searchQuery: ""
4748
5002
  }
4749
5003
  };
4750
5004
  case "modelPickerBack":
@@ -4754,11 +5008,29 @@ function reducer(state, action) {
4754
5008
  ...state.modelPicker,
4755
5009
  step: "provider",
4756
5010
  modelOptions: [],
5011
+ filteredOptions: [],
4757
5012
  selected: 0,
4758
5013
  pickedProviderId: void 0,
5014
+ hint: void 0,
5015
+ searchQuery: ""
5016
+ }
5017
+ };
5018
+ case "modelPickerSearch": {
5019
+ if (!state.modelPicker.open || state.modelPicker.step !== "model") return state;
5020
+ const q = action.query.toLowerCase();
5021
+ const filtered = q ? state.modelPicker.modelOptions.filter((id) => id.toLowerCase().includes(q)) : state.modelPicker.modelOptions;
5022
+ const selected = filtered.length > 0 ? Math.min(state.modelPicker.selected, filtered.length - 1) : 0;
5023
+ return {
5024
+ ...state,
5025
+ modelPicker: {
5026
+ ...state.modelPicker,
5027
+ filteredOptions: filtered,
5028
+ selected,
5029
+ searchQuery: action.query,
4759
5030
  hint: void 0
4760
5031
  }
4761
5032
  };
5033
+ }
4762
5034
  case "modelPickerHint":
4763
5035
  return {
4764
5036
  ...state,
@@ -5534,6 +5806,7 @@ function App({
5534
5806
  const { exit } = useApp();
5535
5807
  const [liveModel, setLiveModel] = useState(model);
5536
5808
  const [liveProvider, setLiveProvider] = useState(provider ?? "agent");
5809
+ const [activeMaxContext, setActiveMaxContext] = useState(effectiveMaxContext);
5537
5810
  const [yoloLive, setYoloLive] = useState(yolo);
5538
5811
  const [autonomyLive, setAutonomyLive] = useState(getAutonomy?.() ?? "off");
5539
5812
  const [hiddenItems, setHiddenItems] = useState(statuslineHiddenItems);
@@ -5602,6 +5875,8 @@ function App({
5602
5875
  steeringPending: false,
5603
5876
  steerSnapshot: null,
5604
5877
  hint: "",
5878
+ brain: { state: "idle" },
5879
+ brainPrompt: null,
5605
5880
  nextId: 1,
5606
5881
  picker: { open: false, query: "", matches: [], selected: 0 },
5607
5882
  slashPicker: { open: false, query: "", matches: [], selected: 0 },
@@ -5615,7 +5890,9 @@ function App({
5615
5890
  step: "provider",
5616
5891
  providerOptions: [],
5617
5892
  modelOptions: [],
5618
- selected: 0
5893
+ filteredOptions: [],
5894
+ selected: 0,
5895
+ searchQuery: ""
5619
5896
  },
5620
5897
  autonomyPicker: { open: false, options: [], selected: 0 },
5621
5898
  settingsPicker: { open: false, field: 0, mode: "off", delayMs: 0 },
@@ -5943,7 +6220,7 @@ function App({
5943
6220
  clearInterval(t);
5944
6221
  };
5945
6222
  }, [agent.ctx.cwd]);
5946
- const maxContext = effectiveMaxContext ?? agent.ctx.provider.capabilities.maxContext;
6223
+ const maxContext = activeMaxContext ?? agent.ctx.provider.capabilities.maxContext;
5947
6224
  const currentContextTokens = (tokenCounter?.currentRequestTokens()?.input ?? 0) + (tokenCounter?.currentRequestTokens()?.cacheRead ?? 0);
5948
6225
  const contextWindow = useMemo(() => {
5949
6226
  void state.contextChipVersion;
@@ -5989,10 +6266,10 @@ function App({
5989
6266
  currentTool: state.leader.currentTool,
5990
6267
  ctxPct: state.leader.ctxPct,
5991
6268
  ctxTokens: state.leader.ctxTokens,
5992
- ctxMaxTokens: state.leader.ctxMaxTokens
6269
+ ctxMaxTokens: state.leader.ctxMaxTokens ?? effectiveMaxContext
5993
6270
  };
5994
6271
  return { leader: leaderEntry, ...state.fleet };
5995
- }, [state.fleet, state.leader, state.status, provider, model]);
6272
+ }, [state.fleet, state.leader, state.status, provider, model, effectiveMaxContext]);
5996
6273
  const STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
5997
6274
  const labelsRef = useRef(/* @__PURE__ */ new Map());
5998
6275
  const labelFor = (id, name) => {
@@ -6769,6 +7046,7 @@ function App({
6769
7046
  });
6770
7047
  });
6771
7048
  const offLeaderCtxPct = events.on("ctx.pct", (e) => {
7049
+ setActiveMaxContext(e.maxContext);
6772
7050
  dispatch({
6773
7051
  type: "leaderCtxPct",
6774
7052
  load: e.load,
@@ -6776,6 +7054,9 @@ function App({
6776
7054
  maxContext: e.maxContext
6777
7055
  });
6778
7056
  });
7057
+ const offLeaderMaxContext = events.on("ctx.max_context", (e) => {
7058
+ if (e.maxContext > 0) setActiveMaxContext(e.maxContext);
7059
+ });
6779
7060
  const offTool = events.on("subagent.tool_executed", (e) => {
6780
7061
  dispatch({
6781
7062
  type: "fleetTool",
@@ -6796,6 +7077,7 @@ function App({
6796
7077
  offIterationSummary();
6797
7078
  offCtxPct();
6798
7079
  offLeaderCtxPct();
7080
+ offLeaderMaxContext();
6799
7081
  offTool();
6800
7082
  };
6801
7083
  }, [events, director]);
@@ -6823,6 +7105,71 @@ function App({
6823
7105
  offRewound();
6824
7106
  };
6825
7107
  }, [events, onClearHistory]);
7108
+ useEffect(() => {
7109
+ const requestSummary = (request) => `${request.source}: ${request.question}`.slice(0, 80);
7110
+ const addBrainEntry = (status, payload) => {
7111
+ const p = payload;
7112
+ const decision = p.decision.optionId ?? p.decision.text ?? p.decision.reason ?? p.decision.prompt ?? p.decision.type;
7113
+ dispatch({
7114
+ type: "brainStatus",
7115
+ state: status,
7116
+ source: p.request.source,
7117
+ risk: p.request.risk,
7118
+ summary: decision
7119
+ });
7120
+ if (status === "ask_human") {
7121
+ dispatch({
7122
+ type: "brainPromptSet",
7123
+ prompt: {
7124
+ requestId: p.request.id,
7125
+ source: p.request.source,
7126
+ risk: p.request.risk,
7127
+ question: p.request.question,
7128
+ context: p.request.context,
7129
+ options: p.request.options
7130
+ }
7131
+ });
7132
+ } else {
7133
+ dispatch({ type: "brainPromptClear" });
7134
+ }
7135
+ dispatch({
7136
+ type: "addEntry",
7137
+ entry: {
7138
+ kind: "brain",
7139
+ status,
7140
+ source: p.request.source,
7141
+ risk: p.request.risk,
7142
+ question: p.request.question,
7143
+ decision,
7144
+ rationale: p.decision.rationale
7145
+ }
7146
+ });
7147
+ };
7148
+ const offRequested = events.on("brain.decision_requested", ({ request }) => {
7149
+ dispatch({
7150
+ type: "brainStatus",
7151
+ state: "deciding",
7152
+ source: request.source,
7153
+ risk: request.risk,
7154
+ summary: requestSummary(request)
7155
+ });
7156
+ });
7157
+ const offAnswered = events.on("brain.decision_answered", (payload) => {
7158
+ addBrainEntry("answered", payload);
7159
+ });
7160
+ const offAskHuman = events.on("brain.decision_ask_human", (payload) => {
7161
+ addBrainEntry("ask_human", payload);
7162
+ });
7163
+ const offDenied = events.on("brain.decision_denied", (payload) => {
7164
+ addBrainEntry("denied", payload);
7165
+ });
7166
+ return () => {
7167
+ offRequested();
7168
+ offAnswered();
7169
+ offAskHuman();
7170
+ offDenied();
7171
+ };
7172
+ }, [events]);
6826
7173
  useEffect(() => {
6827
7174
  if (!subscribeAutoPhase) return;
6828
7175
  const handler = (event, payload) => {
@@ -7590,6 +7937,19 @@ function App({
7590
7937
  dispatch({ type: "modelPickerMove", delta: 1 });
7591
7938
  return;
7592
7939
  }
7940
+ if (state.modelPicker.step === "model" && input && !key.return && !key.backspace) {
7941
+ dispatch({ type: "modelPickerSearch", query: state.modelPicker.searchQuery + input });
7942
+ return;
7943
+ }
7944
+ if (state.modelPicker.step === "model" && key.backspace) {
7945
+ const q = state.modelPicker.searchQuery;
7946
+ if (q.length > 0) {
7947
+ dispatch({ type: "modelPickerSearch", query: q.slice(0, -1) });
7948
+ } else {
7949
+ dispatch({ type: "modelPickerBack" });
7950
+ }
7951
+ return;
7952
+ }
7593
7953
  if (isEnter) {
7594
7954
  inputGateRef.current = true;
7595
7955
  try {
@@ -7604,7 +7964,7 @@ function App({
7604
7964
  return;
7605
7965
  }
7606
7966
  const providerId = state.modelPicker.pickedProviderId;
7607
- const modelId = state.modelPicker.modelOptions[state.modelPicker.selected];
7967
+ const modelId = state.modelPicker.filteredOptions[state.modelPicker.selected];
7608
7968
  if (!providerId || !modelId) return;
7609
7969
  const err = switchProviderAndModel?.(providerId, modelId);
7610
7970
  if (err) {
@@ -7613,6 +7973,7 @@ function App({
7613
7973
  }
7614
7974
  setLiveProvider(providerId);
7615
7975
  setLiveModel(modelId);
7976
+ setActiveMaxContext(agent.ctx.provider.capabilities.maxContext);
7616
7977
  dispatch({
7617
7978
  type: "addEntry",
7618
7979
  entry: { kind: "info", text: `Switched to ${providerId} / ${modelId}.` }
@@ -8213,6 +8574,10 @@ function App({
8213
8574
  if (ctxModel && ctxModel !== liveModel) setLiveModel(ctxModel);
8214
8575
  const ctxProviderId = agent.ctx.provider?.id;
8215
8576
  if (ctxProviderId && ctxProviderId !== liveProvider) setLiveProvider(ctxProviderId);
8577
+ const ctxMaxContext = agent.ctx.provider.capabilities.maxContext;
8578
+ if (ctxMaxContext > 0 && ctxMaxContext !== activeMaxContext) {
8579
+ setActiveMaxContext(ctxMaxContext);
8580
+ }
8216
8581
  if (getYolo) {
8217
8582
  const currentYolo = getYolo();
8218
8583
  if (currentYolo !== yoloLive) setYoloLive(currentYolo);
@@ -8405,8 +8770,10 @@ User message:
8405
8770
  step: state.modelPicker.step,
8406
8771
  providerOptions: state.modelPicker.providerOptions,
8407
8772
  modelOptions: state.modelPicker.modelOptions,
8773
+ filteredOptions: state.modelPicker.filteredOptions,
8408
8774
  selected: state.modelPicker.selected,
8409
8775
  pickedProviderId: state.modelPicker.pickedProviderId,
8776
+ searchQuery: state.modelPicker.searchQuery,
8410
8777
  hint: state.modelPicker.hint
8411
8778
  }
8412
8779
  ) : null,
@@ -8437,6 +8804,16 @@ User message:
8437
8804
  onClose: () => dispatch({ type: "rewindOverlayClose" })
8438
8805
  }
8439
8806
  ) : null,
8807
+ state.brainPrompt ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx(
8808
+ BrainDecisionPrompt,
8809
+ {
8810
+ ...state.brainPrompt,
8811
+ onAnswer: (answer) => {
8812
+ events.emit("brain.human_answered", { ...answer, at: Date.now() });
8813
+ dispatch({ type: "brainPromptClear" });
8814
+ }
8815
+ }
8816
+ ) }) : null,
8440
8817
  state.confirmQueue.length > 0 && (() => {
8441
8818
  const head = state.confirmQueue[0];
8442
8819
  let resolved = false;
@@ -8474,6 +8851,7 @@ User message:
8474
8851
  fleet: fleetCounts,
8475
8852
  git: gitInfo,
8476
8853
  context: contextWindow,
8854
+ brain: state.brain,
8477
8855
  projectName,
8478
8856
  subagentCount: Object.keys(state.fleet).length,
8479
8857
  processCount: getProcessRegistry().activeCount,