@wrongstack/tui 0.6.5 → 0.6.7

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
@@ -50,6 +50,34 @@ interface RunTuiOptions {
50
50
  * iteration as a live timeline entry as it lands.
51
51
  */
52
52
  subscribeEternalIteration?: (fn: (entry: _wrongstack_core.JournalEntry) => void) => () => void;
53
+ /**
54
+ * Subscribe to per-iteration stage transitions from the eternal engine.
55
+ * TUI uses this to render live status (decide → execute → reflect →
56
+ * sleep/paused/stopped) in the status bar.
57
+ */
58
+ subscribeEternalStage?: (fn: (stage: {
59
+ phase: 'idle';
60
+ } | {
61
+ phase: 'decide';
62
+ reason: string;
63
+ } | {
64
+ phase: 'execute';
65
+ task: string;
66
+ } | {
67
+ phase: 'reflect';
68
+ status: 'success' | 'failure' | 'aborted' | 'skipped';
69
+ note?: string;
70
+ } | {
71
+ phase: 'sleep';
72
+ ms: number;
73
+ } | {
74
+ phase: 'paused';
75
+ } | {
76
+ phase: 'stopped';
77
+ } | {
78
+ phase: 'error';
79
+ message: string;
80
+ }) => void) => () => void;
53
81
  /** Renders in the startup banner. Read from the CLI's package.json. */
54
82
  appVersion?: string;
55
83
  /** Provider id for the startup banner ("openai", "anthropic", ...). */
@@ -62,6 +90,8 @@ interface RunTuiOptions {
62
90
  getPickableProviders?: () => Promise<ProviderOption[]>;
63
91
  /** Apply a (provider, model) pair after the picker confirms. Returns an error string on failure. */
64
92
  switchProviderAndModel?: (providerId: string, modelId: string) => string | null;
93
+ /** Apply an autonomy mode after the picker confirms. Returns an error string on failure. */
94
+ switchAutonomy?: (mode: 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel') => string | null;
65
95
  /**
66
96
  * Model-specific maxContext (tokens), resolved by the CLI via the
67
97
  * ModelsRegistry. When omitted, the TUI falls back to the provider
package/dist/index.js CHANGED
@@ -1550,6 +1550,25 @@ function LiveActivityStrip({
1550
1550
  ] }) }) : null
1551
1551
  ] });
1552
1552
  }
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
+ ] });
1571
+ }
1553
1572
  function ModelPicker({
1554
1573
  step,
1555
1574
  providerOptions,
@@ -1634,7 +1653,8 @@ function StatusBar({
1634
1653
  context,
1635
1654
  projectName,
1636
1655
  processCount,
1637
- hiddenItems
1656
+ hiddenItems,
1657
+ eternalStage
1638
1658
  }) {
1639
1659
  const hiddenSet = new Set(hiddenItems);
1640
1660
  const usage = tokenCounter?.total();
@@ -1730,8 +1750,12 @@ function StatusBar({
1730
1750
  }
1731
1751
  )
1732
1752
  ] }) : null,
1753
+ eternalStage ? /* @__PURE__ */ jsxs(Fragment, { children: [
1754
+ yolo || autonomy && autonomy !== "off" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1755
+ /* @__PURE__ */ jsx(EternalStageChip, { stage: eternalStage })
1756
+ ] }) : null,
1733
1757
  elapsedMs !== void 0 && !hiddenSet.has("elapsed") ? /* @__PURE__ */ jsxs(Fragment, { children: [
1734
- yolo ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1758
+ yolo || autonomy && autonomy !== "off" || eternalStage ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
1735
1759
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1736
1760
  "\u23F1 ",
1737
1761
  fmtElapsed2(elapsedMs)
@@ -1855,6 +1879,45 @@ function StatusBar({
1855
1879
  }
1856
1880
  );
1857
1881
  }
1882
+ function EternalStageChip({
1883
+ stage
1884
+ }) {
1885
+ switch (stage.phase) {
1886
+ case "idle":
1887
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2B1C idle" });
1888
+ case "decide":
1889
+ return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
1890
+ "\u2B07 decide: ",
1891
+ stage.reason
1892
+ ] });
1893
+ case "execute":
1894
+ return /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1895
+ "\u25B6 ",
1896
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "execute" }),
1897
+ stage.task ? `(${stage.task})` : ""
1898
+ ] });
1899
+ case "reflect":
1900
+ return /* @__PURE__ */ jsxs(Text, { color: stage.status === "success" ? "green" : stage.status === "failure" ? "red" : "yellow", children: [
1901
+ "\u21A9 reflect: ",
1902
+ stage.status
1903
+ ] });
1904
+ case "sleep":
1905
+ return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1906
+ "\u{1F4A4} sleep ",
1907
+ Math.round(stage.ms / 1e3),
1908
+ "s"
1909
+ ] });
1910
+ case "paused":
1911
+ return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u23F8 paused" });
1912
+ case "stopped":
1913
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25A0 stopped" });
1914
+ case "error":
1915
+ return /* @__PURE__ */ jsxs(Text, { color: "red", children: [
1916
+ "\u26A0 error: ",
1917
+ stage.message
1918
+ ] });
1919
+ }
1920
+ }
1858
1921
  function ContextChip({ ctx }) {
1859
1922
  const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
1860
1923
  const pct = Math.round(ratio * 100);
@@ -2451,6 +2514,30 @@ function reducer(state, action) {
2451
2514
  ...state,
2452
2515
  modelPicker: { ...state.modelPicker, hint: action.text }
2453
2516
  };
2517
+ case "autonomyPickerOpen":
2518
+ return {
2519
+ ...state,
2520
+ autonomyPicker: { open: true, options: action.options, selected: 0, hint: void 0 }
2521
+ };
2522
+ case "autonomyPickerClose":
2523
+ return {
2524
+ ...state,
2525
+ autonomyPicker: { open: false, options: [], selected: 0 }
2526
+ };
2527
+ case "autonomyPickerMove": {
2528
+ const n = state.autonomyPicker.options.length;
2529
+ if (n === 0) return state;
2530
+ const next = (state.autonomyPicker.selected + action.delta + n) % n;
2531
+ return {
2532
+ ...state,
2533
+ autonomyPicker: { ...state.autonomyPicker, selected: next }
2534
+ };
2535
+ }
2536
+ case "autonomyPickerHint":
2537
+ return {
2538
+ ...state,
2539
+ autonomyPicker: { ...state.autonomyPicker, hint: action.text }
2540
+ };
2454
2541
  case "confirmOpen":
2455
2542
  return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
2456
2543
  case "confirmClose":
@@ -2666,6 +2753,9 @@ function reducer(state, action) {
2666
2753
  rewindOverlay: null
2667
2754
  };
2668
2755
  }
