@wrongstack/tui 0.256.0 → 0.257.0

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.d.ts CHANGED
@@ -297,6 +297,10 @@ interface RunTuiOptions {
297
297
  type: 'clearHistory';
298
298
  } | {
299
299
  type: 'resetContextChip';
300
+ } | {
301
+ type: 'streamReset';
302
+ } | {
303
+ type: 'toolStreamClear';
300
304
  }>) => void) | undefined;
301
305
  /**
302
306
  * Live director instance. When set, the TUI renders a fleet panel
@@ -430,6 +434,15 @@ interface RunTuiOptions {
430
434
  * Used by the TUI to display and auto-submit next steps in 'auto' mode.
431
435
  */
432
436
  getSuggestions?: (() => string[]) | undefined;
437
+ /**
438
+ * Retrieve current auto suggestions (items with auto="true" attribute).
439
+ * Used by YOLO+auto mode for automatic next-step submission.
440
+ */
441
+ getAutoSuggestions?: (() => string[]) | undefined;
442
+ /**
443
+ * Autonomy next prompt template for YOLO+auto mode. Contains {{suggestion}} placeholder.
444
+ */
445
+ autonomyNextPrompt?: string | undefined;
433
446
  /**
434
447
  * Write parsed next steps into the shared suggestion store.
435
448
  * Called by the Entry component after parsing each assistant message
@@ -574,6 +587,8 @@ declare function replaySessionEvents(events: SessionEvent[], startId: number): H
574
587
  interface ParsedNextStep {
575
588
  index: number;
576
589
  text: string;
590
+ /** Whether this item has auto="true" attribute for YOLO+auto autonomy mode. */
591
+ auto?: boolean;
577
592
  }
578
593
  interface ParseNextStepsResult {
579
594
  /** Matched steps with their original index and stripped text. */
@@ -585,6 +600,8 @@ interface ParseNextStepsResult {
585
600
  * Used by entry.tsx to strip suggestions from the rendered message body.
586
601
  */
587
602
  stripped: string;
603
+ /** Flat string array — texts of items with auto="true" attribute only. */
604
+ autoTexts: string[];
588
605
  }
589
606
  /**
590
607
  * Parse "<next_steps>" or "💡 Next steps" blocks from assistant output (or raw numbered lines).
package/dist/index.js CHANGED
@@ -2850,19 +2850,36 @@ var QUOTE_RE = /^>\s?(.*)$/;
2850
2850
  function MarkdownView({
2851
2851
  text,
2852
2852
  termWidth,
2853
- contentWidth
2853
+ contentWidth,
2854
+ tableWidth,
2855
+ panelBackground
2854
2856
  }) {
2855
2857
  const lines = text.split("\n");
2856
2858
  const rows = [];
2857
2859
  let i = 0;
2858
2860
  let key = 0;
2859
- const tableBudget = Math.max(20, contentWidth ?? termWidth);
2861
+ const tableBudget = Math.max(20, tableWidth ?? contentWidth ?? termWidth);
2860
2862
  while (i < lines.length) {
2861
2863
  const tableEnd = detectTable(lines, i);
2862
2864
  if (tableEnd > i) {
2863
- rows.push(
2864
- /* @__PURE__ */ jsx(Box, { width: tableBudget, backgroundColor: "transparent", children: /* @__PURE__ */ jsx(Text, { children: renderTable(lines.slice(i, tableEnd), tableBudget) }) }, `t${key++}`)
2865
- );
2865
+ const tableText = renderTable(lines.slice(i, tableEnd), tableBudget);
2866
+ if (panelBackground) {
2867
+ const tableLines = tableText.split("\n");
2868
+ rows.push(
2869
+ /* @__PURE__ */ jsx(Box, { width: tableBudget, children: tableLines.map((line2, li) => {
2870
+ const lineW = strWidth(line2);
2871
+ const padding = tableBudget - lineW;
2872
+ return /* @__PURE__ */ jsxs(Text, { children: [
2873
+ /* @__PURE__ */ jsx(Text, { children: line2 }),
2874
+ padding > 0 && /* @__PURE__ */ jsx(Text, { backgroundColor: panelBackground, children: " ".repeat(padding) })
2875
+ ] }, li);
2876
+ }) }, `t${key++}`)
2877
+ );
2878
+ } else {
2879
+ rows.push(
2880
+ /* @__PURE__ */ jsx(Box, { width: tableBudget, backgroundColor: "transparent", children: /* @__PURE__ */ jsx(Text, { children: tableText }) }, `t${key++}`)
2881
+ );
2882
+ }
2866
2883
  i = tableEnd;
