@wrongstack/tui 0.73.1 → 0.82.6

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/README.md CHANGED
@@ -31,7 +31,6 @@ const exitCode = await runTui({
31
31
  family: 'anthropic',
32
32
  keyTail: '…ABC',
33
33
  effectiveMaxContext: 200_000,
34
- altScreen: true,
35
34
  });
36
35
 
37
36
  process.exit(exitCode);
@@ -76,24 +75,16 @@ process.exit(exitCode);
76
75
  | `Esc` | Close any picker / dialog / agents monitor |
77
76
  | `Ctrl+L` | Clear screen (TUI keeps state — equivalent to scrolling) |
78
77
 
79
- Keyboard shortcuts (always available in managed/alt-screen mode):
80
- - **PgUp/PgDn** — page scroll through chat history.
81
- - **Home/End** — jump to top/bottom of chat history (when input is empty); move cursor to start/end of line (when typing).
82
- - **Ctrl+Home/End** — jump to top/bottom of chat history (always, even when typing).
83
- - **↑/↓** — navigate input history when buffer is empty.
84
-
85
78
  ## Options worth knowing
86
79
 
87
- - **`altScreen: true`** (default) — render into the terminal's alternate screen buffer (vim/less/htop style). The TUI owns the whole viewport, native scrollback is untouched, and the live region cannot leak into terminal history. Raw mode plus alt-screen also means every keystroke — including Ctrl+S, Ctrl+Q, Ctrl+Z, Ctrl+\\ — reaches Ink instead of being consumed by the terminal driver (`runTui` additionally registers no-op handlers for `SIGTSTP`/`SIGQUIT`/`SIGTTIN`/`SIGTTOU` as belt-and-suspenders). Set `false` (or pass `--no-alt-screen`) to render into normal scrollback if you specifically want completed chat to survive after exit; the trade-off is the documented live-region leak on resize / overlay-close / picker-submit, and that some shortcuts may fall through to the terminal.
88
80
  - **`effectiveMaxContext`** — the context-bar denominator. Pass the model-specific value resolved via `ModelsRegistry`, not the family baseline; the 1M Opus variant has a much larger window than the 200k default.
89
81
  - **`queueStore`** — if set, queued input survives a crash. Without it, queued lines are in-memory only.
90
82
  - **`onClearHistory`** — invoked from the `/clear` slash command so the TUI can wipe its rendered history entries (keeping just the banner) while `Agent`/memory reset happens elsewhere.
91
- - **`onAfterExit`** — called once the alt-screen has been restored on clean shutdown. Use it to print "session saved" hints into the user's normal terminal (alt-screen exit erases the TUI view).
92
83
 
93
84
  ## Architecture
94
85
 
