@oh-my-pi/pi-tui 18.4.12 → 18.5.1

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +61 -11
  2. package/dist/types/active-terminal.d.ts +30 -0
  3. package/dist/types/components/markdown.d.ts +13 -4
  4. package/dist/types/native/encode.d.ts +1 -0
  5. package/dist/types/native/node.d.ts +22 -3
  6. package/dist/types/overlays/hub-frame.d.ts +4 -1
  7. package/dist/types/overlays/jobs-panel.d.ts +1 -7
  8. package/dist/types/overlays/report-panel.d.ts +68 -0
  9. package/dist/types/overlays/thinking-selector.d.ts +2 -2
  10. package/dist/types/prompt/composer-cache.d.ts +0 -16
  11. package/dist/types/prompt/composer.d.ts +17 -7
  12. package/dist/types/prompt/custom-editor.d.ts +2 -1
  13. package/dist/types/prompt/welcome.d.ts +17 -42
  14. package/dist/types/status-line/context-usage.d.ts +7 -5
  15. package/dist/types/terminal-capabilities.d.ts +1 -1
  16. package/dist/types/terminal.d.ts +1 -10
  17. package/dist/types/thinking.d.ts +1 -1
  18. package/dist/types/tools/bash.d.ts +7 -2
  19. package/dist/types/tools/task.d.ts +5 -1
  20. package/dist/types/windows-input-mode.d.ts +12 -0
  21. package/package.json +9 -9
  22. package/src/active-terminal.ts +80 -0
  23. package/src/bracketed-paste.ts +10 -3
  24. package/src/components/markdown.ts +473 -105
  25. package/src/desktop-notify.ts +2 -1
  26. package/src/kitty-graphics.ts +7 -1
  27. package/src/native/backend.ts +11 -1
  28. package/src/native/encode.ts +13 -1
  29. package/src/native/node.ts +21 -4
  30. package/src/native/reconcile.ts +12 -4
  31. package/src/overlays/ask-dialog.ts +3 -7
  32. package/src/overlays/hub-frame.ts +19 -1
  33. package/src/overlays/jobs-panel.ts +6 -53
  34. package/src/overlays/model-browser.ts +30 -16
  35. package/src/overlays/model-hub.ts +17 -4
  36. package/src/overlays/plan-review-overlay.ts +15 -1
  37. package/src/overlays/report-panel.ts +191 -0
  38. package/src/overlays/thinking-selector.ts +11 -11
  39. package/src/prompt/composer-cache.ts +11 -92
  40. package/src/prompt/composer.ts +29 -27
  41. package/src/prompt/custom-editor.ts +39 -12
  42. package/src/prompt/tips.txt +4 -0
  43. package/src/prompt/welcome.ts +101 -372
  44. package/src/render/render-utils.ts +5 -1
  45. package/src/status-line/context-usage.ts +21 -48
  46. package/src/terminal-capabilities.ts +22 -3
  47. package/src/terminal.ts +34 -60
  48. package/src/theme/symbols.ts +5 -3
  49. package/src/thinking.ts +1 -1
  50. package/src/tools/bash.ts +24 -5
  51. package/src/tools/streaming-output.ts +5 -0
  52. package/src/tools/task.ts +6 -2
  53. package/src/tui.ts +283 -53
  54. package/src/windows-input-mode.ts +110 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.5.1] - 2026-10-03