2867
2884
  continue;
2868
2885
  }
@@ -3682,10 +3699,11 @@ function extractDiffPreview(toolName, output) {
3682
3699
  if (!diff || !diff.trim() || diff.startsWith("(no-op")) return void 0;
3683
3700
  return parseUnifiedDiff(diff, DIFF_MAX_LINES);
3684
3701
  }
3702
+ var MESSAGE_PANEL_BORDER_WIDTH = 1;
3685
3703
  var MESSAGE_PANEL_CHROME_WIDTH = 2;
3686
- var MESSAGE_PANEL_MARGIN = 2;
3704
+ var ASSISTANT_BG = "#1e1e2e";
3687
3705
  function assistantContentWidth(termWidth) {
3688
- return Math.max(20, termWidth - MESSAGE_PANEL_CHROME_WIDTH - MESSAGE_PANEL_MARGIN * 2);
3706
+ return Math.max(20, termWidth - MESSAGE_PANEL_CHROME_WIDTH);
3689
3707
  }
3690
3708
  function splitFencedBlocks(text) {
3691
3709
  const lines = text.split("\n");
@@ -3723,7 +3741,8 @@ function splitFencedBlocks(text) {
3723
3741
  function AssistantBody({
3724
3742
  text,
3725
3743
  termWidth,
3726
- contentWidth
3744
+ contentWidth,
3745
+ panelBackground
3727
3746
  }) {
3728
3747
  const segments = splitFencedBlocks(text);
3729
3748
  const inner = contentWidth ?? termWidth;
@@ -3733,7 +3752,16 @@ function AssistantBody({
3733
3752
  /* @__PURE__ */ jsx(CodeBlock, { code: seg.text, lang: seg.lang ?? "plain", contentWidth: inner }, i)
3734
3753
  ) : (
3735
3754
  // biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
3736
- /* @__PURE__ */ jsx(MarkdownView, { text: seg.text, termWidth: inner }, i)
3755
+ /* @__PURE__ */ jsx(
3756
+ MarkdownView,
3757
+ {
3758
+ text: seg.text,
3759
+ termWidth: inner,
3760
+ panelBackground,
3761
+ tableWidth: termWidth - MESSAGE_PANEL_BORDER_WIDTH
3762
+ },
3763
+ i
3764
+ )
3737
3765
  )
3738
3766
  ) });
3739
3767
  }
@@ -3826,7 +3854,7 @@ var PERMISSIVE_HEADING_PATTERNS = [
3826
3854
  { re: /\n{1,2}Next steps?\s*\n+/i, label: "plain" },
3827
3855
  { re: /<next_steps>\s*\n+/i, label: "xml-tag" }
3828
3856
  ];
3829
- var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+)$/;
3857
+ var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+?)(\s+auto="true")?$/;
3830
3858
  var MAX_STEPS = 6;