2756
+ case "eternalStage": {
2757
+ return { ...state, eternalStage: action.stage };
2758
+ }
2669
2759
  }
2670
2760
  }
2671
2761
  var PASTE_THRESHOLD_CHARS = 200;
@@ -2720,6 +2810,7 @@ function App({
2720
2810
  getEternalEngine,
2721
2811
  getParallelEngine,
2722
2812
  subscribeEternalIteration,
2813
+ subscribeEternalStage,
2723
2814
  getSDDContext,
2724
2815
  onSDDOutput,
2725
2816
  appVersion,
@@ -2728,6 +2819,7 @@ function App({
2728
2819
  keyTail,
2729
2820
  getPickableProviders,
2730
2821
  switchProviderAndModel,
2822
+ switchAutonomy,
2731
2823
  effectiveMaxContext,
2732
2824
  onExit,
2733
2825
  director,
@@ -2790,13 +2882,15 @@ function App({
2790
2882
  modelOptions: [],
2791
2883
  selected: 0
2792
2884
  },
2885
+ autonomyPicker: { open: false, options: [], selected: 0 },
2793
2886
  confirmQueue: [],
2794
2887
  contextChipVersion: 0,
2795
2888
  fleet: {},
2796
2889
  fleetCost: 0,
2797
2890
  streamFleet: true,
2798
2891
  checkpoints: [],
2799
- rewindOverlay: null
2892
+ rewindOverlay: null,
2893
+ eternalStage: null
2800
2894
  });
2801
2895
  const builderRef = useRef(null);
2802
2896
  if (builderRef.current === null) {
@@ -3283,6 +3377,22 @@ function App({
3283
3377
  slashRegistry.unregister("model");
3284
3378
  };
3285
3379
  }, [slashRegistry, getPickableProviders, switchProviderAndModel]);
3380
+ useEffect(() => {
3381
+ if (!switchAutonomy) return;
3382
+ const cmd = {
3383
+ name: "autonomy",
3384
+ aliases: ["auto"],
3385
+ description: "Pick an autonomy mode interactively (picker).",
3386
+ async run() {
3387
+ dispatch({ type: "autonomyPickerOpen", options: AUTONOMY_OPTIONS });
3388
+ return { message: void 0 };
3389
+ }
3390
+ };
3391
+ slashRegistry.register(cmd);
3392
+ return () => {
3393
+ slashRegistry.unregister("autonomy");
3394
+ };
3395
+ }, [slashRegistry, switchAutonomy]);
3286
3396
  useEffect(() => {
3287
3397
  const FLUSH_MS = 100;
3288
3398
  const flush = () => {
@@ -3930,6 +4040,32 @@ function App({
3930
4040
  }
3931
4041
  return;
3932
4042
  }
4043
+ if (state.autonomyPicker.open) {
4044
+ if (key.escape) {
4045
+ dispatch({ type: "autonomyPickerClose" });
4046
+ return;
4047
+ }
4048
+ if (key.upArrow) {
4049
+ dispatch({ type: "autonomyPickerMove", delta: -1 });
4050
+ return;
4051
+ }
4052
+ if (key.downArrow) {
4053
+ dispatch({ type: "autonomyPickerMove", delta: 1 });
4054
+ return;
4055
+ }
4056
+ if (isEnter) {
4057
+ const opt = state.autonomyPicker.options[state.autonomyPicker.selected];
4058
+ if (!opt) return;
4059
+ const err = switchAutonomy?.(opt.mode);
4060
+ if (err) {
4061
+ dispatch({ type: "autonomyPickerHint", text: err });
4062
+ return;
4063
+ }
4064
+ dispatch({ type: "autonomyPickerClose" });
4065
+ return;
4066
+ }
4067
+ return;
4068
+ }
3933
4069
  if (state.slashPicker.open) {
3934
4070
  if (key.escape) {
3935
4071
  dispatch({ type: "slashPickerClose" });
@@ -4343,6 +4479,13 @@ function App({
4343
4479
  });
4344
4480
  return unsub;
4345
4481
  }, [subscribeEternalIteration]);
4482
+ useEffect(() => {
4483
+ if (!subscribeEternalStage) return;
4484
+ const unsub = subscribeEternalStage((stage) => {
4485
+ dispatch({ type: "eternalStage", stage });
4486
+ });
4487
+ return unsub;
4488
+ }, [subscribeEternalStage]);
4346
4489
  const submit = async (overrideRaw) => {
4347
4490
  const raw = overrideRaw ?? draftRef.current.buffer;
4348
4491
  const trimmed = raw.trim();
@@ -4528,6 +4671,14 @@ User message:
4528
4671
  hint: state.modelPicker.hint
4529
4672
  }
4530
4673
  ) : null,
4674
+ state.autonomyPicker.open ? /* @__PURE__ */ jsx(
4675
+ AutonomyPicker,
4676
+ {
4677
+ options: state.autonomyPicker.options,
4678
+ selected: state.autonomyPicker.selected,
4679
+ hint: state.autonomyPicker.hint
4680
+ }
4681
+ ) : null,
4531
4682
  state.rewindOverlay ? /* @__PURE__ */ jsx(
4532
4683
  CheckpointTimeline,
4533
4684
  {
@@ -4576,7 +4727,8 @@ User message:
4576
4727
  projectName,
4577
4728
  subagentCount: Object.keys(state.fleet).length,
4578
4729
  processCount: getProcessRegistry().activeCount,
4579
- hiddenItems
4730
+ hiddenItems,
4731
+ eternalStage: state.eternalStage
4580
4732
  }
4581
4733
  ),
4582
4734
  director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null
@@ -4707,12 +4859,14 @@ async function runTui(opts) {
4707
4859
  getEternalEngine: opts.getEternalEngine,
4708
4860
  getParallelEngine: opts.getParallelEngine,
4709
4861
  subscribeEternalIteration: opts.subscribeEternalIteration,
4862
+ subscribeEternalStage: opts.subscribeEternalStage,
4710
4863
  appVersion: opts.appVersion,
4711
4864
  provider: opts.provider,
4712
4865
  family: opts.family,
4713
4866
  keyTail: opts.keyTail,
4714
4867
  getPickableProviders: opts.getPickableProviders,
4715
4868
  switchProviderAndModel: opts.switchProviderAndModel,
4869
+ switchAutonomy: opts.switchAutonomy,
4716
4870
  effectiveMaxContext: opts.effectiveMaxContext,
4717
4871
  onExit,
4718
4872
  director: opts.director ?? null,