6
+
7
+ ### Added
8
+
9
+ - Added native terminal support for submitting explicit composer prompts atomically, preserving displaced drafts and attachments for local recall.
10
+ - Added progress percentages to subagent entries in the agent tree, task, and wait views.
11
+ - Added a `Rebuilding…` indicator for lengthy tmux resize redraws without flashing it for quick updates.
12
+ - Added `writeTerminalSequence()` for sending supported terminal escape sequences through the active terminal output stream, with stdout fallback when no terminal is active.
13
+
14
+ ### Changed
15
+
16
+ - Clipboard payloads are now represented by their length in `PI_TUI_WRITE_LOG` rather than by their contents.
17
+
18
+ ### Fixed
19
+
20
+ - Fixed pending clipboard-image attachments being bypassed when subsequent input or native prompts were submitted before loading completed.
21
+ - Improved narrow `/models` layouts by retaining the scope sidebar while simplifying and truncating model rows as needed.
22
+ - Fixed Markdown rendering with themes that do not define their own symbol set; the active theme's symbols are now used as a fallback.
23
+ - Fixed model role assignment showing models that are unavailable for the selected provider.
24
+ - Improved tmux resize, zoom, and rebuild behavior, including smoother coalesced redraws, reduced visual artifacts and extra output, correct transcript restoration after rapid size changes, and preservation of history when panes are resized.
25
+ - Fixed multiline paste on Windows inserting escape-code fragments instead of line breaks, and prevented bracketed-paste markers from appearing in the composer.
26
+ - Fixed terminal notifications occasionally corrupting the screen with stray escape-code fragments during streaming output.
27
+ - Added rendering and notification compatibility for Monstar terminals, including Kitty graphics, hyperlinks, synchronized output, styled underlines, progress keepalives, and Monstar-focused desktop notifications.
28
+ - Fixed Agent Hub transcripts crashing when assistant messages do not include usage or cost data.
29
+ - Fixed idle terminal activity notifications while preserving bracketed-paste recovery during input and rendering.
30
+ - Fixed diff blocks in ask questions losing their layout; additions and removals now retain separate diff highlighting.
31
+ - Fixed duplicate ASCII Plan, Prewalk, and Goal labels in the status line.
32
+ - Improved Markdown rendering for long and streamed messages, including display math, fenced code, reference links, lists, whitespace, emphasis, and line breaks, so completed content no longer shows raw markup, misplaced blank lines, or broken block layout.
33
+
34
+ ## [18.5.0] - 2026-10-03
35
+
36
+ ### Breaking Changes
37
+
38
+ - `WelcomeComponent` no longer takes a model or provider: its constructor is `(version)`, and `setModel()`, `setRecentSessions()`, `setLspServers()`, `handleNativeEvent()`, `RecentSession`, `LspServerInfo`, `WELCOME_SESSION_SLOTS` and `WELCOME_LSP_SLOTS` are gone; `ComposerWelcomeUpdate` drops `modelName`/`providerName`/`recentSessions`/`lspServers`, and `ComposerCache` drops `writeWelcome()`, `writeRecentSessions()`, `writeLspServers()`, `ComposerWelcomeCache` and the `welcome`/`recentSessions`/`lspServers` fields of `ComposerStartupCache`.
39
+ - `renderWelcomeTip()` returns its lines without an indent, `Tip:` and the body wrapped together, for the caller to place.
40
+
41
+ ### Added
42
+
43
+ - Added `ReportPanel`, a read-only command report: a `/btw`-style titled box with an Esc hint in text mode (above the editor, or as a full-screen page whose body scrolls on the arrow/page/Home/End keys and the wheel), and natively a `/usage`-style sheet whose body the terminal scrolls once it is long, with a Close button ([#14136](https://github.com/can1357/oh-my-pi/pull/14136) by [@H4vC](https://github.com/H4vC)).
44
+ - Added `contextUsageHead()`, the `/context` title naming the model and its window ([#14136](https://github.com/can1357/oh-my-pi/pull/14136) by [@H4vC](https://github.com/H4vC)).
45
+ - Added `Composer.rowsBelow()`, the rows the chrome under a below-transcript root took in the last frame ([#14136](https://github.com/can1357/oh-my-pi/pull/14136) by [@H4vC](https://github.com/H4vC)).
46
+ - Added `Composer.pinInputToBottom()`, which keeps the input on the bottom row after chrome above the editor closes when rows it displaced went to scrollback ([#14136](https://github.com/can1357/oh-my-pi/pull/14136) by [@H4vC](https://github.com/H4vC)).
47
+ - Added a repeatable native `reveal` (`{ at, n }`): a described node scrolls into view again whenever its `n` changes, without being re-added.
48
+
49
+ ### Changed
50
+
51
+ - `ContextUsageView` is now a bare report body without its own title, rules or card; `setBreakdown()` was removed ([#14136](https://github.com/can1357/oh-my-pi/pull/14136) by [@H4vC](https://github.com/H4vC)).
52
+ - The terminal welcome banner is the gradient logo beside the `omp` wordmark with the version under it and the tip, centered in the terminal; the logo stands alone when the lockup does not fit, and the tip drops below 50 columns. It no longer greets with "Welcome back!", natively either.
53
+
54
+ ### Fixed
55
+
56
+ - Fixed tool previews on Windows showing a working directory on another drive as a raw absolute path instead of its home-shortened `~/…` form.
57
+ - Fixed pasted drive-less `file:///…` URLs (forwarded from a macOS pasteboard or remote session) staying undecoded on Windows instead of loading as image paths.
58
+ - Fixed an output artifact whose file cannot be opened (e.g. a directory in the way) being reported on Windows as a write failure and retried later, instead of a terminal open failure.
59
+ - Fixed plan review's Contents in Tern: clicking an entry, or moving through them with the arrow keys, now scrolls the plan to that section.
60
+
61
+ ### Removed
62
+
63
+ - Removed `JobsPanel`, the `/jobs` transcript block; `/jobs` now opens `JobsSheet` natively ([#14138](https://github.com/can1357/oh-my-pi/pull/14138) by [@H4vC](https://github.com/H4vC)).
64
+
5
65
  ## [18.4.12] - 2026-10-02
6
66
 
7
67
  ### Changed
@@ -2957,14 +3017,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
2957
3017
  - Crash in `visibleWidth()` and grapheme iteration when encountering undefined code points ([#372](https://github.com/badlogic/pi-mono/pull/372) by [@HACKE-RC](https://github.com/HACKE-RC))
2958
3018
  - ZWJ emoji sequences (rainbow flag, family, etc.) now render with correct width instead of being split into multiple characters ([#369](https://github.com/badlogic/pi-mono/pull/369) by [@nathyong](https://github.com/nathyong))
2959
3019
 
2960
- ## [0.29.0] - 2025-12-25
2961
-
2962
- ### Added
2963
-
2964
- - **Auto-space before pasted file paths**: When pasting a file path (starting with `/`, `~`, or `.`) and the cursor is after a word character, a space is automatically prepended for better readability. Useful when dragging screenshots from macOS. ([#307](https://github.com/badlogic/pi-mono/pull/307) by [@mitsuhiko](https://github.com/mitsuhiko))
2965
- - **Word navigation for Input component**: Added Ctrl+Left/Right and Alt+Left/Right support for word-by-word cursor movement. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
2966
- - **Full Unicode input**: Input component now accepts Unicode characters beyond ASCII. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
2967
-
2968
- ### Fixed
2969
-
2970
- - **Readline-style Ctrl+W**: Now skips trailing whitespace before deleting the preceding word, matching standard readline behavior. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
3020
+ Older entries are archived in [packages/tui/CHANGELOG.md@bac7e83b5b0e](https://github.com/can1357/oh-my-pi/blob/bac7e83b5b0eb86c909c17830a6666efc359578b/packages/tui/CHANGELOG.md).
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Ownership of stdout by a started {@link ProcessTerminal}, kept in a leaf
3
+ * module so writers that `terminal.ts` itself imports (terminal capabilities,
4
+ * notifications) can route through the active terminal without an import cycle.
5
+ */
6
+ import type { ProcessTerminal } from "./terminal.js";
7
+ /** The started terminal that owns stdout in this thread, if any. */
8
+ export declare function getActiveTerminal(): ProcessTerminal | null;
9
+ /** Record the terminal that owns stdout (`ProcessTerminal.start`), or release it with `null` (`stop`). */
10
+ export declare function setActiveTerminal(terminal: ProcessTerminal | null): void;
11
+ /** Observe stdout errors through the shared listener. Returns the unregister callback. */
12
+ export declare function registerStdoutErrorHandler(handler: (err: Error) => void): () => void;
13
+ /**
14
+ * Hand `data` to the active terminal's ordered output path. Returns false when
15
+ * no terminal in this thread has started. On the main thread that means the
16
+ * caller owns stdout; a worker thread never sees the main thread's terminal, so
17
+ * there `false` is not permission to write. Prefer {@link writeTerminalSequence}.
18
+ */
19
+ export declare function writeThroughActiveTerminal(data: string): boolean;
20
+ /**
21
+ * Write an out-of-band escape sequence (window title, OSC 52 clipboard,
22
+ * notification). While a TUI owns stdout, its frames go through an off-thread
23
+ * pump in chunks that ignore escape boundaries; a direct `process.stdout.write`
24
+ * can land between two chunks and split a frame's escape sequence, and the host
25
+ * terminal then prints its tail as text. So the sequence takes the active
26
+ * terminal's ordered output path, and goes straight to stdout, best-effort, only
27
+ * when no terminal owns it. A worker thread cannot reach the main thread's
28
+ * terminal and would write around its pump, so it writes nothing.
29
+ */
30
+ export declare function writeTerminalSequence(data: string): void;
@@ -1,8 +1,10 @@
1
1
  import type { DescribeContext, NativeNode } from "../native/node.js";
2
2
  import type { SymbolTheme } from "../symbols.js";
3
3
  import type { Component } from "../tui.js";
4
- /** @internal exported for tests — the grown-line-start block-kind gate. */
4
+ /** @internal exported for tests — the grown-line block-kind gate. */
5
5
  export declare function fastLineStartHazard(grownLine: string): boolean;
6
+ /** @internal exported for tests — the windowed lexer's first-probe window size. */
7
+ export declare const LEX_WINDOW_BYTES: number;
6
8
  /** A hyperlink as the renderer sees it: inline `[text](href)`, `<autolink>`, bare GFM URL, or reference link. */
7
9
  export interface MarkdownLink {
8
10
  /** Flattened visible label with whitespace collapsed to one row; falls back to `href` when empty. */
@@ -82,7 +84,12 @@ export interface MarkdownTheme {
82
84
  * Return null to fall back to fenced code rendering.
83
85
  */
84
86
  resolveMermaidAscii?: (source: string, maxWidth?: number) => string | null;
85
- symbols: SymbolTheme;
87
+ /**
88
+ * Glyphs for quote borders, rules, tables and color swatches. Optional so themes
89
+ * built to the upstream pi-tui `MarkdownTheme` shape (which has no `symbols`)
90
+ * still render; omitted symbols fall back to the active theme's set.
91
+ */
92
+ symbols?: SymbolTheme;
86
93
  }
87
94
  export declare class Markdown implements Component {
88
95
  #private;
@@ -101,8 +108,10 @@ export declare class Markdown implements Component {
101
108
  describe(_cx: DescribeContext): NativeNode;
102
109
  /**
103
110
  * Width-independent source prefix of the last render ending at a frozen
104
- * Markdown block boundary. Only meaningful while streaming (transient
105
- * render cache on); grows monotonically under append-only `setText`.
111
+ * Markdown block boundary that no append can move: it stops in front of a
112
+ * display-math opener whose block an append could still close. Only
113
+ * meaningful while streaming (transient render cache on); grows
114
+ * monotonically under append-only `setText`.
106
115
  */
107
116
  getLastRenderStableText(): string;
108
117
  get transientRenderCache(): boolean;
@@ -29,6 +29,7 @@ export declare function encodeTspJson(verb: TspVerb, value: unknown, params?: Ts
29
29
  * tells the terminal that omp applies its `edit` events (TSP §8.5), so it may keep a
30
30
  * native selection in omp's editors; without it, every key stays omp's. `"undo"`
31
31
  * says omp applies `undo` events, so the terminal may turn ⌃Z in a field into one.
32
+ * `"send"` accepts an explicit prompt for a live composer without simulating keys.
32
33
  */
33
34
  export declare function encodeTspHelloQuery(version?: string): string;
34
35
  /** One decoded APC message: verb, parameters and raw body. */
@@ -28,10 +28,12 @@ export type NativeNode = {
28
28
  */
29
29
  readonly key?: string;
30
30
  /**
31
- * Scroll the node into view, placed like the `reveal` op, when it is
32
- * added. Key a node by what it points at to reveal it again on a move.
31
+ * Scroll the node into view, placed like the `reveal` op. A placement
32
+ * reveals it when it is added: key a node by what it points at to
33
+ * reveal it again on a move. A {@link NativeReveal} reveals it whenever
34
+ * its `n` differs from the previous description of the same node.
33
35
  */
34
- readonly reveal?: "start" | "end" | "nearest";
36
+ readonly reveal?: NativeRevealAt | NativeReveal;
35
37
  /**
36
38
  * Keyboard scrolling forwarded to the terminal (PgUp/PgDn/End reach the
37
39
  * program): moves the scroller at or above the node by `by` whenever
@@ -42,6 +44,17 @@ export type NativeNode = {
42
44
  readonly scroll?: NativeScroll;
43
45
  };
44
46
  }[TspKind];
47
+ /** Where a revealed node lands in its scroller. */
48
+ export type NativeRevealAt = "start" | "end" | "nearest";
49
+ /**
50
+ * A repeatable {@link NativeNode.reveal}: bump `n` to bring an existing node
51
+ * into view again (a Contents entry jumping to its section). A freshly added
52
+ * node is not revealed.
53
+ */
54
+ export interface NativeReveal {
55
+ readonly at: NativeRevealAt;
56
+ readonly n: number;
57
+ }
45
58
  /** A {@link NativeNode.scroll} request. */
46
59
  export interface NativeScroll {
47
60
  readonly by: TspScrollBy;
@@ -122,6 +135,12 @@ export type NativeUiEvent = {
122
135
  | {
123
136
  readonly type: "undo";
124
137
  readonly key: string;
138
+ }
139
+ /** Submit an explicit prompt through the composer's normal path, preserving the previous draft for recall. */
140
+ | {
141
+ readonly type: "send";
142
+ readonly key: string;
143
+ readonly text: string;
125
144
  };
126
145
  /**
127
146
  * A primitive edit the terminal made over its own text selection (cut,
@@ -61,7 +61,10 @@ export declare class HubFrame {
61
61
  constructor(title: string, sidebarBounds: {
62
62
  min: number;
63
63
  max: number;
64
- }, renderSidebar: (width: number, rows: number) => string[], renderBody: (width: number, height: number | undefined) => readonly string[]);
64
+ }, renderSidebar: (width: number, rows: number) => string[], renderBody: (width: number, height: number | undefined) => readonly string[], options?: {
65
+ bodyMinWidth?: number;
66
+ preserveSidebar?: boolean;
67
+ });
65
68
  /** Invalidate the composed layout. */
66
69
  invalidate(): void;
67
70
  /** Measure labels and annotations within this hub's sidebar width bounds. */
@@ -1,4 +1,4 @@
1
- import { type Component, Container } from "../tui.js";
1
+ import type { Component } from "../tui.js";
2
2
  import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
3
3
  /** One async job as the session snapshots it. */
4
4
  export interface JobsPanelJob {
@@ -40,12 +40,6 @@ export interface JobsSheetSource {
40
40
  /** Dismiss the sheet. */
41
41
  close(): void;
42
42
  }
43
- /** The `/jobs` block: `ansi` renders in the terminal, the snapshot describes the native frame. */
44
- export declare class JobsPanel extends Container {
45
- #private;
46
- constructor(snapshot: JobsPanelSnapshot, nowMs: number, ansi: readonly Component[]);
47
- describe(cx: DescribeContext): NativeNode;
48
- }
49
43
  /**
50
44
  * The jobs pill's sheet: a centred `lg` glass sheet titled Background jobs.
51
45
  * A selectable list of every job (running first) sits over the selected
@@ -0,0 +1,68 @@
1
+ import type { TspText } from "@oh-my-pi/pi-wire";
2
+ import { OverlayPanel } from "../chrome/overlay-box.js";
3
+ import type { NativeNode, NativeUiEvent } from "../native/node.js";
4
+ import type { Component } from "../tui.js";
5
+ /** Options of a {@link ReportPanel}. */
6
+ export interface ReportPanelOptions {
7
+ /** Plain title: the text-mode border title, and the native sheet head unless {@link head} is given. */
8
+ readonly title: string;
9
+ /** Styled native sheet head. */
10
+ readonly head?: TspText;
11
+ /** The read-only report; it draws no frame or title of its own. */
12
+ readonly body: Component;
13
+ /**
14
+ * Display form of the key that dismisses the report while it sits above the
15
+ * editor (the editor's interrupt key, which routes to it). Once the panel
16
+ * holds focus ({@link ReportPanel.holdFocus}) the hint shows the key its own
17
+ * input closes on instead.
18
+ */
19
+ readonly closeKey: string;
20
+ /** The focused panel (native sheet, text-mode full-screen page) closes on Esc / its Close button: this runs. */
21
+ readonly onClose: () => void;
22
+ /**
23
+ * Most rows the text-mode panel may take, borders included (the screen rows
24
+ * left above the editor); a taller report scrolls inside it. `undefined`
25
+ * leaves it uncapped.
26
+ */
27
+ readonly maxRows?: () => number | undefined;
28
+ }
29
+ /**
30
+ * A read-only command report (`/changelog`, `/context`, `/tools`, …).
31
+ *
32
+ * Text mode draws a titled box with the body and an Esc hint: above the editor
33
+ * like the `/btw` panel while it fits there (the editor keeps focus and its
34
+ * Esc takes it away), or as a full-screen page on the alternate screen when it
35
+ * is taller, whose body scrolls on the arrow/page/Home/End keys and the wheel.
36
+ * Natively it is a sheet like `/usage`: a centred `lg` glass sheet titled by
37
+ * the report whose body the terminal scrolls (wheel, and the same keys
38
+ * forwarded as scroll requests), then a Close button; Esc closes it.
39
+ */
40
+ export declare class ReportPanel extends OverlayPanel {
41
+ #private;
42
+ readonly nativeOverlay: NonNullable<Component["nativeOverlay"]>;
43
+ constructor(options: ReportPanelOptions);
44
+ /**
45
+ * The panel is shown with focus (native sheet, text-mode full-screen page):
46
+ * its own {@link handleInput} closes it, so the hint names that key.
47
+ */
48
+ holdFocus(): void;
49
+ /**
50
+ * Text mode: cap the box to {@link ReportPanelOptions.maxRows}, scrolling a
51
+ * taller body. The cap is a hard limit: when a resize leaves fewer rows than
52
+ * the box's chrome needs, its bottom (the hint and closing border) is cut
53
+ * rather than spilling over the editor.
54
+ */
55
+ render(width: number): readonly string[];
56
+ /** Text mode: rows the whole box takes at `width` when nothing caps it. */
57
+ heightAt(width: number): number;
58
+ /** The sheet body (the overlay is the frame, and its body the scroller): the report, then Close (Esc). */
59
+ describe(): NativeNode;
60
+ invalidate(): void;
61
+ /**
62
+ * Focused (the native sheet, or the text-mode full-screen page): Esc closes;
63
+ * the arrow, page, Home and End keys and the wheel scroll the body.
64
+ */
65
+ handleInput(data: string): void;
66
+ /** Close runs what Esc runs. */
67
+ handleNativeEvent(event: NativeUiEvent): void;
68
+ }
@@ -1,4 +1,4 @@
1
- import type { Effort } from "@oh-my-pi/pi-ai";
1
+ import { type ConfiguredThinkingLevel } from "../thinking.js";
2
2
  import { SelectList, type SgrMouseEvent } from "../index.js";
3
3
  import { OverlayPanel } from "../chrome/overlay-box.js";
4
4
  import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
@@ -7,7 +7,7 @@ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.
7
7
  */
8
8
  export declare class ThinkingSelectorComponent extends OverlayPanel {
9
9
  #private;
10
- constructor(currentLevel: Effort, availableLevels: Effort[], onSelect: (level: Effort) => void, onCancel: () => void);
10
+ constructor(currentLevel: ConfiguredThinkingLevel | undefined, availableLevels: ConfiguredThinkingLevel[], onSelect: (level: ConfiguredThinkingLevel) => void, onCancel: () => void);
11
11
  describe(cx: DescribeContext): NativeNode | null;
12
12
  /** Picker pointer events drive the list exactly as its keys do. */
13
13
  handleNativeEvent(event: NativeUiEvent): void;
@@ -1,4 +1,3 @@
1
- import type { LspServerInfo, RecentSession } from "./welcome.js";
2
1
  import type { ComposerPreferences, ComposerStatusCache } from "./composer.js";
3
2
  import type { SymbolPreset } from "../theme/theme.js";
4
3
  /** Theme inputs cached from the last resolved settings load for stable prepaint colors. */
@@ -8,19 +7,10 @@ export interface ComposerThemePreferences {
8
7
  readonly darkTheme?: string;
9
8
  readonly lightTheme?: string;
10
9
  }
11
- /** Last authoritative model labels shown in the welcome component. */
12
- export interface ComposerWelcomeCache {
13
- readonly modelName: string;
14
- readonly providerName: string;
15
- }
16
10
  /** Speculative composer state read before the settings/session graph is available. */
17
11
  export interface ComposerStartupCache {
18
12
  readonly preferences?: ComposerPreferences;
19
13
  readonly theme?: ComposerThemePreferences;
20
- readonly welcome?: ComposerWelcomeCache;
21
- readonly recentSessions: RecentSession[];
22
- /** `null` when the last run had LSP disabled. */
23
- readonly lspServers: LspServerInfo[] | null;
24
14
  readonly status?: ComposerStatusCache;
25
15
  }
26
16
  /**
@@ -43,12 +33,6 @@ export declare class ComposerCache {
43
33
  read(cwd: string): ComposerStartupCache;
44
34
  /** Resolved theme and composer settings for the next prepaint. */
45
35
  writeUi(cwd: string, preferences: ComposerPreferences, theme: ComposerThemePreferences): void;
46
- /** Authoritative model/provider labels for the next welcome prepaint. */
47
- writeWelcome(cwd: string, welcome: ComposerWelcomeCache): void;
48
- /** The latest recent-session rows (first four). */
49
- writeRecentSessions(cwd: string, sessions: readonly RecentSession[]): void;
50
- /** The latest detected project LSP rows; `null` records that LSP is disabled. */
51
- writeLspServers(cwd: string, servers: readonly LspServerInfo[] | null): void;
52
36
  /** Status-bar inputs for the next prepaint's startup status line. */
53
37
  writeStatus(cwd: string, status: ComposerStatusCache): void;
54
38
  close(): void;
@@ -6,7 +6,7 @@ import { type Component, type ResizeScrollbackMode, type TerminalFramePlan, type
6
6
  import type { NativeSurface, NativeSurfaceProvider } from "../native/node.js";
7
7
  import { CustomEditor } from "./custom-editor.js";
8
8
  import type { WordCompletionMethod } from "./word-completion.js";
9
- import { type LspServerInfo, type RecentSession, WelcomeComponent } from "./welcome.js";
9
+ import { WelcomeComponent } from "./welcome.js";
10
10
  /** Live settings that affect the composer before and after session adoption. */
11
11
  export interface ComposerPreferences {
12
12
  readonly quiet: boolean;
@@ -25,11 +25,6 @@ export declare const COMPOSER_DEFAULTS: ComposerPreferences;
25
25
  /** Welcome data that can be supplied initially or patched as startup resolves it. */
26
26
  export interface ComposerWelcomeUpdate {
27
27
  readonly version?: string;
28
- readonly modelName?: string;
29
- readonly providerName?: string;
30
- readonly recentSessions?: readonly RecentSession[];
31
- /** Detected project servers; `null` means LSP is disabled and hides the welcome section. */
32
- readonly lspServers?: readonly LspServerInfo[] | null;
33
28
  }
34
29
  /**
35
30
  * Status-bar inputs persisted by the last session. The first frame renders
@@ -122,6 +117,21 @@ export declare class Composer implements TerminalFrameProvider, NativeSurfacePro
122
117
  #private;
123
118
  readonly ui: TUI;
124
119
  constructor(options?: ComposerOptions);
120
+ /**
121
+ * Rows the below-transcript chrome under `root` (editor, status line, …)
122
+ * took in the last frame, so a root that grows upward can cap itself to
123
+ * the screen rows left above them; `undefined` before `root` was laid out.
124
+ */
125
+ rowsBelow(root: Component): number | undefined;
126
+ /**
127
+ * Keep the input on the bottom row while the live rows cannot fill the
128
+ * screen, as after an inline decision panel closes. A tall block that just
129
+ * left the chrome above the editor (a command report) may have scrolled
130
+ * rows into native history that cannot be pulled back; without the pin the
131
+ * editor would jump up to where the shorter frame now ends. The pin lifts
132
+ * once live rows fill the screen again.
133
+ */
134
+ pinInputToBottom(): void;
125
135
  /** Compose the bounded mutable viewport and the next ordered history append. */
126
136
  renderFrame(viewport: ViewportSize): TerminalFramePlan;
127
137
  /**
@@ -164,7 +174,7 @@ export declare class Composer implements TerminalFrameProvider, NativeSurfacePro
164
174
  enableInput(): void;
165
175
  /** Apply settings changes without replacing the editor or welcome component. */
166
176
  setPreferences(update: Partial<ComposerPreferences>): void;
167
- /** Patch welcome data in place as model, session, and project discovery complete. */
177
+ /** Patch welcome data in place as version, session, and project discovery complete. */
168
178
  updateWelcome(update: ComposerWelcomeUpdate): void;
169
179
  /** Replace optional header content around the stable welcome scene. */
170
180
  setHeaderExtras(before: readonly Component[], after: readonly Component[]): void;
@@ -237,7 +237,8 @@ export declare class CustomEditor extends Editor {
237
237
  * Clicks on the composer's controls take the same paths as their keys: ⇧⇥,
238
238
  * ⏎ and Esc; the viewing header's links (`focus:<id>`) go to the host,
239
239
  * the status facts' clicks (`status.*`) to their source. Selection edits
240
- * go to the buffer.
240
+ * go to the buffer; `send` submits its own prompt after saving the old draft
241
+ * for recall and waiting for in-flight clipboard work.
241
242
  */
242
243
  handleNativeEvent(event: NativeUiEvent): void;
243
244
  onEscape?: () => void;
@@ -1,58 +1,36 @@
1
- import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
1
+ import type { DescribeContext, NativeNode } from "../native/node.js";
2
2
  import type { Component } from "../tui.js";
3
- /**
4
- * Fixed number of session rows in the welcome box so its height stays stable
5
- * across recent-session updates.
6
- */
7
- export declare const WELCOME_SESSION_SLOTS = 4;
8
- /**
9
- * Fixed number of LSP-server rows, for the same reason. Overflow is sliced so
10
- * the box height is constant regardless of how many servers a project has.
11
- */
12
- export declare const WELCOME_LSP_SLOTS = 4;
13
3
  /** Pick a tip from `tips`, biased toward "[NEW]" tips by {@link NEW_TIP_WEIGHT};
14
4
  * `r` is a uniform sample in [0, 1). Returns "" when `tips` is empty.
15
5
  * Exported for tests. */
16
6
  export declare function pickWeightedTip(tips: readonly string[], r: number): string;
17
- export declare function renderWelcomeTip(tip: string, boxWidth: number, phase?: number): string[];
18
- export interface RecentSession {
19
- name: string;
20
- timeAgo: string;
21
- /** Session file; a native click on the row resumes it. */
22
- path?: string;
23
- }
24
- export interface LspServerInfo {
25
- name: string;
26
- status: "ready" | "error" | "connecting" | "available";
27
- fileTypes: string[];
28
- }
29
7
  /**
30
- * Premium welcome screen with block-based OMP logo and two-column layout.
8
+ * The welcome tip as lines of at most `width` columns: `Tip:` and the body
9
+ * wrapped together, with no indent, so the banner can center each line.
10
+ * `[]` when `width` leaves no room for a useful line.
11
+ */
12
+ export declare function renderWelcomeTip(tip: string, width: number, phase?: number): string[];
13
+ /**
14
+ * The session's welcome banner. In a terminal: the gradient logo beside the
15
+ * `omp` wordmark with the version under it (the logo alone when the lockup does
16
+ * not fit) and the tip of the session (dropped below {@link TIP_MIN_COLUMNS}
17
+ * columns). Natively: a card with the same logo, wordmark, version and tip
18
+ * ({@link WelcomeComponent.describe}).
31
19
  */
32
20
  export declare class WelcomeComponent implements Component {
33
21
  #private;
34
22
  private version;
35
- private modelName;
36
- private providerName;
37
- private recentSessions;
38
- /** Detected project servers; `null` means LSP is disabled and hides the section. */
39
- private lspServers;
40
- constructor(version: string, modelName: string, providerName: string, recentSessions?: RecentSession[],
41
- /** Detected project servers; `null` means LSP is disabled and hides the section. */
42
- lspServers?: LspServerInfo[] | null);
23
+ constructor(version: string);
43
24
  get tip(): string | undefined;
44
25
  invalidate(): void;
45
26
  /**
46
- * A `card` (`omp.welcome`) titled with the app version. The brand column
47
- * (`omp.welcome.brand`: greeting and the terminal's builtin `omp` mark, which
48
- * it animates) sits beside the info column (`omp.welcome.info`: prompt-sigil
49
- * keycaps, LSP servers, recent sessions); the tip of the session closes the card. Roles
50
- * carry the look (gradient logo, type scale, column hairline); a "[NEW]" tip
27
+ * A `card` (`omp.welcome`) mirroring the terminal banner: the lockup
28
+ * (`omp.welcome.lockup`: the terminal's builtin `omp` mark, which it animates,
29
+ * beside the wordmark with the version under it) and the tip of the session.
30
+ * Roles carry the look (gradient logo, type scale); a "[NEW]" tip
51
31
  * carries a terminal-clocked shimmering tag.
52
32
  */
53
33
  describe(_cx: DescribeContext): NativeNode;
54
- /** A click on a recent session resumes it. */
55
- handleNativeEvent(event: NativeUiEvent): void;
56
34
  /** The intro keeps the welcome block mutable; settling lets it retire to history. */
57
35
  isTranscriptBlockFinalized(): boolean;
58
36
  /**
@@ -71,9 +49,6 @@ export declare class WelcomeComponent implements Component {
71
49
  stopIntro(): void;
72
50
  /** Update the version embedded in the welcome border title. */
73
51
  setVersion(version: string): void;
74
- setModel(modelName: string, providerName: string): void;
75
- setRecentSessions(sessions: RecentSession[]): void;
76
- setLspServers(servers: LspServerInfo[] | null): void;
77
52
  render(termWidth: number): readonly string[];
78
53
  }
79
54
  /** Block-grid brand mark shared by the welcome and setup surfaces. */
@@ -3,6 +3,7 @@ import type { CompactionSettings } from "@oh-my-pi/pi-agent-core/compaction";
3
3
  import type { Tool as AiTool, Model } from "@oh-my-pi/pi-ai";
4
4
  import type { Theme } from "../theme/index.js";
5
5
  import { Container } from "../tui.js";
6
+ import type { TspText } from "@oh-my-pi/pi-wire";
6
7
  import type { DescribeContext, NativeNode } from "../native/node.js";
7
8
  interface ContextSkill {
8
9
  readonly name: string;
@@ -154,6 +155,8 @@ export declare function computeNonMessageBreakdown(session: NonMessageTokenSourc
154
155
  * session and model.
155
156
  */
156
157
  export declare function computeContextBreakdown(session: ContextUsageSession, options: ContextUsageOptions): ContextBreakdown;
158
+ /** The `/context` title: the model and its window once a model is selected. */
159
+ export declare function contextUsageHead(breakdown: ContextBreakdown): TspText;
157
160
  /**
158
161
  * Native context-usage panel for terminals without `meter`: the cell grid as
159
162
  * unwrapped styled rows beside the legend. The terminal places the legend
@@ -161,15 +164,14 @@ export declare function computeContextBreakdown(session: ContextUsageSession, op
161
164
  */
162
165
  export declare function describeContextUsage(breakdown: ContextBreakdown): NativeNode;
163
166
  /**
164
- * The `/context` transcript block: ANSI renders the titled cell grid between
165
- * rules; natively it is one frame, drawn with `meter`s where the terminal
166
- * has them and as the glyph grid otherwise.
167
+ * The `/context` report body, without a frame or title of its own (the panel
168
+ * showing it is titled {@link contextUsageHead}): ANSI renders the cell grid
169
+ * beside the legend; natively it is drawn with `meter`s where the terminal has
170
+ * them and as the glyph grid otherwise.
167
171
  */
168
172
  export declare class ContextUsageView extends Container {
169
173
  #private;
170
174
  constructor(breakdown: ContextBreakdown, theme: Theme);
171
- /** Replace the shown breakdown in place, refreshing both the ANSI and native views. */
172
- setBreakdown(breakdown: ContextBreakdown): void;
173
175
  describe(cx: DescribeContext): NativeNode;
174
176
  }
175
177
  /**
@@ -11,7 +11,7 @@ export declare enum NotifyProtocol {
11
11
  Osc99 = "\u001B]99;;",
12
12
  Osc9 = "\u001B]9;"
13
13
  }
14
- export type TerminalId = "kitty" | "ghostty" | "wezterm" | "iterm2" | "vscode" | "alacritty" | "warp" | "orca" | "otty" | "rio" | "tern" | "base" | "trueColor";
14
+ export type TerminalId = "kitty" | "ghostty" | "wezterm" | "iterm2" | "vscode" | "alacritty" | "warp" | "orca" | "otty" | "rio" | "tern" | "monstar" | "base" | "trueColor";
15
15
  /** Terminal capability details used for rendering and protocol selection. */
16
16
  export declare class TerminalInfo {
17
17
  readonly id: TerminalId;
@@ -1,4 +1,5 @@
1
1
  import { type TspHello } from "./native/encode.js";
2
+ export { writeTerminalSequence, writeThroughActiveTerminal } from "./active-terminal.js";
2
3
  /**
3
4
  * Split `data` into chunks whose encoded UTF-8 byte length is no greater than
4
5
  * `maxChunkBytes`, preferring a line boundary (`\n`) as the cut point so
@@ -69,16 +70,6 @@ export declare class StdoutStallWatchdog {
69
70
  }
70
71
  /** Record alternate-screen state (called by the TUI on `?1049h`/`?1049l` writes). */
71
72
  export declare function setAltScreenActive(active: boolean): void;
72
- /**
73
- * Route an out-of-band escape sequence (e.g. an OSC title update) through the
74
- * active terminal's output path. While a TUI owns stdout, frame paints go
75
- * through the off-thread write pump and can split across multiple write(2)
76
- * calls; a direct main-thread `process.stdout.write` can land between two of
77
- * them — mid escape sequence — and the host terminal then prints the payload
78
- * as literal text at the cursor position. Returns false when no terminal has
79
- * started, in which case the caller owns stdout and may write directly.
80
- */
81
- export declare function writeThroughActiveTerminal(data: string): boolean;
82
73
  /**
83
74
  * Emergency terminal restore - call this from signal/crash handlers
84
75
  * Resets terminal state without requiring access to the ProcessTerminal instance
@@ -4,7 +4,7 @@ import { ThinkingLevel } from "@oh-my-pi/pi-agent-core/thinking";
4
4
  import { Effort } from "@oh-my-pi/pi-catalog/effort";
5
5
  import type { Model } from "@oh-my-pi/pi-catalog/types";
6
6
  /** Thinking selectors accepted by CLI inputs, in display order. */
7
- export declare const CLI_THINKING_LEVELS: readonly string[];
7
+ export declare const CLI_THINKING_LEVELS: readonly ConfiguredThinkingLevel[];
8
8
  /**
9
9
  * Metadata used to render thinking selector values in the coding-agent UI.
10
10
  */
@@ -4,8 +4,13 @@ import { type OutputMeta } from "./output-meta.js";
4
4
  import type { NativeToolView, RenderResultContextOptions, RenderResultOptions } from "./renderer.js";
5
5
  /** Default collapsed shell output preview height. */
6
6
  export declare const BASH_DEFAULT_PREVIEW_LINES = 10;
7
- /** LLM-facing footer appended when a tool call becomes a background job. */
8
- export declare function formatBackgroundNotice(jobId: string): string;
7
+ /**
8
+ * LLM-facing footer appended when a tool call becomes a background job. It states the job's kill
9
+ * deadline (`timeoutSec`, `undefined` when disabled) so the model knows the job will die at it before
10
+ * it waits on the result. The deadline counts the job's whole run time, not time left from now: an
11
+ * auto-backgrounded call has already spent its foreground wait.
12
+ */
13
+ export declare function formatBackgroundNotice(jobId: string, timeoutSec: number | undefined): string;
9
14
  /** Shell execution metadata used by transcript rendering. */
10
15
  export interface BashToolDetails {
11
16
  meta?: OutputMeta;