3831
3859
  function parseNextSteps(content, strict = false, requireHeading = true) {
3832
3860
  if (requireHeading) {
@@ -3845,6 +3873,7 @@ function parseRawNumbered(content) {
3845
3873
  if (!m) continue;
3846
3874
  const numPart = m[1];
3847
3875
  let text = m[2].trim();
3876
+ const hasAuto = !!m[3];
3848
3877
  let index;
3849
3878
  if (numPart !== void 0) {
3850
3879
  index = Number.parseInt(numPart, 10);
@@ -3854,16 +3883,21 @@ function parseRawNumbered(content) {
3854
3883
  if (seenNumbers.has(index)) continue;
3855
3884
  if (text.length < 3) continue;
3856
3885
  seenNumbers.add(index);
3857
- steps.push({ index, text });
3886
+ steps.push({ index, text, auto: hasAuto });
3858
3887
  if (steps.length >= MAX_STEPS) break;
3859
3888
  }
3860
- return { steps, texts: steps.map((s2) => s2.text), stripped: content };
3889
+ return {
3890
+ steps,
3891
+ texts: steps.map((s2) => s2.text),
3892
+ stripped: content,
3893
+ autoTexts: steps.filter((s2) => s2.auto).map((s2) => s2.text)
3894
+ };
3861
3895
  }
3862
3896
  function parseWithHeading(content, strict) {
3863
3897
  const headingRe = strict ? STRICT_HEADING_RE : buildPermissiveHeadingRe();
3864
3898
  const headingMatch = headingRe.exec(content);
3865
3899
  if (!headingMatch) {
3866
- return { steps: [], texts: [], stripped: content };
3900
+ return { steps: [], texts: [], stripped: content, autoTexts: [] };
3867
3901
  }
3868
3902
  const headingEnd = headingMatch.index + headingMatch[0].length;
3869
3903
  const afterHeading = content.slice(headingEnd);
@@ -3877,6 +3911,7 @@ function parseWithHeading(content, strict) {
3877
3911
  if (!m) break;
3878
3912
  const numPart = m[1];
3879
3913
  let text = m[2].trim();
3914
+ const hasAuto = !!m[3];
3880
3915
  let index;
3881
3916
  if (numPart !== void 0) {
3882
3917
  index = Number.parseInt(numPart, 10);
@@ -3886,17 +3921,18 @@ function parseWithHeading(content, strict) {
3886
3921
  if (seenNumbers.has(index)) continue;
3887
3922
  if (text.length < 3) continue;
3888
3923
  seenNumbers.add(index);
3889
- steps.push({ index, text });
3924
+ steps.push({ index, text, auto: hasAuto });
3890
3925
  if (steps.length >= MAX_STEPS) break;
3891
3926
  }
3892
3927
  if (steps.length === 0) {
3893
- return { steps: [], texts: [], stripped: content };
3928
+ return { steps: [], texts: [], stripped: content, autoTexts: [] };
3894
3929
  }
3895
3930
  const texts = steps.map((s2) => s2.text);
3931
+ const autoTexts = steps.filter((s2) => s2.auto).map((s2) => s2.text);
3896
3932
  const blockStart = headingMatch.index;
3897
3933
  const blockEnd = headingEnd + findBlockEnd(afterHeading, steps.length);
3898
3934
  const stripped = (content.slice(0, blockStart) + content.slice(blockStart + blockEnd)).replace(/\n{3,}/g, "\n\n").trim();
3899
- return { steps, texts, stripped };
3935
+ return { steps, texts, stripped, autoTexts };
3900
3936
  }
3901
3937
  function buildPermissiveHeadingRe() {
3902
3938
  const variants = PERMISSIVE_HEADING_PATTERNS.map(({ re }) => `(?:${re.source})`).join("|");
@@ -3970,7 +4006,7 @@ var Entry = React5.memo(function Entry2({
3970
4006
  return /* @__PURE__ */ jsx(
3971
4007
  Box,
3972
4008
  {
3973
- marginX: MESSAGE_PANEL_MARGIN,
4009
+ marginX: 0,
3974
4010
  borderStyle: "single",
3975
4011
  borderTop: false,
3976
4012
  borderRight: false,
@@ -4001,7 +4037,7 @@ var Entry = React5.memo(function Entry2({
4001
4037
  Box,
4002
4038
  {
4003
4039
  flexDirection: "column",
4004
- marginX: MESSAGE_PANEL_MARGIN,
4040
+ marginX: 0,
4005
4041
  marginY: 1,
4006
4042
  borderStyle: "single",
4007
4043
  borderTop: false,
@@ -4012,7 +4048,15 @@ var Entry = React5.memo(function Entry2({
4012
4048
  paddingLeft: 1,
4013
4049
  children: [
4014
4050
  /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
4015
- /* @__PURE__ */ jsx(AssistantBody, { text: stripped, termWidth, contentWidth })
4051
+ /* @__PURE__ */ jsx(
4052
+ AssistantBody,
4053
+ {
4054
+ text: stripped,
4055
+ termWidth,
4056
+ contentWidth,
4057
+ panelBackground: ASSISTANT_BG
4058
+ }
4059
+ )
4016
4060
  ]
4017
4061
  }
4018
4062
  ),
@@ -4020,7 +4064,7 @@ var Entry = React5.memo(function Entry2({
4020
4064
  Box,
4021
4065
  {
4022
4066
  flexDirection: "column",
4023
- marginX: MESSAGE_PANEL_MARGIN,
4067
+ marginX: 0,
4024
4068
  marginY: 1,
4025
4069
  borderStyle: "single",
4026
4070
  borderTop: false,
@@ -4103,7 +4147,7 @@ var Entry = React5.memo(function Entry2({
4103
4147
  return /* @__PURE__ */ jsx(
4104
4148
  Box,
4105
4149
  {
4106
- marginX: MESSAGE_PANEL_MARGIN,
4150
+ marginX: 0,
4107
4151
  borderStyle: "single",
4108
4152
  borderTop: false,
4109
4153
  borderRight: false,
@@ -4117,7 +4161,7 @@ var Entry = React5.memo(function Entry2({
4117
4161
  return /* @__PURE__ */ jsx(
4118
4162
  Box,
4119
4163
  {
4120
- marginX: MESSAGE_PANEL_MARGIN,
4164
+ marginX: 0,
4121
4165
  borderStyle: "single",
4122
4166
  borderTop: false,
4123
4167
  borderRight: false,
@@ -4136,7 +4180,7 @@ var Entry = React5.memo(function Entry2({
4136
4180
  Box,
4137
4181
  {
4138
4182
  flexDirection: "column",
4139
- marginX: MESSAGE_PANEL_MARGIN,
4183
+ marginX: 0,
4140
4184
  marginY: 1,
4141
4185
  borderStyle: "single",
4142
4186
  borderTop: false,
@@ -8824,6 +8868,8 @@ function App({
8824
8868
  predictNext,
8825
8869
  onSuggestionsParsed,
8826
8870
  getSuggestions,
8871
+ getAutoSuggestions,
8872
+ autonomyNextPrompt,
8827
8873
  setSuggestions,
8828
8874
  switchAutonomy,
8829
8875
  effectiveMaxContext,
@@ -10051,9 +10097,16 @@ function App({
10051
10097
  return;
10052
10098
  }
10053
10099
  const delay = cfg?.delayMs ?? 45e3;
10054
- const top = suggestions[0];
10100
+ const isYolo = getYolo?.() ?? false;
10101
+ const autoSuggestions = isYolo ? getAutoSuggestions?.() ?? [] : [];
10102
+ const useAutoSuggestions = isYolo && autoSuggestions.length > 0;
10103
+ const top = useAutoSuggestions ? autoSuggestions[0] : suggestions[0];
10055
10104
  if (!top) return;
10056
- nextStepsAutoSubmitSuggestionRef.current = top;
10105
+ let promptToSubmit = top;
10106
+ if (useAutoSuggestions && autonomyNextPrompt) {
10107
+ promptToSubmit = autonomyNextPrompt.replace("{{suggestion}}", top);
10108
+ }
10109
+ nextStepsAutoSubmitSuggestionRef.current = promptToSubmit;
10057
10110
  const start = Date.now();
10058
10111
  setNextStepsAutoSubmitCountdown(Math.ceil(delay / 1e3));
10059
10112
  nextStepsAutoSubmitTimerRef.current = setInterval(() => {
@@ -12858,6 +12911,10 @@ async function runTui(opts) {
12858
12911
  saveSettings: opts.saveSettings,
12859
12912
  predictNext: opts.predictNext,
12860
12913
  onSuggestionsParsed: opts.onSuggestionsParsed,
12914
+ getSuggestions: opts.getSuggestions,
12915
+ getAutoSuggestions: opts.getAutoSuggestions,
12916
+ autonomyNextPrompt: opts.autonomyNextPrompt,
12917
+ setSuggestions: opts.setSuggestions,
12861
12918
  chime: opts.chime,
12862
12919
  confirmExit: opts.confirmExit,
12863
12920
  mouse: mouseEnabled,