@wrongstack/tui 1.0.1 → 1.0.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.
@@ -27,6 +27,17 @@ export type Action = {
27
27
  cursor: number;
28
28
  } | {
29
29
  type: 'clearInput';
30
+ }
31
+ /**
32
+ * Flip the composer into bash mode (`!` pressed on an empty draft): the
33
+ * input becomes a shell-command line and Enter runs it via the `!` path.
34
+ */
35
+ | {
36
+ type: 'bashModeEnter';
37
+ }
38
+ /** Leave bash mode and restore the normal chat composer. */
39
+ | {
40
+ type: 'bashModeExit';
30
41
  } | {
31
42
  type: 'clearHistory';
32
43
  model?: string | undefined;
@@ -659,6 +670,7 @@ export type Action = {
659
670
  view?: Extract<AuthPanelView, 'list' | 'oauth'> | undefined;
660
671
  providers?: AuthProviderRow[] | undefined;
661
672
  presets?: AuthLocalPresetRow[] | undefined;
673
+ oauthStrategies?: import('./auth-panel-model.js').AuthOAuthStrategyRow[] | undefined;
662
674
  } | {
663
675
  type: 'authClose';
664
676
  } | {
@@ -44,7 +44,9 @@ interface AppKeyHandlerOptions {
44
44
  cursor: number;
45
45
  }>;
46
46
  setDraft: (buffer: string, cursor: number) => void;
47
- submit: () => void;
47
+ /** Submits the composer. `overrideRaw` bypasses the buffer (bash mode
48
+ * forwards its draft through the `!` shell path this way). */
49
+ submit: (overrideRaw?: string) => void;
48
50
  mouseMode: boolean;
49
51
  termRows: number;
50
52
  terminalColumns: number;
@@ -62,6 +62,14 @@ export type State = {
62
62
  resumeLoad: ResumeLoadState | null;
63
63
  buffer: string;
64
64
  cursor: number;
65
+ /**
66
+ * Bash mode: the composer is dedicated to shell commands. Entered by
67
+ * pressing `!` on an empty draft, exited by Esc / Backspace-on-empty (or a
68
+ * successful run). While on, Enter submits the draft through the `!` shell
69
+ * path (`/dev`) instead of sending it to the model, and the composer rail
70
+ * relabels itself so the mode is unmistakable.
71
+ */
72
+ bashMode: boolean;
65
73
  streamingText: string;
66
74
  /**
67
75
  * Live tail of the currently streaming tool's stdout/progress text. Mirrors
@@ -36,7 +36,15 @@ export interface AuthLocalPresetRow {
36
36
  noAuth: boolean;
37
37
  hint: string;
38
38
  }
39
- export type AuthOAuthKind = 'chatgpt' | 'claude' | 'copilot';
39
+ /** UI-safe interactive-login descriptor supplied by the CLI host. */
40
+ export interface AuthOAuthStrategyRow {
41
+ id: string;
42
+ providerId: string;
43
+ label: string;
44
+ description?: string | undefined;
45
+ }
46
+ /** Strategy ids are runtime-extensible. */
47
+ export type AuthOAuthKind = string;
40
48
  /**
41
49
  * Bridge the CLI flows use to talk to the panel while a flow runs.
42
50
  * `prompt` REJECTS when the user cancels (Esc) — flows treat a thrown
@@ -120,6 +128,7 @@ export interface AuthPanelHost {
120
128
  listProviders(): Promise<AuthProviderRow[]>;
121
129
  listCatalog(): Promise<AuthCatalogRow[]>;
122
130
  localPresets(): AuthLocalPresetRow[];
131
+ oauthStrategies?: (() => AuthOAuthStrategyRow[]) | undefined;
123
132
  setActiveKey(providerId: string, label: string): Promise<string | null>;
124
133
  deleteKey(providerId: string, label: string): Promise<string | null>;
125
134
  removeProvider(providerId: string): Promise<string | null>;
@@ -198,6 +207,7 @@ export interface AuthPanelState {
198
207
  hint?: string | undefined;
199
208
  providers: AuthProviderRow[];
200
209
  presets: AuthLocalPresetRow[];
210
+ oauthStrategies?: AuthOAuthStrategyRow[] | undefined;
201
211
  catalog: AuthCatalogRow[];
202
212
  /** Cursor index into `authPanelRows(state)` for the current view. */
203
213
  selected: number;
@@ -295,7 +305,7 @@ export type AuthPanelRow = {
295
305
  preset: AuthLocalPresetRow;
296
306
  } | {
297
307
  kind: 'oauth-option';
298
- oauth: AuthOAuthKind;
308
+ oauth: AuthOAuthStrategyRow;
299
309
  } | {
300
310
  kind: 'form-field';
301
311
  field: AuthFormFieldId;
@@ -13,6 +13,14 @@ export interface InputProps {
13
13
  hint?: string | undefined;
14
14
  /** Label embedded in the composer's top rail. */
15
15
  title?: string | undefined;
16
+ /** Glyph shown before the title in the top rail (defaults to the brand glyph). */
17
+ railIcon?: string | undefined;
18
+ /**
19
+ * Frame/prompt color override for a special composer mode (e.g. the warn
20
+ * color while bash mode is active). Defaults to the theme brand colors;
21
+ * `disabled` still wins with the error color.
22
+ */
23
+ accent?: string | undefined;
16
24
  /**
17
25
  * Right-aligned live status descriptor for the composer's top rail. Renders
18
26
  * as an animated {@link ComposerStatusChip} (the thinking word while working,
@@ -83,5 +91,5 @@ export interface KeyEvent {
83
91
  fn?: number | undefined;
84
92
  }
85
93
  export declare const EMPTY_KEY: KeyEvent;
86
- export declare const Input: React.MemoExoticComponent<({ prompt, value, cursor, disabled, hint, title, status, animationStyle, workingTime, footerHint, hidden, placeholderHeight, onKey, maxWidth, }: InputProps) => React.ReactElement>;
94
+ export declare const Input: React.MemoExoticComponent<({ prompt, value, cursor, disabled, hint, title, railIcon, accent, status, animationStyle, workingTime, footerHint, hidden, placeholderHeight, onKey, maxWidth, }: InputProps) => React.ReactElement>;
87
95
  //# sourceMappingURL=input.d.ts.map
@@ -15,7 +15,7 @@ export declare function badgeForKind(kind: 'oauth' | 'api_key' | 'session_token'
15
15
  label: string;
16
16
  color: string;
17
17
  } | undefined;
18
- /** Colors for the three OAuth kinds shown in the auth panel. */
18
+ /** Brand colors for known OAuth strategies; unknown plugin strategies use the fallback. */
19
19
  export declare const OAUTH_KIND_COLORS: Record<string, string>;
20
20
  /** Semantic UI colors used across auth / model panels. */
21
21
  export declare const UI_COLORS: {
@@ -26,6 +26,7 @@ export declare const STATUSLINE_ICONS: {
26
26
  readonly processes: string;
27
27
  readonly project: string;
28
28
  readonly prompt_variant: string;
29
+ readonly quota: string;
29
30
  readonly queue: string;
30
31
  readonly sessions: string;
31
32
  readonly side_effects: string;
@@ -1,9 +1,10 @@
1
- import type { StatuslineDensity } from "@wrongstack/core/statusline";
2
- import type React from "react";
3
- import type { AnimationStyle } from "./animation-style.js";
4
- import type { RailSpanEntry } from "./powerline-rail.js";
5
- import type { FleetAgentDetail, MailboxStatus, StatusBarProps } from "./status-bar-types.js";
6
- import type { StatuslineItem } from "./statusline-picker.js";
1
+ import type { StatuslineDensity } from '@wrongstack/core/statusline';
2
+ import type React from 'react';
3
+ import type { ProviderQuotaChip } from '../hooks/use-provider-quota.js';
4
+ import type { AnimationStyle } from './animation-style.js';
5
+ import type { RailSpanEntry } from './powerline-rail.js';
6
+ import type { FleetAgentDetail, MailboxStatus, StatusBarProps } from './status-bar-types.js';
7
+ import type { StatuslineItem } from './statusline-picker.js';
7
8
  export interface StatusBarRailBuildParams {
8
9
  showChip: (item: StatuslineItem) => boolean;
9
10
  /** Resolved density for a chip ('auto' unless the user pinned one). */
@@ -38,6 +39,13 @@ export interface StatusBarRailBuildParams {
38
39
  queueCount?: number | undefined;
39
40
  hint?: string | undefined;
40
41
  breakerCountdown?: StatusBarProps['breakerCountdown'];
42
+ /**
43
+ * Most-consumed subscription window across every metered provider, or
44
+ * undefined until one has reported. Resolved inside `<StatusBar />` from the
45
+ * provider-neutral quota store, not threaded from app state: the value is
46
+ * push-driven and belongs to no single session.
47
+ */
48
+ quota?: ProviderQuotaChip | undefined;
41
49
  projectName?: string | undefined;
42
50
  workingDir?: string | undefined;
43
51
  git?: StatusBarProps['git'];
@@ -1,5 +1,5 @@
1
- import type { RailSpanEntry } from "./powerline-rail.js";
2
- import { type StatusBarRailBuildParams } from "./status-bar-rails-common.js";
1
+ import type { RailSpanEntry } from './powerline-rail.js';
2
+ import { type StatusBarRailBuildParams } from './status-bar-rails-common.js';
3
3
  /**
4
4
  * Standing posture (is this session dangerous? is it throttled?) followed by
5
5
  * the work in flight. A reader scans this rail left-to-right to answer
@@ -117,6 +117,13 @@ export type HistoryEntry = {
117
117
  ok: boolean;
118
118
  input?: unknown | undefined;
119
119
  output?: string | undefined;
120
+ /**
121
+ * Canonical result text used only for clipboard operations. `output`
122
+ * belongs to the bounded display cache and may be shortened by history
123
+ * retention or by the visual renderer; this field must keep the exact
124
+ * tool_result content that was sent back to the model.
125
+ */
126
+ copyOutput?: string | undefined;
120
127
  /**
121
128
  * SAGE Memory Injector block for this call — `--- SAGE: … ---` header
122
129
  * plus one line per injected memory — carried beside `output` because
@@ -136,8 +143,9 @@ export type HistoryEntry = {
136
143
  */
137
144
  sageStats?: string | undefined;
138
145
  /** Full byte length of the result body the model actually received
139
- * (post-cap, post-scrub). Carried separately because `output` is a
140
- * ~400-char preview — `outputBytes` is what the model paid for. */
146
+ * (post-cap, post-scrub). Carried separately because rendering and
147
+ * display retention may shorten `output`; this is what the model paid
148
+ * for. */
141
149
  outputBytes?: number | undefined;
142
150
  /** ~3.5 chars/token estimate over `outputBytes`. Cheap to render in
143
151
  * the chip; the authoritative count lives in provider.response.usage. */
@@ -1,5 +1,5 @@
1
1
  import type { Action } from '../app-reducer.js';
2
- /** Coordinates bounded or user-stopped `/bughunt` rounds in the TUI. */
2
+ /** Coordinates single-round or explicitly bounded `/bughunt` runs in the TUI. */
3
3
  export declare function useBugHuntLoop(dispatch: (action: Action) => void, submit: (command: string) => void, historyGen?: number): {
4
4
  onBugHuntStarted: (command: string, totalRounds?: number) => void;
5
5
  onRunFinished: (status: 'done' | 'aborted' | 'failed' | 'max_iterations') => void;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * useProviderQuota — the one quota number a status bar has room for.
3
+ *
4
+ * Subscription-metered providers report their remaining plan budget into the
5
+ * provider-neutral store in `@wrongstack/core/quota`. A statusline chip cannot
6
+ * show every window of every provider, so this hook reduces the store to the
7
+ * single reading that would change what the user does next: the most-consumed
8
+ * window anywhere, with its countdown.
9
+ *
10
+ * It subscribes rather than polling. Quota changes only when a request
11
+ * completes, so a timer would either lag the reading or repaint a quiet
12
+ * terminal for nothing — and this terminal stays quiet by directive.
13
+ *
14
+ * The countdown is deliberately NOT re-rendered every second. A reset is hours
15
+ * away; ticking it once a second would repaint the whole status bar 3,600 times
16
+ * to move one digit. The value is recomputed whenever a new reading lands,
17
+ * which is exactly when it can have meaningfully changed.
18
+ */
19
+ /** What the chip renders. Absent until some provider has reported. */
20
+ export interface ProviderQuotaChip {
21
+ /** Provider that reported this window, e.g. `openai-codex`. */
22
+ providerId: string;
23
+ /** Window name: `5h`, `7d`, or the provider's own label. */
24
+ windowLabel: string;
25
+ usedPercent: number;
26
+ /** `4h 12m`, when the provider published a reset time. */
27
+ resetIn?: string | undefined;
28
+ /** True when this window is the one currently cutting the account off. */
29
+ reached: boolean;
30
+ }
31
+ export declare function useProviderQuota(): ProviderQuotaChip | undefined;
32
+ //# sourceMappingURL=use-provider-quota.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export type { Settings } from './app.js';
2
2
  export { buildGoalPreamble } from './app.js';
3
- export type { AuthCatalogRow, AuthFlowIo, AuthFlowResult, AuthKeyEdit, AuthKeyRow, AuthLocalPresetRow, AuthModelEdit, AuthOAuthKind, AuthPanelHost, AuthProviderEdit, AuthProviderRow, AuthProviderSetup, } from './auth-panel-model.js';
3
+ export type { AuthCatalogRow, AuthFlowIo, AuthFlowResult, AuthKeyEdit, AuthKeyRow, AuthLocalPresetRow, AuthModelEdit, AuthOAuthKind, AuthOAuthStrategyRow, AuthPanelHost, AuthProviderEdit, AuthProviderRow, AuthProviderSetup, } from './auth-panel-model.js';
4
4
  export type { BrainDenyIsTerminal, BrainHeuristicKey, BrainPanelHeuristics, BrainPanelHost, BrainPanelPersona, BrainPanelSettings, BrainPanelVoter, BrainTerminalPolicyValue, BrainTraceContent, } from './brain-panel-model.js';
5
5
  export { replaySessionMessages } from './components/history/replay.js';
6
6
  export type { ProviderOption } from './components/model-picker.js';