@wrongstack/tui 0.310.0 → 0.313.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.
@@ -300,7 +300,7 @@ export type Action = {
300
300
  * One of the renderable styles plus the meta-mode `'cycle'`. Persisted
301
301
  * to disk on every ←/→ change in `/settings`.
302
302
  */
303
- animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'cycle';
303
+ animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'static' | 'cycle';
304
304
  /**
305
305
  * Persisted row index for where to land when the picker reopens.
306
306
  * See `Settings.lastSettingsField`.
@@ -328,6 +328,16 @@ export type Action = {
328
328
  showSageMemoryInject: boolean;
329
329
  sageMemoryInjectThreshold: number;
330
330
  nextStepsTool: boolean;
331
+ /**
332
+ * WrongProxy / WrongTrace: master switch + configurable URL
333
+ * (default http://localhost:3444). Mirrors `Settings.wrongProxy*`
334
+ * and `SettingsPickerPatch.wrongProxy*`. Both fields land in
335
+ * the Integrations section of the picker; the runtime probe
336
+ * reads the values via the TUI settings adapter (see
337
+ * `packages/cli/boot/tui-settings-adapter.ts`).
338
+ */
339
+ wrongProxyEnabled: boolean;
340
+ wrongProxyUrl: string;
331
341
  } | {
332
342
  type: 'settingsClose';
333
343
  } | {
@@ -378,6 +388,23 @@ export type Action = {
378
388
  /** Discard the draft and leave edit mode without changing the word. */
379
389
  | {
380
390
  type: 'settingsThinkingEditCancel';
391
+ }
392
+ /** Begin free-text editing of the WrongProxy URL (Enter on its row). */
393
+ | {
394
+ type: 'settingsWrongProxyUrlEditStart';
395
+ }
396
+ /** Replace the in-progress WrongProxy URL draft with the given buffer. */
397
+ | {
398
+ type: 'settingsWrongProxyUrlEditChange';
399
+ draft: string;
400
+ }
401
+ /** Commit the draft as the new WrongProxy URL (validated in the reducer). */
402
+ | {
403
+ type: 'settingsWrongProxyUrlEditCommit';
404
+ }
405
+ /** Discard the draft and leave edit mode without changing the URL. */
406
+ | {
407
+ type: 'settingsWrongProxyUrlEditCancel';
381
408
  } | {
382
409
  type: 'statuslineOpen';
383
410
  hiddenItems: StatuslineItem[];
@@ -95,7 +95,7 @@ export type Settings = {
95
95
  cacheTtl: CacheTtl;
96
96
  /** Where to persist settings: 'global' or 'project'. */
97
97
  configScope: 'global' | 'project';
98
- animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'cycle';
98
+ animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'static' | 'cycle';
99
99
  /** When true, read tool includes codebase-index symbols alongside file content. */
100
100
  readSymbols: boolean;
101
101
  /** Full mouse mode: in-app managed scroll + clickable UI (SGR tracking on). */
@@ -110,5 +110,17 @@ export type Settings = {
110
110
  breakerEnabled?: boolean | undefined;
111
111
  /** Auto kill/reset delay (ms) when the breaker trips. 0 = manual recovery. */
112
112
  breakerAutoKillResetMs?: number | undefined;
113
+ /**
114
+ * WrongProxy / WrongTrace: master switch. When true AND the daemon at
115
+ * `wrongProxyUrl` is reachable, every provider's base URL is rewritten
116
+ * through `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is
117
+ * excluded by spec. Mirrors `SettingsPickerPatch.wrongProxyEnabled`.
118
+ */
119
+ wrongProxyEnabled?: boolean | undefined;
120
+ /**
121
+ * WrongProxy / WrongTrace URL. Default `http://localhost:3444`. Mirrors
122
+ * `SettingsPickerPatch.wrongProxyUrl`.
123
+ */
124
+ wrongProxyUrl?: string | undefined;
113
125
  };
114
126
  //# sourceMappingURL=app-settings-type.d.ts.map
@@ -326,7 +326,25 @@ export type State = {
326
326
  * meta-mode `'cycle'` that rotates through the variant styles every
327
327
  * `CYCLE_INTERVAL_SECONDS`. Persisted on every ←/→ change in `/settings`.
328
328
  */
329
- animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'cycle';
329
+ animationStyle: 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'static' | 'cycle';
330
+ /**
331
+ * WrongProxy / WrongTrace: master switch. When true AND the daemon at
332
+ * `wrongProxyUrl` is reachable, every provider's base URL is rewritten
333
+ * through `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is
334
+ * excluded by spec. Mirrors `Settings.wrongProxyEnabled` and the
335
+ * `tools.wrongProxy.enabled` config key. Picker field 59.
336
+ */
337
+ wrongProxyEnabled: boolean;
338
+ /**
339
+ * WrongProxy / WrongTrace URL. Default `http://localhost:3444`. The
340
+ * CLI's periodic probe targets `<wrongProxyUrl>/api/health`; a 2xx
341
+ * response flips the runtime's `active` flag. Picker field 60.
342
+ */
343
+ wrongProxyUrl: string;
344
+ /** True while free-text editing the WrongProxy URL (Enter on its row). */
345
+ wrongProxyUrlEditing: boolean;
346
+ /** In-progress text buffer while `wrongProxyUrlEditing`. */
347
+ wrongProxyUrlDraft: string;
330
348
  /** Whether the process circuit breaker gates bash/exec. */
331
349
  breakerEnabled: boolean;
332
350
  /** Auto kill/reset delay (ms) when the breaker trips. 0 = manual recovery. */
@@ -1,7 +1,7 @@
1
1
  import type React from 'react';
2
2
  import type { AppViewProps } from './app-view-contract.js';
3
3
  import type { usePlanPanelData } from './components/plan-panel.js';
4
- import type { useSidebarConnections, useSidebarKanban, useSidebarProcessList } from './hooks/use-sidebar-panel-data.js';
4
+ import type { useSidebarConnections, useSidebarKanban, useSidebarProcessList, useSidebarWrongProxy } from './hooks/use-sidebar-panel-data.js';
5
5
  import type { PanelId } from './ui-contracts.js';
6
6
  export interface AppViewSidebarProps {
7
7
  host: AppViewProps['host'];
@@ -14,6 +14,14 @@ export interface AppViewSidebarProps {
14
14
  sidebarConnectionsData: ReturnType<typeof useSidebarConnections>;
15
15
  sidebarKanbanData: ReturnType<typeof useSidebarKanban>;
16
16
  sidebarPlanData: ReturnType<typeof usePlanPanelData>;
17
+ /** Master switch from `liveSettings?.wrongProxyEnabled`. The WrongProxy
18
+ * sidebar panel renders only while this is true; when false the entire
19
+ * panel returns `null` so it doesn't take a slot in `SIDEBAR_PANEL_LIMIT`
20
+ * or burn IPC probes. */
21
+ sidebarWrongProxyEnabled: boolean;
22
+ /** Live probe data from `useSidebarWrongProxy`. `null` while the panel
23
+ * is bootstrapping or the daemon URL hasn't produced a response yet. */
24
+ sidebarWrongProxyData: ReturnType<typeof useSidebarWrongProxy>;
17
25
  }
18
- export declare function AppViewSidebar({ host, runtime, sidebarWidth, sidebarContentWidth, sidebarSlotVisible, hiddenSidebarPanelCount, sidebarProcessData, sidebarConnectionsData, sidebarKanbanData, sidebarPlanData, }: AppViewSidebarProps): React.ReactElement | null;
26
+ export declare function AppViewSidebar({ host, runtime, sidebarWidth, sidebarContentWidth, sidebarSlotVisible, hiddenSidebarPanelCount, sidebarProcessData, sidebarConnectionsData, sidebarKanbanData, sidebarPlanData, sidebarWrongProxyEnabled, sidebarWrongProxyData, }: AppViewSidebarProps): React.ReactElement | null;
19
27
  //# sourceMappingURL=app-view-sidebar.d.ts.map
@@ -19,7 +19,7 @@ interface AppViewStateOptions {
19
19
  export declare function deriveAppViewState(options: AppViewStateOptions): {
20
20
  inputHint: string;
21
21
  composerStatus: import("./components/composer-status-chip.js").ComposerStatus;
22
- composerAnimationStyle: "breathe" | "cycle" | "dots" | "pulse" | "rainbow" | "wave";
22
+ composerAnimationStyle: "breathe" | "cycle" | "dots" | "pulse" | "rainbow" | "static" | "wave";
23
23
  inputHeight: number;
24
24
  hideInput: boolean;
25
25
  lowerFunctionPanelOpen: boolean;
@@ -1,7 +1,7 @@
1
1
  export declare const HUE_WHEEL: string[];
2
2
  export declare const BREATHE_FRAMES: string[];
3
3
  export declare const DOTS_FRAMES: string[];
4
- export declare const ANIMATION_STYLES: readonly ['rainbow', 'wave', 'pulse', 'dots', 'breathe'];
4
+ export declare const ANIMATION_STYLES: readonly ['rainbow', 'wave', 'pulse', 'dots', 'breathe', 'static'];
5
5
  export type AnimationStyle = (typeof ANIMATION_STYLES)[number];
6
6
  export declare const DEFAULT_ANIMATION_STYLE: AnimationStyle;
7
7
  export declare const ANIMATION_STYLE_DESCS: Record<AnimationStyle, string>;
@@ -36,7 +36,7 @@ export declare function colorPhaseFromTime(elapsedMs: number): number;
36
36
  /**
37
37
  * Cycle through every other `AnimationStyle` in order, returning to the
38
38
  * start once the list is exhausted. `rainbow` is excluded from the cycle
39
- * (it's the default/canonical look); cycle goes through the four variant
39
+ * (it's the default/canonical look); cycle goes through the five variant
40
40
  * styles only.
41
41
  */
42
42
  export declare const CYCLE_ORDER: readonly AnimationStyle[];
@@ -53,31 +53,66 @@ export interface HistoryScrollController {
53
53
  * scrollbar/copy-icon/wheel paths remain intact because they call their own
54
54
  * handlers; this only kicks in when the mouse layer explicitly routes a
55
55
  * left-press into the card band.
56
+ *
57
+ * Column contract (v1.1 M3): `col` is a HISTORY-BAND column (0-based from
58
+ * the band's left edge). The controller translates it to card-body-local
59
+ * coordinates before storing: bordered kinds (assistant/thinking/user) have
60
+ * a MESSAGE_PANEL_CHROME_WIDTH (2) left gutter, and gutter columns CLAMP to
61
+ * the card's first visible column — a press on the border/padding selects
62
+ * from the start of the card's visible line, mirroring standard editor
63
+ * margin-click behavior. Gutterless kinds (info, memory-lifecycle, tool
64
+ * groups, …) pass the column through unchanged.
65
+ *
66
+ * Known limitation: `warn` rows still render a `⚠ ` prefix inline with no
67
+ * prefix translation (the wrap map covers assistant/thinking/user/info —
68
+ * see wrap-geometry.ts). User cards WITH a paste block also keep the v1
69
+ * naive path: they render two text regions while the copy base holds one.
70
+ *
71
+ * Inline prefixes (user `👤 USER ` label, info `ℹ ` icon) are translated
72
+ * row-aware in the assembler: the wrap map wraps `prefix + first line`
73
+ * together exactly as the renderer's single Text node does, and
74
+ * resolveRowCol shifts row-0 columns past the measured prefix width
75
+ * (string-width cells), clamping label/icon clicks to the text start —
76
+ * the same margin-click semantics as the gutter clamp above. Constants
77
+ * are single-sourced in wrap-geometry.ts and consumed by entry.tsx.
56
78
  */
57
79
  beginSelection(row: number, col: number): void;
58
80
  /**
59
- * Extend an active selection to `row`,`col`. If no selection is in progress,
60
- * the call is a no-op. Crossing into the gutter or below the viewport cancels
61
- * the drag internally — leaving stale viewport-relative coords around after
62
- * a mid-drag escape would let the next right-click paste from the wrong
63
- * card, which is the worse failure mode than the selection disappearing.
81
+ * Extend an active selection to `row`,`col` (history-band viewport cell,
82
+ * translated to body-local exactly as in {@link beginSelection}). If no
83
+ * selection is in progress, the call is a no-op. Columns outside the band
84
+ * or rows below the viewport / above 0 cancel the drag internally — leaving
85
+ * stale viewport-relative coords around after a mid-drag escape would let
86
+ * the next right-click paste from the wrong card, which is the worse
87
+ * failure mode than the selection disappearing.
64
88
  */
65
89
  extendSelection(row: number, col: number): void;
66
90
  /**
67
- * End an active drag (left-release). Does NOT write to the clipboard — the
68
- * copy is performed by {@link commitSelection}, which is triggered by a
69
- * separate right-click in the history band (per the drag-select-then-commit
70
- * contract). If no selection is in progress, the call is a no-op.
91
+ * Mark an active drag as ended (left-release) WITHOUT copying. The primary
92
+ * release path goes straight to {@link commitSelection}; this intermediate
93
+ * state exists for callers that end a drag but defer the copy decision,
94
+ * and it pins {@link extendSelection} against stray post-release motion.
95
+ * If no selection is in progress, the call is a no-op.
71
96
  */
72
97
  endSelection(): void;
98
+ /**
99
+ * True while a drag-selection has been begun and not yet committed,
100
+ * cleared, or cancelled. Lets the key handler decide synchronously whether
101
+ * a left-release should trigger {@link commitSelection} — a release with
102
+ * no active selection must not spawn a pointless async clipboard path.
103
+ */
104
+ hasSelection(): boolean;
73
105
  /** Drop any in-progress or committed selection without copying. */
74
106
  clearSelection(): void;
75
107
  /**
76
- * Commit the active selection to the system clipboard. Returns true if a
77
- * non-empty selection was resolved and the write succeeded. Returns false
78
- * silently when there is no selection, the selection is empty (e.g. the drag
79
- * never moved), or the write fails — the caller can show a transient notice
80
- * on the truthy branch and stay silent on the falsy branch.
108
+ * Commit the active selection to the system clipboard. Triggered by the
109
+ * left-button release that ends a drag (the release-commits-copy
110
+ * contract); a right-press in the history band commits any selection that
111
+ * is still pending after an unusual end. Returns true if a non-empty
112
+ * selection was resolved and the write succeeded. Returns false silently
113
+ * when there is no selection, the selection is empty (e.g. the drag never
114
+ * moved), or the write fails — the caller can show a transient notice on
115
+ * the truthy branch and stay silent on the falsy branch.
81
116
  */
82
117
  commitSelection(): Promise<boolean>;
83
118
  }
@@ -4,15 +4,24 @@
4
4
  * All three columns are always reserved, so copy affordances and scrollability
5
5
  * never reflow chat content.
6
6
  *
7
+ * The gap column doubles as the drag-selection highlight band: while a drag is
8
+ * in progress, the subscribing component re-renders ONLY this rail (via
9
+ * useSyncExternalStore on {@link SelectionBandStore}) — the history cards
10
+ * never re-render, and because the band occupies the already-reserved gap
11
+ * column the layout (and the fixed-height overflow-hidden viewport) cannot
12
+ * change mid-drag.
13
+ *
7
14
  * Extracted from scrollable-history.tsx.
8
15
  */
9
16
  import type React from 'react';
10
17
  import type { CopyHit } from './copy-geometry.js';
11
- export declare function Scrollbar({ rows, offset, total, copyHits, copiedEntryId, }: {
18
+ import { type SelectionBandStore } from './selection-band-store.js';
19
+ export declare function Scrollbar({ rows, offset, total, copyHits, copiedEntryId, selectionBandStore, }: {
12
20
  rows: number;
13
21
  offset: number;
14
22
  total: number;
15
23
  copyHits: readonly CopyHit[];
16
24
  copiedEntryId?: number | null | undefined;
25
+ selectionBandStore?: SelectionBandStore | undefined;
17
26
  }): React.ReactElement;
18
27
  //# sourceMappingURL=scrollbar-rail.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Minimal external store for the drag-selection highlight band.
3
+ *
4
+ * Why an external store instead of React state: the selection gesture must
5
+ * not re-render the history cards. Selection coordinates already live in a
6
+ * ref (see use-history-controller) precisely so a drag causes zero renders;
7
+ * this store gives the one leaf that DOES need to update — the right-edge
8
+ * rail — a subscription channel. The controller publishes on every selection
9
+ * mutation, and only components that call useSyncExternalStore on the store
10
+ * re-render. Cards never subscribe, so they never re-render mid-drag, and
11
+ * because the band renders inside the rail's already-reserved columns the
12
+ * layout (and the fixed-height overflow-hidden viewport) cannot change.
13
+ *
14
+ * Snapshots are immutable; `publish` suppresses value-identical updates so a
15
+ * drag that holds the same row span doesn't spam listeners.
16
+ */
17
+ /** Row span of an in-progress drag, in viewport rows (0-based, inclusive). */
18
+ export interface SelectionBand {
19
+ readonly topRow: number;
20
+ readonly bottomRow: number;
21
+ /** Row under the live drag head — rendered denser so the user can see
22
+ * where the gesture currently points. */
23
+ readonly headRow: number;
24
+ }
25
+ export type SelectionBandSnapshot = SelectionBand | null;
26
+ export interface SelectionBandStore {
27
+ subscribe(listener: () => void): () => void;
28
+ getSnapshot(): SelectionBandSnapshot;
29
+ publish(next: SelectionBandSnapshot): void;
30
+ }
31
+ /** Band covering the anchor..head row span of an in-progress drag. */
32
+ export declare function bandFromSelection(anchor: {
33
+ row: number;
34
+ }, head: {
35
+ row: number;
36
+ }): SelectionBand;
37
+ export declare function createSelectionBandStore(): SelectionBandStore;
38
+ //# sourceMappingURL=selection-band-store.d.ts.map
@@ -1,4 +1,4 @@
1
- import type { HistoryEntry } from './index.js';
1
+ import type { HistoryEntry } from './types.js';
2
2
  /**
3
3
  * Selection rectangle in viewport cell coordinates, normalized so
4
4
  * `topLeft.row <= bottomRight.row` and the column pairs are likewise ordered.
@@ -107,5 +107,12 @@ export declare function assembleSelectionText(opts: {
107
107
  slices: readonly SelectionSlice[];
108
108
  entriesById: ReadonlyMap<number, HistoryEntry>;
109
109
  toolGroupsByHeadId?: ReadonlyMap<number, readonly number[]> | undefined;
110
+ /**
111
+ * Render width used to build the wrap-aware row→line translation for
112
+ * assistant/thinking cards (v1.1 M4). When omitted, wrapped kinds fall
113
+ * back to the v1 naive mapping below — callers that cannot know the
114
+ * width keep their existing behavior.
115
+ */
116
+ termWidth?: number | undefined;
110
117
  }): string;
111
118
  //# sourceMappingURL=selection-helpers.d.ts.map
@@ -1,7 +1,8 @@
1
1
  import { type ScrollAnchor, type ScrollGeometry } from '../../scroll-anchor.js';
2
2
  import type { CopyHit } from './copy-geometry.js';
3
- import type { MountedCardSpan } from './scrollbar-geometry.js';
4
3
  import type { HistoryScrollController } from './scroll-controller-types.js';
4
+ import type { MountedCardSpan } from './scrollbar-geometry.js';
5
+ import { type SelectionBandStore } from './selection-band-store.js';
5
6
  import type { HistoryEntry } from './types.js';
6
7
  export interface UseHistoryControllerOptions {
7
8
  geometry: ScrollGeometry;
@@ -41,6 +42,10 @@ export interface UseHistoryControllerOptions {
41
42
  startedAt: number;
42
43
  } | null | undefined;
43
44
  };
45
+ /** External store for the drag-selection highlight band. The controller
46
+ * publishes selection geometry here so the rail leaf can re-render on
47
+ * drag motion WITHOUT any history card re-rendering. */
48
+ selectionBandStore?: SelectionBandStore | undefined;
44
49
  setAnchor: (anchor: {
45
50
  id: number;
46
51
  clip: number;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Wrap-aware card-row → source-text translation for drag-selection text
3
+ * recovery (v1.1 item M4).
4
+ *
5
+ * v1's assembler indexed the entry's source lines by the card's VISUAL row,
6
+ * which equals the source line only when no line wraps. Any wrapped line
7
+ * desynchronizes the index and garbles the copied text. This module supplies
8
+ * the per-row mapping against the entry's SOURCE text (sanitized, with the
9
+ * assistant next-steps block stripped exactly like the renderer).
10
+ *
11
+ * Exactness boundary: the mapping is EXACT for plain prose and thinking text
12
+ * — MarkdownView renders those lines as-is and Ink wraps them with the same
13
+ * wrap-ansi call mirrored below. For assistant text containing markdown
14
+ * STRUCTURE (headings, lists, tables, fenced code), MarkdownView restyles
15
+ * the render (heading styles, bullet glyphs, table layout), so the visual
16
+ * rows can diverge from this source-text map. The copy semantics are
17
+ * deliberately source-based in that case: a drag recovers what the model
18
+ * wrote, not the renderer's decoration. Visual-row alignment for
19
+ * heavily-structured markdown is approximate and documented as such.
20
+ *
21
+ * The render truth this mirrors (verified against the components):
22
+ * - `assistant` cards (entry.tsx) render `parseNextSteps(text, true).stripped`
23
+ * through AssistantBody → MarkdownView, wrapped by Ink's Text at
24
+ * `assistantContentWidth(termWidth)` = termWidth − 2. Ink wraps via
25
+ * wrap-ansi with `{ trim: false, hard: true }` (ink/build/wrap-text.js).
26
+ * The markdown transform above applies only to structured spans; plain
27
+ * prose lines pass through unwrapped-by-markdown and are exact here.
28
+ * - `thinking` cards render sanitizeTerminalText(text) at the same width
29
+ * with no markdown transform — exact.
30
+ * - `user` cards render the `'👤 USER '` label inline before the text in
31
+ * the same bordered Text (entry.tsx), so row 0 = label cells then text;
32
+ * wrapped continuation rows start at the text. `pasteContent` renders as
33
+ * a second block (`' ↳ '` preview) after a newline; the copy base is
34
+ * `pasteContent || text` (copy-icon.ts), so a card with BOTH blocks shows
35
+ * two text regions while the base holds one — those keep the v1 naive
36
+ * mapping (assembler-side residual, documented here).
37
+ * - `info` cards are unbordered plain Text: the `'ℹ '` icon inline before
38
+ * the text, wrapped at the FULL termWidth (no panel gutter).
39
+ *
40
+ * Inline-prefix translation: the label/icon cells are chrome, not copyable
41
+ * text. buildBodyRowMap wraps `prefix + first line` together — the renderer
42
+ * concatenates them into one Text node before Ink wraps it, so the wrap
43
+ * boundaries are only correct when the prefix participates in the wrap — and
44
+ * records the prefix width in terminal cells (string-width, the project's
45
+ * measurer; 👤 is a surrogate pair — 2 code units AND 2 cells — so both
46
+ * shipped prefixes happen to have prefixWidth === prefix.length). resolveRowCol
47
+ * shifts row-0 columns past it, clamping prefix clicks to the text start:
48
+ * the same margin-click semantics M3 gives the card gutter. The clamp works
49
+ * in CELLS while segment ranges are in CHARACTERS — exact when the body's
50
+ * characters are single-cell, the same standing M4 approximation that
51
+ * already governs text content. Narrow panes where the label alone exceeds
52
+ * the content width produce label-only rows (zero-width spans) — that
53
+ * mirrors Ink's render exactly and is deliberately preserved: any divergence
54
+ * between the map and the renderer breaks WYSIWYG slicing.
55
+ *
56
+ * Origin: card row 0 = body row 0, matching v1's documented origin (one card
57
+ * row per source line when nothing wraps). Any chrome-row offset above the
58
+ * body is a preexisting v1 approximation outside M4's scope — preserved, not
59
+ * altered, so every pinned expectation keeps its exact meaning.
60
+ *
61
+ * The load-bearing invariant (verified empirically against wrap-ansi@10.0.1,
62
+ * the exact version ink 7.1.1 resolves): for each source line,
63
+ * `wrapAnsi(line, w, {trim:false, hard:true}).split('\n').join('') === line`.
64
+ * Segment prefix sums therefore give EXACT source offsets. For a non-wrapped
65
+ * line the single segment spans the whole line with `start = 0`, so every
66
+ * resolve here reduces to v1's math (`offset = col`, end = `col + 1`).
67
+ */
68
+ import type { HistoryEntry } from './types.js';
69
+ /** One wrapped visual row inside a card body: the source line it shows and
70
+ * the half-open [start, end) character range of that line it covers. */
71
+ export interface BodyRowSpan {
72
+ line: number;
73
+ start: number;
74
+ end: number;
75
+ }
76
+ export interface BodyRowMap {
77
+ /** Per-card-row spans, index 0 = card row 0 (v1 origin). */
78
+ rows: readonly BodyRowSpan[];
79
+ /** The exact text the map indexes into — the render base (sanitized; for
80
+ * assistant entries with the next-steps block stripped exactly like the
81
+ * renderer). Slicing this text is WYSIWYG for the wrapped kinds. */
82
+ text: string;
83
+ /** Terminal CELLS of inline chrome rendered before the first text
84
+ * character on row 0 (user label / info icon). 0 for prefix-less kinds. */
85
+ prefixWidth: number;
86
+ }
87
+ /** Inline label the renderer places before a user card's text
88
+ * (entry.tsx: `<Text bold>👤 USER </Text>` then the text, one Text node).
89
+ * Exported so entry.tsx consumes the single source (p3) — drift between the
90
+ * render and this constant silently mis-offsets user-card selection. */
91
+ export declare const USER_LABEL = "\uD83D\uDC64 USER ";
92
+ /** Inline icon the renderer places before an info card's text
93
+ * (entry.tsx: `<Text>ℹ </Text>` then the text, one Text node). */
94
+ export declare const INFO_PREFIX = "\u2139 ";
95
+ /** Kinds whose render path this module mirrors. Everything else uses the
96
+ * v1 naive mapping in assembleSelectionText. Declared as a type predicate
97
+ * (taking the entry, not the kind) so call sites narrow the HistoryEntry
98
+ * union — every member kind carries `text`, the others may not. The
99
+ * assembler additionally restricts user cards to the no-pasteContent shape
100
+ * (see selection-helpers): a card with a paste block renders two text
101
+ * regions but the copy base holds one, so those stay on the v1 path. */
102
+ export declare function hasWrapMap(entry: HistoryEntry): entry is Extract<HistoryEntry, {
103
+ kind: 'assistant' | 'thinking' | 'user' | 'info';
104
+ }>;
105
+ /**
106
+ * Build the card-row → (source line, char range) map for one text card.
107
+ * Pure and deterministic from (kind, text, termWidth).
108
+ *
109
+ * For prefixed kinds (user label, info icon) line 0 is wrapped AS the
110
+ * renderer sees it — `prefix + line` in one Text node — so wrap boundaries
111
+ * match the visual rows; each segment is then translated back to
112
+ * text-local character coordinates (the prefix chars subtracted, clamped).
113
+ */
114
+ export declare function buildBodyRowMap(kind: HistoryEntry['kind'], rawText: string, termWidth: number): BodyRowMap;
115
+ /**
116
+ * Resolve the (source line, char offset) a card row + column points at,
117
+ * clamping out-of-range rows to the last body row and columns to the
118
+ * wrapped segment.
119
+ *
120
+ * Column semantics match v1: `col` is a body-local character offset (v1
121
+ * sliced the source line by it directly), so a non-wrapped line resolves to
122
+ * exactly v1's numbers. `atEnd` is set for an inclusive drag endpoint (end
123
+ * of a selection range): the offset then counts one past the column,
124
+ * clamped to the segment's end — mirroring v1's `endCol + 1`.
125
+ */
126
+ export declare function resolveRowCol(map: BodyRowMap, row: number, col: number, atEnd: boolean): {
127
+ line: number;
128
+ offset: number;
129
+ };
130
+ //# sourceMappingURL=wrap-geometry.d.ts.map
@@ -83,7 +83,7 @@ export declare function formatMultiDiffSummaryThreshold(n: number): string;
83
83
  export declare function formatEnhanceDelay(ms: number): string;
84
84
  export declare function formatPreRefineSeconds(s: number): string;
85
85
  /** Animation style choices for the settings picker — all AnimationStyles plus 'cycle'. */
86
- export declare const ANIMATION_STYLE_CHOICES: readonly ["rainbow", "wave", "pulse", "dots", "breathe", "cycle"];
86
+ export declare const ANIMATION_STYLE_CHOICES: readonly ["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"];
87
87
  export type AnimationStyleChoice = (typeof ANIMATION_STYLE_CHOICES)[number];
88
88
  /** Human-readable label for an animation style choice (including cycle). */
89
89
  export declare function formatAnimationStyle(style: AnimationStyleChoice): string;
@@ -101,6 +101,14 @@ export declare const SETTINGS_FIELD_COUNT: number;
101
101
  * definitions to keep the three in sync. If the row order changes, update this.
102
102
  */
103
103
  export declare const THINKING_WORD_FIELD = 22;
104
+ /**
105
+ * Field index of the "WrongProxy URL" row. Same rationale as
106
+ * {@link THINKING_WORD_FIELD}: the keyboard handler in `use-app-picker-keys.ts`
107
+ * dispatches `settingsWrongProxyUrlEditStart` when the user presses Enter
108
+ * on this row, so the constant lives next to the row definition to keep
109
+ * the three in sync.
110
+ */
111
+ export declare const WRONGPROXY_URL_FIELD = 60;
104
112
  /**
105
113
  * Field index of the "Multi-diff summary" row. Same rationale as
106
114
  * {@link THINKING_WORD_FIELD}: the keyboard handler in app.tsx dispatches
@@ -83,6 +83,22 @@ export interface SettingsPickerProps {
83
83
  * per PanelId in PANEL_IDS order; each row cycles 'bottom' ↔ 'sidebar'.
84
84
  */
85
85
  panelPositions: import('../ui-contracts.js').PanelPositionMap;
86
+ /**
87
+ * WrongProxy / WrongTrace: master switch. When true AND the daemon at
88
+ * `wrongProxyUrl` is reachable, every provider's base URL is rewritten
89
+ * through `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is
90
+ * excluded by spec. Toggled on the row at field index 59.
91
+ */
92
+ wrongProxyEnabled: boolean;
93
+ /**
94
+ * WrongProxy / WrongTrace URL. Default `http://localhost:3444`. Text
95
+ * field (Enter on the row opens an inline edit). Picker field 60.
96
+ */
97
+ wrongProxyUrl: string;
98
+ /** True while free-text editing the WrongProxy URL (Enter on its row). */
99
+ wrongProxyUrlEditing: boolean;
100
+ /** In-progress text buffer while `wrongProxyUrlEditing`. */
101
+ wrongProxyUrlDraft: string;
86
102
  /** Raw SSE stream debugging toggle — hex-dump every byte received from providers. */
87
103
  debugStream: boolean;
88
104
  /** Statusline density: minimum single-line or detailed multi-line. */
@@ -117,5 +133,5 @@ export interface SettingsPickerProps {
117
133
  fieldRowIndex: readonly number[];
118
134
  }) => void) | undefined;
119
135
  }
120
- export declare function SettingsPicker({ field, filter, mode, delayMs, titleAnimation, yolo, fleetChat, chime, confirmExit, nextPrediction, featureMcp, featurePlugins, featureMemory, featureSkills, featureModelsRegistry, tokenSavingTier, allowOutsideProjectRoot, maxIterations, autoProceedMaxIterations, enhanceDelayMs, enhanceEnabled, enhanceLanguage, preRefineSeconds, indexOnStart, multiDiffSummaryThreshold, thinkingWord, thinkingWordEditing, thinkingWordDraft, reasoningMode, reasoningEffort, reasoningPreserve, cacheTtl, contextAutoCompact, contextStrategy, contextMode, maxConcurrent, logLevel, auditLevel, debugStream, statuslineMode, configScope, profileConfigPath, animationStyle, breakerEnabled, breakerAutoKillResetMs, showModelReasoning, showAgentSwarmPanel, showSageMemoryInject, sageMemoryInjectThreshold, nextStepsTool, readSymbols, panelPositions, inputHeight, hint, onLayoutComputed, }: SettingsPickerProps): React.ReactElement;
136
+ export declare function SettingsPicker({ field, filter, mode, delayMs, titleAnimation, yolo, fleetChat, chime, confirmExit, nextPrediction, featureMcp, featurePlugins, featureMemory, featureSkills, featureModelsRegistry, tokenSavingTier, allowOutsideProjectRoot, maxIterations, autoProceedMaxIterations, enhanceDelayMs, enhanceEnabled, enhanceLanguage, preRefineSeconds, indexOnStart, multiDiffSummaryThreshold, thinkingWord, thinkingWordEditing, thinkingWordDraft, wrongProxyUrlEditing, wrongProxyUrlDraft, reasoningMode, reasoningEffort, reasoningPreserve, cacheTtl, contextAutoCompact, contextStrategy, contextMode, maxConcurrent, logLevel, auditLevel, debugStream, statuslineMode, configScope, profileConfigPath, animationStyle, breakerEnabled, breakerAutoKillResetMs, showModelReasoning, showAgentSwarmPanel, showSageMemoryInject, sageMemoryInjectThreshold, nextStepsTool, readSymbols, panelPositions, wrongProxyEnabled, wrongProxyUrl, inputHeight, hint, onLayoutComputed, }: SettingsPickerProps): React.ReactElement;
121
137
  //# sourceMappingURL=settings-picker.d.ts.map
@@ -114,7 +114,7 @@ export declare function isCurrentSession(rowId: string | undefined, currentSessi
114
114
  * the routed F-key panel twins (`sidebar-panel-frame.tsx` +
115
115
  * `sidebar-panels-{workspace,task}.tsx`). Imported at the top of this file
116
116
  * for the `MODEL CORE`, `PROMPT CACHE`, `SYSTEM`, `AGENT SWARM`, `MISSIONS`,
117
- * `SESSIONS`, and `TOOL TICKER` cards — the migration keeps the persistent
117
+ * and `SESSIONS` cards — the migration keeps the persistent
118
118
  * call sites identical because the shared component preserves the same
119
119
  * `innerWidth` / `marginBottom` / `accent` / `children` contract.
120
120
  */
@@ -1,5 +1,6 @@
1
1
  import type React from 'react';
2
2
  import type { FleetEntry } from '../app-state.js';
3
+ import type { SidebarWrongProxy } from '../hooks/use-sidebar-panel-data.js';
3
4
  import { type WorktreeRow } from '../ui-contracts.js';
4
5
  import type { ProjectPickerItem } from './project-picker.js';
5
6
  export interface ProjectPickerSidebarProps {
@@ -47,4 +48,26 @@ export interface ConnectionsPanelSidebarProps {
47
48
  width: number;
48
49
  }
49
50
  export declare function ConnectionsPanelSidebar({ connections, width, }: ConnectionsPanelSidebarProps): React.ReactElement;
51
+ export interface WrongProxyPanelSidebarProps {
52
+ /**
53
+ * Live probe state. When `null` (URL missing or probe disabled) the
54
+ * panel renders an idle placeholder inside the same frame so the
55
+ * layout never jumps when the toggle flips on mid-session.
56
+ */
57
+ proxy: SidebarWrongProxy | null;
58
+ width: number;
59
+ }
60
+ /**
61
+ * Sidebar twin for the live WrongProxy / WrongTrace daemon. Renders the
62
+ * proxy URL with its round-trip latency, the probe error detail when
63
+ * warn/down, and — when the daemon's `/api/health` body exposes them —
64
+ * the WrongTrace IPC socket path and daemon version.
65
+ *
66
+ * The panel is mounted only when `wrongProxyEnabled` is true at the
67
+ * `app-view-sidebar.tsx` gate — see the `wrongProxyEnabled` usage there.
68
+ * This component still defensively renders an empty-state when
69
+ * `proxy === null` so a mount/unmount race during a toggle flip does
70
+ * not flash an inconsistent card.
71
+ */
72
+ export declare function WrongProxyPanelSidebar({ proxy, width, }: WrongProxyPanelSidebarProps): React.ReactElement;
50
73
  //# sourceMappingURL=sidebar-panels-workspace.d.ts.map
@@ -1,4 +1,4 @@
1
1
  export { EmptyState, fleetStatusVisual, fmtRelative, fmtShortDuration, liveSessionColor, liveSessionGlyph, SidebarWorklistRow, } from './sidebar-panels-shared.js';
2
2
  export { GoalPanelSidebar, type GoalPanelSidebarProps, KanbanPanelSidebar, type KanbanPanelSidebarProps, PlanPanelSidebar, type PlanPanelSidebarProps, ProcessListPanelSidebar, type ProcessListPanelSidebarProps, QueuePanelSidebar, type QueuePanelSidebarProps, SessionsPanelSidebar, type SessionsPanelSidebarProps, TodosPanelSidebar, type TodosPanelSidebarProps, } from './sidebar-panels-task.js';
3
- export { AgentsPanelSidebar, type AgentsPanelSidebarProps, ConnectionsPanelSidebar, type ConnectionsPanelSidebarProps, CoordinatorPanelSidebar, type CoordinatorPanelSidebarProps, FleetPanelSidebar, type FleetPanelSidebarProps, ProjectPickerSidebar, type ProjectPickerSidebarProps, WorktreePanelSidebar, type WorktreePanelSidebarProps, } from './sidebar-panels-workspace.js';
3
+ export { AgentsPanelSidebar, type AgentsPanelSidebarProps, ConnectionsPanelSidebar, type ConnectionsPanelSidebarProps, CoordinatorPanelSidebar, type CoordinatorPanelSidebarProps, FleetPanelSidebar, type FleetPanelSidebarProps, ProjectPickerSidebar, type ProjectPickerSidebarProps, WorktreePanelSidebar, type WorktreePanelSidebarProps, WrongProxyPanelSidebar, type WrongProxyPanelSidebarProps, } from './sidebar-panels-workspace.js';
4
4
  //# sourceMappingURL=sidebar-panels.d.ts.map
@@ -29,6 +29,12 @@ export interface StatusBarRailBuildParams {
29
29
  } | undefined;
30
30
  cache?: {
31
31
  hitRatio: number;
32
+ readTokens: number;
33
+ writeTokens: number;
34
+ savedUsd: number;
35
+ /** 5-min / 1-hour cache-write split; present for Anthropic-family providers. */
36
+ cacheWrite5m?: number | undefined;
37
+ cacheWrite1h?: number | undefined;
32
38
  } | undefined;
33
39
  queueCount?: number | undefined;
34
40
  hint?: string | undefined;
@@ -1,5 +1,5 @@
1
1
  import type { Settings } from '../app-settings-type.js';
2
- type AnimationStyle = 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'cycle';
2
+ type AnimationStyle = 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'static' | 'cycle';
3
3
  export declare function useLiveSettingsState({ getSettings, titleController, chime, confirmExit, }: {
4
4
  getSettings?: (() => Settings) | undefined;
5
5
  titleController?: {
@@ -1,4 +1,4 @@
1
- import { type MouseTrackingPolicy } from '../mouse.js';
1
+ import type { MouseTrackingPolicy } from '../mouse.js';
2
2
  type MouseWritable = {
3
3
  write(data: string): unknown;
4
4
  } | undefined;