95
86
  ```
96
- runTui — entry; sets up bracketed paste, alt-screen, signal handlers
87
+ runTui — entry; sets up bracketed paste, signal handlers
97
88
 
98
89
  App (React component) — useReducer-driven state machine
99
90
  ↓ dispatches events to ↓
@@ -102,6 +93,11 @@ EventBus — agent.run() emits these, the TUI subscribes
102
93
 
103
94
  State is a single `useReducer` `State` shape with discriminated-union `Action`s. The reducer is exported (`reducer`) and unit-tested.
104
95
 
96
+ ## React Version
97
+
98
+ TUI remains on React 18 because ink v5 does not yet fully support React 19.
99
+ WebUI uses React 19. This is a known divergence tracked in this codebase.
100
+
105
101
  ## License
106
102
 
107
103
  MIT
package/dist/index.d.ts CHANGED
@@ -10,7 +10,29 @@ interface ProviderOption {
10
10
  /** Model ids the picker offers in step 2 for this provider. */
11
11
  models: string[];
12
12
  /** Optional dim hint shown next to the model list (e.g. "from saved config"). */
13
- modelsLabel?: string;
13
+ modelsLabel?: string | undefined;
14
+ }
15
+
16
+ interface Settings {
17
+ mode: 'off' | 'suggest' | 'auto';
18
+ delayMs: number;
19
+ titleAnimation: boolean;
20
+ yolo: boolean;
21
+ streamFleet: boolean;
22
+ chime: boolean;
23
+ confirmExit: boolean;
24
+ nextPrediction: boolean;
25
+ featureMcp: boolean;
26
+ featurePlugins: boolean;
27
+ featureMemory: boolean;
28
+ featureSkills: boolean;
29
+ featureModelsRegistry: boolean;
30
+ contextAutoCompact: boolean;
31
+ contextStrategy: 'hybrid' | 'intelligent' | 'selective';
32
+ logLevel: 'error' | 'warn' | 'info' | 'debug' | 'trace';
33
+ auditLevel: 'minimal' | 'standard' | 'full';
34
+ indexOnStart: boolean;
35
+ maxIterations: number;
14
36
  }
15
37
 
16
38
  interface RunTuiOptions {
@@ -18,57 +40,57 @@ interface RunTuiOptions {
18
40
  slashRegistry: SlashCommandRegistry;
19
41
  attachments: AttachmentStore;
20
42
  events: EventBus;
21
- tokenCounter?: TokenCounter;
22
- visionAdapters?: VisionAdapters;
43
+ tokenCounter?: TokenCounter | undefined;
44
+ visionAdapters?: VisionAdapters | undefined;
23
45
  /** Resolve current model vision support. Falls back to provider capability when omitted. */
24
- supportsVision?: () => boolean | Promise<boolean>;
46
+ supportsVision?: (() => boolean | Promise<boolean>) | undefined;
25
47
  model: string;
26
- banner?: boolean;
48
+ banner?: boolean | undefined;
27
49
  /** Persists the input queue across crashes; if omitted, the queue is in-memory only. */
28
- queueStore?: QueueStore;
50
+ queueStore?: QueueStore | undefined;
29
51
  /** Surfaces the "⚠ YOLO" chip in the status bar. */
30
- yolo?: boolean;
52
+ yolo?: boolean | undefined;
31
53
  /** Query live YOLO state from the permission policy. */
32
- getYolo?: () => boolean;
54
+ getYolo?: (() => boolean) | undefined;
33
55
  /** Query the live autonomy mode. */
34
- getAutonomy?: () => 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel';
56
+ getAutonomy?: (() => 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel') | undefined;
35
57
  /**
36
58
  * Access the eternal-autonomy engine. When autonomy mode flips to
37
59
  * 'eternal' the TUI drives `runOneIteration()` from the post-slash hook
38
60
  * so the engine and TUI never race for the shared Context.
39
61
  */
40
- getEternalEngine?: () => _wrongstack_core.EternalAutonomyEngine | null;
62
+ getEternalEngine?: (() => _wrongstack_core.EternalAutonomyEngine | null) | undefined;
41
63
  /**
42
64
  * Access the parallel-eternal engine. When autonomy mode flips to
43
65
  * 'eternal-parallel' the TUI drives `runOneIteration()` from the post-slash
44
66
  * hook so the engine and TUI never race for the shared Context.
45
67
  */
46
- getParallelEngine?: () => _wrongstack_core.ParallelEternalEngine | null;
68
+ getParallelEngine?: (() => _wrongstack_core.ParallelEternalEngine | null) | undefined;
47
69
  /**
48
70
  * Subscribe to live per-iteration events from the eternal engine.
49
71
  * Returns an unsubscribe function. TUI uses this to render each
50
72
  * iteration as a live timeline entry as it lands.
51
73
  */
52
- subscribeEternalIteration?: (fn: (entry: _wrongstack_core.JournalEntry) => void) => () => void;
74
+ subscribeEternalIteration?: ((fn: (entry: _wrongstack_core.JournalEntry) => void) => () => void) | undefined;
53
75
  /**
54
76
  * Subscribe to per-iteration stage transitions from the autonomy engines.
55
77
  * TUI uses this to render live status in the status bar.
56
78
  */
57
- subscribeEternalStage?: (fn: (stage: AutonomyStage) => void) => () => void;
79
+ subscribeEternalStage?: ((fn: (stage: AutonomyStage) => void) => () => void) | undefined;
58
80
  /** Renders in the startup banner. Read from the CLI's package.json. */
59
- appVersion?: string;
81
+ appVersion?: string | undefined;
60
82
  /** Provider id for the startup banner ("openai", "anthropic", ...). */
61
- provider?: string;
83
+ provider?: string | undefined;
62
84
  /** Wire family — shown beneath provider in the banner. */
63
- family?: string;
85
+ family?: string | undefined;
64
86
  /** Last 3 chars of the active API key — shown in the banner for visual key-pick verification. */
65
- keyTail?: string;
87
+ keyTail?: string | undefined;
66
88
  /** Snapshot of keyed providers + their model lists for the `/model` picker. Async — the catalog fetch may need to hit disk/network. */
67
- getPickableProviders?: () => Promise<ProviderOption[]>;
89
+ getPickableProviders?: (() => Promise<ProviderOption[]>) | undefined;
68
90
  /** Apply a (provider, model) pair after the picker confirms. Returns an error string on failure. */
69
- switchProviderAndModel?: (providerId: string, modelId: string) => string | null;
91
+ switchProviderAndModel?: ((providerId: string, modelId: string) => string | null) | undefined;
70
92
  /** Apply an autonomy mode after the picker confirms. Returns an error string on failure. */
71
- switchAutonomy?: (mode: 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel') => string | null;
93
+ switchAutonomy?: ((mode: 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel') => string | null) | undefined;
72
94
  /**
73
95
  * Model-specific maxContext (tokens), resolved by the CLI via the
74
96
  * ModelsRegistry. When omitted, the TUI falls back to the provider
@@ -76,46 +98,43 @@ interface RunTuiOptions {
76
98
  * for variants like the 1M-context Opus build. The status bar's
77
99
  * context chip uses this for its progress denominator.
78
100
  */
79
- effectiveMaxContext?: number;
101
+ effectiveMaxContext?: number | undefined;
80
102
  /** Absolute project root for goal.json loading. */
81
- projectRoot?: string;
82
- /** Render into the terminal's alternate screen buffer (like vim/less/htop).
83
- * Default: false native scrollback stays live so chat history is
84
- * scrollable (wheel / Shift+PgUp), which matches the user's
85
- * "this is a chat app, let me scroll the chat" intuition. Pass true
86
- * (or run with `--alt-screen`) for the full-screen mode that owns the
87
- * terminal and prevents resize/overlay leaks of the live region —
88
- * trade-off is that the terminal's native scrollback is suspended
89
- * while the TUI is up and only what's currently on screen is visible.
90
- */
91
- altScreen?: boolean;
92
- /**
93
- * Called right after we exit the alt-screen on a clean shutdown. The
94
- * CLI uses this to print a one-line "session saved to …" hint into
95
- * the user's normal terminal, since alt-screen exit erases the whole
96
- * TUI view.
97
- */
98
- onAfterExit?: () => void;
103
+ projectRoot?: string | undefined;
104
+ /**
105
+ * Terminal title animation on/off. Defaults to true. When false, the
106
+ * OSC-0 window/tab title stays static (the app name only, no spinner).
107
+ * Controlled via /settings Terminal title animation.
108
+ */
109
+ titleAnimation?: boolean | undefined;
110
+ /** Play terminal bell (\\x07) when agent run completes. */
111
+ chime?: boolean | undefined;
112
+ /** Show "confirm exit" message on first Ctrl+C instead of "exit". */
113
+ confirmExit?: boolean | undefined;
114
+ /** Active agent mode label shown in the status bar (e.g. "teach", "brief"). */
115
+ modeLabel?: string | undefined;
116
+ /** Live getter for the agent mode label so the status bar updates after /mode. */
117
+ getModeLabel?: (() => string) | undefined;
99
118
  /** Called from /clear so the TUI can wipe its history entries while agent.ctx + memory are cleared separately. */
100
- onClearHistory?: (dispatch: React.Dispatch<{
119
+ onClearHistory?: ((dispatch: React.Dispatch<{
101
120
  type: 'clearHistory';
102
121
  } | {
103
122
  type: 'resetContextChip';
104
- }>) => void;
123
+ }>) => void) | undefined;
105
124
  /**
106
125
  * Live director instance. When set, the TUI renders a fleet panel
107
126
  * showing every spawned subagent, its current task, streaming output,
108
127
  * and runtime cost — updated live from the FleetBus. Pass null or omit
109
128
  * when multi-agent / director mode is disabled.
110
129
  */
111
- director?: Director | null;
130
+ director?: Director | null | undefined;
112
131
  /**
113
132
  * Optional roster reference for resolving subagent role ids to
114
133
  * human-readable names. Same value passed to director.tools().
115
134
  */
116
135
  fleetRoster?: Record<string, {
117
136
  name: string;
118
- }>;
137
+ }> | undefined;
119
138
  /**
120
139
  * Shared controller for the `/fleet stream on|off` toggle. The slash
121
140
  * command runs in the CLI process and needs to flip TUI reducer state;
@@ -131,7 +150,17 @@ interface RunTuiOptions {
131
150
  fleetStreamController?: {
132
151
  enabled: boolean;
133
152
  setEnabled: (enabled: boolean) => void;
134
- };
153
+ } | undefined;
154
+ /**
155
+ * Controller for the `/enhance on|off` prompt-refinement toggle. The App
156
+ * installs a dispatch-backed `setEnabled` here on mount so the slash command
157
+ * (run in the CLI process) flips the TUI's reducer flag. Mirrors
158
+ * `fleetStreamController`.
159
+ */
160
+ enhanceController?: {
161
+ enabled: boolean;
162
+ setEnabled: (enabled: boolean) => void;
163
+ } | undefined;
135
164
  /**
136
165
  * Controller for status bar hidden items. App installs a dispatch-backed
137
166
  * setter on mount so the /statusline slash command can update the TUI's
@@ -148,7 +177,7 @@ interface RunTuiOptions {
148
177
  agentsMonitorController?: {
149
178
  visible: boolean;
150
179
  setVisible: (visible: boolean) => void;
151
- };
180
+ } | undefined;
152
181
  /**
153
182
  * If set, the App boots straight into goal mode — the text is wrapped
154
183
  * in the GOAL preamble and submitted as the first turn. Lets users
@@ -157,62 +186,56 @@ interface RunTuiOptions {
157
186
  * The chat shows a one-line "🎯 Goal locked: …" hint; the actual
158
187
  * preamble is hidden from the visible history (same as `/goal`).
159
188
  */
160
- initialGoal?: string;
189
+ initialGoal?: string | undefined;
161
190
  /**
162
191
  * If set, submitted as the first turn verbatim (no preamble). Mainly
163
192
  * for scripted shell aliases — `wstack --tui --ask "summarize foo.md"`
164
193
  * — that want one turn pre-populated without the goal-mode framing.
165
194
  * Ignored when `initialGoal` is also set.
166
195
  */
167
- initialAsk?: string;
196
+ initialAsk?: string | undefined;
168
197
  /**
169
198
  * Directory containing session JSONL files. Required for rewind
170
199
  * functionality. When provided the TUI can list checkpoints and
171
200
  * trigger a rewind via `/rewind` or Ctrl+R.
172
201
  */
173
- sessionsDir?: string;
202
+ sessionsDir?: string | undefined;
174
203
  /**
175
204
  * SDD session context getter. When an SDD session is active, returns
176
205
  * the AI prompt context to inject into user messages.
177
206
  */
178
- getSDDContext?: () => string | null;
207
+ getSDDContext?: (() => string | null) | undefined;
179
208
  /**
180
209
  * Process AI output for SDD auto-detection (spec, tasks, plan).
181
210
  * Returns displayable status messages.
182
211
  */
183
- onSDDOutput?: (output: string) => Promise<string[]>;
212
+ onSDDOutput?: ((output: string) => Promise<string[]>) | undefined;
184
213
  /**
185
214
  * Subscribe to AutoPhase phase/graph events from the PhaseOrchestrator.
186
215
  * Returns an unsubscribe function. The TUI uses this to drive the
187
216
  * PhaseMonitor and PhasePanel live views via dispatch actions.
188
217
  */
189
- subscribeAutoPhase?: (handler: (event: string, payload: unknown) => void) => () => void;
218
+ subscribeAutoPhase?: ((handler: (event: string, payload: unknown) => void) => () => void) | undefined;
190
219
  /**
191
220
  * Read the persisted autonomy settings (defaultMode, autoProceedDelayMs).
192
221
  * Used by the SettingsPicker in the TUI on mount and after Ctrl+S toggle.
193
222
  */
194
- getSettings?: () => {
195
- mode: 'off' | 'suggest' | 'auto';
196
- delayMs: number;
197
- };
223
+ getSettings?: (() => Settings) | undefined;
198
224
  /**
199
- * Persist autonomy settings changes. Returns null on success, or an
225
+ * Persist settings changes. Returns null on success, or an
200
226
  * error string on failure (so the TUI can display it as a hint).
201
227
  */
202
- saveSettings?: (s: {
203
- mode: 'off' | 'suggest' | 'auto';
204
- delayMs: number;
205
- }) => string | null | Promise<string | null>;
228
+ saveSettings?: ((s: Settings) => string | null | Promise<string | null>) | undefined;
206
229
  /**
207
230
  * Predict likely next steps after a completed turn. The CLI wires this from
208
231
  * the session provider and the `/next` toggle; it returns [] when prediction
209
232
  * is disabled or autonomy isn't 'off'. Display-only — never executed.
210
233
  */
211
- predictNext?: (input: {
234
+ predictNext?: ((input: {
212
235
  userRequest: string;
213
236
  assistantSummary: string;
214
- }) => Promise<string[]>;
237
+ }) => Promise<string[]>) | undefined;
215
238
  }
216
239
  declare function runTui(opts: RunTuiOptions): Promise<number>;
217
240
 
218
- export { type RunTuiOptions, runTui };
241
+ export { type RunTuiOptions, type Settings, runTui };