@oh-my-pi/pi-tui 18.13.1 → 18.13.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +44 -15
  2. package/dist/types/apps/session-picker.d.ts +4 -0
  3. package/dist/types/chat/assistant-message.d.ts +1 -1
  4. package/dist/types/chat/bash-execution.d.ts +2 -0
  5. package/dist/types/chat/display-preferences.d.ts +2 -0
  6. package/dist/types/chat/tool-execution.d.ts +1 -1
  7. package/dist/types/chrome/context-map.d.ts +15 -0
  8. package/dist/types/chrome/context-presentation.d.ts +48 -0
  9. package/dist/types/chrome/context-view-model.d.ts +77 -0
  10. package/dist/types/components/editor.d.ts +2 -0
  11. package/dist/types/overlays/advisor-config.d.ts +6 -0
  12. package/dist/types/overlays/annotation-overlay.d.ts +7 -1
  13. package/dist/types/overlays/annotation-types.d.ts +28 -0
  14. package/dist/types/overlays/ask-dialog.d.ts +9 -2
  15. package/dist/types/overlays/context-viewer-format.d.ts +42 -0
  16. package/dist/types/overlays/context-viewer-overview.d.ts +70 -0
  17. package/dist/types/overlays/context-viewer.d.ts +25 -0
  18. package/dist/types/overlays/hook-input.d.ts +1 -0
  19. package/dist/types/overlays/plan-review-overlay.d.ts +2 -0
  20. package/dist/types/overlays/running-subagent-badge.d.ts +7 -1
  21. package/dist/types/overlays/session-selector.d.ts +13 -2
  22. package/dist/types/status-line/context-usage.d.ts +15 -30
  23. package/dist/types/theme/symbols.d.ts +1 -1
  24. package/dist/types/theme/theme.d.ts +0 -23
  25. package/dist/types/tools/ask.d.ts +2 -0
  26. package/dist/types/tools/bash-interactive.d.ts +6 -0
  27. package/dist/types/tools/fetch.d.ts +1 -0
  28. package/dist/types/tools/github.d.ts +3 -0
  29. package/dist/types/tools/read.d.ts +3 -0
  30. package/dist/types/tools/wait.d.ts +6 -0
  31. package/dist/types/tui.d.ts +6 -1
  32. package/package.json +10 -10
  33. package/src/apps/session-picker.ts +5 -0
  34. package/src/chat/advisor-message.ts +2 -0
  35. package/src/chat/assistant-message.ts +3 -1
  36. package/src/chat/bash-execution.ts +6 -0
  37. package/src/chat/display-preferences.ts +3 -0
  38. package/src/chat/tool-execution.ts +7 -3
  39. package/src/chrome/context-map.ts +62 -0
  40. package/src/chrome/context-presentation.ts +26 -0
  41. package/src/chrome/context-view-model.ts +73 -0
  42. package/src/components/editor.ts +26 -1
  43. package/src/components/markdown.ts +14 -2
  44. package/src/native/backend.ts +2 -64
  45. package/src/overlays/advisor-config.ts +9 -2
  46. package/src/overlays/annotation-overlay.ts +125 -37
  47. package/src/overlays/annotation-types.ts +24 -0
  48. package/src/overlays/ask-dialog.ts +55 -15
  49. package/src/overlays/context-viewer-format.ts +145 -0
  50. package/src/overlays/context-viewer-overview.ts +381 -0
  51. package/src/overlays/context-viewer.ts +728 -0
  52. package/src/overlays/hook-input.ts +2 -0
  53. package/src/overlays/hook-selector.ts +2 -2
  54. package/src/overlays/plan-review-overlay.ts +13 -2
  55. package/src/overlays/running-subagent-badge.ts +12 -1
  56. package/src/overlays/session-selector.ts +195 -26
  57. package/src/overlays/usage-dashboard.ts +5 -12
  58. package/src/prompt/custom-editor.ts +6 -1
  59. package/src/render/output-pane.ts +3 -3
  60. package/src/status-line/context-usage.ts +56 -580
  61. package/src/terminal.ts +24 -2
  62. package/src/theme/symbols.ts +16 -0
  63. package/src/theme/theme.ts +0 -65
  64. package/src/tools/ask.ts +2 -0
  65. package/src/tools/bash-interactive.ts +6 -1
  66. package/src/tools/bash.ts +5 -23
  67. package/src/tools/fetch.ts +1 -0
  68. package/src/tools/github.ts +23 -3
  69. package/src/tools/job-widget.ts +13 -1
  70. package/src/tools/json-tree.ts +1 -1
  71. package/src/tools/read.ts +3 -1
  72. package/src/tools/wait.ts +6 -0
  73. package/src/tui.ts +30 -5
package/CHANGELOG.md CHANGED
@@ -2,12 +2,54 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.13.3] - 2026-10-28
6
+
7
+ ### Added
8
+
9
+ - The resume picker renames the selected session in place: F2 opens a dialog prefilled with the current title, Enter commits, Esc cancels ([#17262](https://github.com/can1357/oh-my-pi/pull/17262) by [@Twilight0](https://github.com/Twilight0))
10
+
11
+ ### Changed
12
+
13
+ - Updated Bun engine requirement to ≥1.4.4
14
+
15
+ ### Fixed
16
+
17
+ - Restored WebP and JPEG images stay visible in Kitty scrollback after resuming a session ([#17220](https://github.com/can1357/oh-my-pi/issues/17220)).
18
+ - Escape in an annotation note no longer discards it: the overlay closes and `getDraft()`/`restoreDraft()` let the host keep and reopen the note; **Discard notes and close** (confirmed by a second press) clears them instead, and code review's actions start on Paste so a stray Enter never sends the LLM review ([#17271](https://github.com/can1357/oh-my-pi/pull/17271) by [@H4vC](https://github.com/H4vC), based on [#17230](https://github.com/can1357/oh-my-pi/pull/17230) by [@Shadorain](https://github.com/Shadorain)).
19
+ - Fixed terminal replies such as Tern's `tsp;e;{"ev":"ack",…}` showing up in the shell prompt after quitting omp; the exit drain now waits for the terminal to answer a final DA1 sentinel
20
+ - Fixed the plan review sheet in Tern squeezing the "continue with" model tiers under a long plan, so the model name overlapped the tier buttons
21
+ - `/usage` in Tern shows when each quota resets as a countdown (`resets in 2h30m`) instead of a clock time; hovering shows the date and time
22
+ - Fixed extension `ui.select` dialogs treating unconfigured `j`/`k` keys as navigation, which could turn a default No into Yes when typing `ok` then Enter ([#17255](https://github.com/can1357/oh-my-pi/pull/17255) by [@SAKANA-MOONLIGHT](https://github.com/SAKANA-MOONLIGHT)).
23
+
24
+ ### Removed
25
+
26
+ - Removed support for the TSP `t` (theme) verb, as surface theme synchronization is no longer required
27
+
28
+ ## [18.13.2] - 2026-10-27
29
+
30
+ ### Added
31
+
32
+ - Added a frame-write listener (`TUI.addFrameWriteListener`) for terminal integrations that need to react to emitted ANSI output, including resize paints ([#17145](https://github.com/can1357/oh-my-pi/issues/17145))
33
+ - `HookInputComponent` (`showHookInput`) now accepts `{ secret: true }` to mask typed characters as bullets (`•`) in input overlays ([#17080](https://github.com/can1357/oh-my-pi/pull/17080) by [@GTanger](https://github.com/GTanger))
34
+ - Added an ANSI and native `/context` viewer with category navigation, content inspection, token-usage and compaction estimates, and keyboard/mouse controls that adapt across Tern and other terminals ([#16160](https://github.com/can1357/oh-my-pi/pull/16160) by [@C-W-Z](https://github.com/C-W-Z)).
35
+
36
+ ### Fixed
37
+
38
+ - Fixed `AskDialogComponent`'s draft input guard holding the keyboard until the draft was cleared; Up/Down (or a pointer action) now release it so the question can be answered with the draft parked, and `syncPresentation` receives the effective blocked state ([#17215](https://github.com/can1357/oh-my-pi/pull/17215) by [@H4vC](https://github.com/H4vC))
39
+ - Fixed the prompt editor's autocomplete popup (e.g. emoji suggestions after `:D`) staying open and following the cursor after Shift/Ctrl/Alt+Enter inserted a newline, so the next Enter submitted past a stale list; newlines and cursor motion (arrows, Home/End, word jumps, character jumps) now close it ([#17215](https://github.com/can1357/oh-my-pi/pull/17215) by [@H4vC](https://github.com/H4vC))
40
+ - Fixed `run_watch` failed-job rows hiding why a job's logs are unavailable; multiline `gh` errors now stay on one row ([#17173](https://github.com/can1357/oh-my-pi/pull/17173) by [@alphastorm](https://github.com/alphastorm))
41
+
42
+ ### Removed
43
+
44
+ - Removed the static context usage report (`ContextUsageView`, `renderContextUsage`, `describeContextUsage`), `contextUsageHead()`, and the `glyph` and `color` fields of `ContextBreakdown` categories; use `ContextViewer` ([#16160](https://github.com/can1357/oh-my-pi/pull/16160) by [@C-W-Z](https://github.com/C-W-Z)).
45
+ - Fixed Markdown tables inside list items disappearing from the terminal transcript ([#17165](https://github.com/can1357/oh-my-pi/issues/17165)).
46
+
5
47
  ## [18.13.1] - 2026-10-27
6
48
 
7
49
  ### Added
8
50
 
9
51
  - ANSI and TSP `/pause` screens show unsettled turns and jobs, hide settled counters, and preserve counts and resume controls on short terminals ([#17073](https://github.com/can1357/oh-my-pi/pull/17073) by [@anatoli-tsinovoy](https://github.com/anatoli-tsinovoy)).
10
- - Added `noteOption` to `ExtensionAskDialogResultItem` and `QuestionResult`: the label of the option an ask note is on (unset for a note on the custom answer) ([#17126](https://github.com/can1357/oh-my-pi/pull/17126) by [@H4vC](https://github.com/H4vC))
52
+ - Added `noteOption` to `ExtensionAskDialogResultItem`, `QuestionResult`, and single-question `AskToolDetails`: the label of the option an ask note is on (unset for a note on the custom answer) ([#17126](https://github.com/can1357/oh-my-pi/pull/17126) by [@H4vC](https://github.com/H4vC))
11
53
 
12
54
  ### Changed
13
55
 
@@ -2456,17 +2498,4 @@
2456
2498
  - Fixed TUI shutdown placing the parent shell prompt one row below short rendered content instead of directly on the next line ([#1620](https://github.com/can1357/oh-my-pi/issues/1620)).
2457
2499
  - Stopped painting inline color swatches for 4-digit hex runs in Markdown rendering. The `#RGBA` CSS form collides with hashline `#TAG` snapshot tags (4 hex digits, e.g. `#6C5E`), which were sprouting spurious RGB swatches in prose and codespans. Only `#RGB`, `#RRGGBB`, and `#RRGGBBAA` qualify now.
2458
2500
 
2459
- ## [15.7.6] - 2026-06-01
2460
-
2461
- ### Fixed
2462
-
2463
- - Fixed native Windows + Windows Terminal freezing the editor on the wrap keystroke, on `/plan`/`/resume`/model-switch/status-line toggles, and on any other offscreen structural mutation until the next prompt submit. The `15.7.5` `#1635` fix routed every viewport-saturating pure-append and structural mutation through `deferredMutation` (a literal no-op) whenever `isNativeViewportAtBottom()` returned `undefined` — which it always does under `WT_SESSION` because the kernel32 probe can't see WT host scrollback. The deferral was only ever meant for the *confirmed-scrolled* case; an unknown viewport now falls back to a non-destructive `viewportRepaint` instead, so the live UI keeps updating without emitting `\x1b[3J` and without yanking a possibly-scrolled reader. Confirmed-scrolled frames (probe returns `false`) still defer.
2464
- - Removed the hard-coded 20-result cap on `@`-prefixed fuzzy file completion in `CombinedAutocompleteProvider.#getFuzzyFileSuggestions`. The dropdown now honors the existing `maxResults: 100` ceiling already configured for `fuzzyFind`, so projects with many files sharing a common stem (e.g. `@controller`, `@test`) surface all relevant matches instead of being silently truncated. ([#1652](https://github.com/can1357/oh-my-pi/issues/1652))
2465
-
2466
- ## [15.7.5] - 2026-06-01
2467
-
2468
- ### Fixed
2469
-
2470
- - Fixed native Windows + Windows Terminal scrollback being yanked to the top when a streaming response triggered a TUI full redraw. Under ConPTY the `kernel32` `GetConsoleScreenBufferInfo` probe answers about the pseudo-console (always at the buffer tail) and not about WT's host scrollback, so `isNativeViewportAtBottom()` falsely returned `true` while the user was scrolled up and the shrink-across-viewport branch issued a destructive `historyRebuild` (`\x1b[2J\x1b[H\x1b[3J`). The probe now short-circuits to `undefined` whenever `WT_SESSION` is set, letting the existing deferred-rebuild path keep streaming-time mutations non-destructive and reconcile native history at the next prompt-submit checkpoint. ([#1635](https://github.com/can1357/oh-my-pi/issues/1635))
2471
-
2472
- Older entries are archived in [packages/tui/CHANGELOG.md@3d45d8557cd7](https://github.com/can1357/oh-my-pi/blob/3d45d8557cd7493221b69c7ed3c6b6a2307f46e7/packages/tui/CHANGELOG.md).
2501
+ Older entries are archived in [packages/tui/CHANGELOG.md@3deb6751027b](https://github.com/can1357/oh-my-pi/blob/3deb6751027b11b10ac14b2a5c07303817276505/packages/tui/CHANGELOG.md).
@@ -4,6 +4,8 @@ export interface SessionPickerHost<T extends SessionSelectorEntry = SessionSelec
4
4
  loadPinnedIds?(): Promise<ReadonlySet<string>>;
5
5
  loadHistoryMatcher?(): SessionHistoryMatcher;
6
6
  deleteSession?(session: T): Promise<boolean>;
7
+ /** Rename the session and resolve with the title as stored, or null when it did not happen. */
8
+ renameSession?(session: T, title: string): Promise<string | null>;
7
9
  loadAllSessions?(): Promise<T[]>;
8
10
  }
9
11
  /** Presentation and capability controls for the standalone session picker. */
@@ -13,6 +15,8 @@ export interface SessionPickerOptions<T extends SessionSelectorEntry = SessionSe
13
15
  scopeLabel?: string | false;
14
16
  showCwd?: boolean;
15
17
  allowDelete?: boolean;
18
+ /** Rename the selected session; resolve with the title as stored, or null when it did not happen. */
19
+ onRename?: (session: T, title: string) => Promise<string | null>;
16
20
  allowGlobalScope?: boolean;
17
21
  historySearch?: boolean;
18
22
  pinnedIds?: ReadonlySet<string>;
@@ -87,7 +87,7 @@ export declare class AssistantMessageComponent extends Container {
87
87
  */
88
88
  setExpanded(expanded: boolean): void;
89
89
  isTranscriptBlockFinalized(): boolean;
90
- /** Whether a figure still waits for the raster of its final source; the transcript holds retirement meanwhile. */
90
+ /** Hold image and figure rendering until the completed block can enter immutable scrollback. */
91
91
  isTranscriptBlockPending(): boolean;
92
92
  render(width: number): readonly string[];
93
93
  /**
@@ -37,6 +37,8 @@ export declare class BashExecutionComponent extends Container {
37
37
  appendOutput(chunk: string): void;
38
38
  /** Switch to PTY rendering and feed raw terminal bytes through the vterm replay. */
39
39
  appendPtyChunk(chunk: string): void;
40
+ /** Bytes a terminal would send for a key event, honoring the command's cursor-key mode; "" for key releases. */
41
+ encodePtyInput(data: string): string;
40
42
  setComplete(exitCode: number | undefined, cancelled: boolean, options?: {
41
43
  output?: string;
42
44
  truncation?: TruncationMeta;
@@ -6,6 +6,8 @@ export interface ChatTranscriptDisplayPreferences {
6
6
  cacheMissMarker: boolean;
7
7
  showTokenUsage: boolean;
8
8
  showTurnTime: boolean;
9
+ /** Max rows a collapsed advisor card shows below its header; 0 = no cap. */
10
+ advisorCollapsedLines: number;
9
11
  }
10
12
  /** Current transcript display preferences. */
11
13
  export declare const chatTranscriptDisplayPreferences: ChatTranscriptDisplayPreferences;
@@ -102,7 +102,7 @@ export declare class ToolExecutionComponent extends Container {
102
102
  * component-scoped so the TUI reuses every other root subtree (issue #4377).
103
103
  */
104
104
  tickSpinner(frame: number): void;
105
- /** Whether the result's figure still waits for its raster; the transcript holds retirement meanwhile. */
105
+ /** Hold visible results until their figures and Kitty images are ready for immutable scrollback. */
106
106
  isTranscriptBlockPending(): boolean;
107
107
  /**
108
108
  * Whether this block is ready to retire as immutable history. Partial
@@ -0,0 +1,15 @@
1
+ /** Pure occupancy calculations for contiguous token segments, independent of themes and renderers. */
2
+ export interface ContextMapSegment<T> {
3
+ readonly id: T;
4
+ readonly tokens: number;
5
+ }
6
+ export interface ContextMapCell<T> {
7
+ readonly id: T;
8
+ readonly full: boolean;
9
+ }
10
+ /**
11
+ * Lays `segments` out in order over a `columns` × `rows` grid representing `windowTokens`; each cell takes the
12
+ * segment covering most of it and is `full` at 70% coverage or more. Returns `[]` when the window or grid
13
+ * size is unusable, and omits cells no segment touches.
14
+ */
15
+ export declare function planContextMap<T>(segments: readonly ContextMapSegment<T>[], windowTokens: number, columns: number, rows: number): ContextMapCell<T>[];
@@ -0,0 +1,48 @@
1
+ import type { ContextCategoryId } from "./context-view-model.js";
2
+ export declare const CONTEXT_PRESENTATION: {
3
+ readonly "system-prompt": {
4
+ readonly color: "accent";
5
+ readonly symbol: "context.content";
6
+ };
7
+ readonly skills: {
8
+ readonly color: "success";
9
+ readonly symbol: "context.content";
10
+ };
11
+ readonly "built-in-tools": {
12
+ readonly color: "warning";
13
+ readonly symbol: "context.content";
14
+ };
15
+ readonly "custom-tools": {
16
+ readonly color: "customMessageLabel";
17
+ readonly symbol: "context.content";
18
+ };
19
+ readonly "user-messages": {
20
+ readonly color: "accent";
21
+ readonly symbol: "context.messages";
22
+ };
23
+ readonly "assistant-messages": {
24
+ readonly color: "userMessageText";
25
+ readonly symbol: "context.messages";
26
+ };
27
+ readonly "assistant-thinking": {
28
+ readonly color: "customMessageLabel";
29
+ readonly symbol: "context.content";
30
+ };
31
+ readonly "tool-calls": {
32
+ readonly color: "warning";
33
+ readonly symbol: "context.content";
34
+ };
35
+ readonly "tool-output": {
36
+ readonly color: "muted";
37
+ readonly symbol: "context.messages";
38
+ };
39
+ readonly buffer: {
40
+ readonly color: "warning";
41
+ readonly symbol: "context.buffer";
42
+ };
43
+ readonly free: {
44
+ readonly color: "dim";
45
+ readonly symbol: "context.free";
46
+ };
47
+ };
48
+ export type ContextPresentationId = ContextCategoryId | "buffer" | "free";
@@ -0,0 +1,77 @@
1
+ /** Context snapshot shapes shared by the session snapshot builder and the context viewer. */
2
+ import type { ContextBreakdown } from "../status-line/context-usage.js";
3
+ interface ContextCategoryDescriptor {
4
+ readonly id: string;
5
+ readonly label: string;
6
+ /** Overview row label when the Overview weight differs from the category's content. */
7
+ readonly overviewLabel?: string;
8
+ /** Listed with its weight but never opened. */
9
+ readonly openable?: false;
10
+ }
11
+ /** Context categories in display order. */
12
+ export declare const CONTEXT_CATEGORIES: readonly [{
13
+ readonly id: "system-prompt";
14
+ readonly label: "System Prompt";
15
+ readonly overviewLabel: "System Prompt (excluding Skills)";
16
+ }, {
17
+ readonly id: "skills";
18
+ readonly label: "Skills";
19
+ readonly openable: false;
20
+ }, {
21
+ readonly id: "built-in-tools";
22
+ readonly label: "Built-in Tools";
23
+ }, {
24
+ readonly id: "custom-tools";
25
+ readonly label: "Custom Tools";
26
+ }, {
27
+ readonly id: "user-messages";
28
+ readonly label: "User / Developer Messages";
29
+ }, {
30
+ readonly id: "assistant-messages";
31
+ readonly label: "Assistant Messages";
32
+ }, {
33
+ readonly id: "assistant-thinking";
34
+ readonly label: "Assistant Thinking";
35
+ }, {
36
+ readonly id: "tool-calls";
37
+ readonly label: "Tool Calls";
38
+ }, {
39
+ readonly id: "tool-output";
40
+ readonly label: "Tool Output";
41
+ }];
42
+ export type ContextCategoryId = (typeof CONTEXT_CATEGORIES)[number]["id"];
43
+ /** Descriptor of a category id: its label, optional Overview label, and whether it can be opened. */
44
+ export declare function contextCategoryDescriptor(id: ContextCategoryId): ContextCategoryDescriptor;
45
+ export interface ContextThinkingGroup {
46
+ readonly id: string;
47
+ readonly label: string;
48
+ readonly tokens: number;
49
+ readonly interrupted?: boolean;
50
+ }
51
+ export interface ContextViewEntry {
52
+ readonly id: string;
53
+ readonly label: string;
54
+ readonly text: string;
55
+ /** Aggregation weight for the unscaled replay estimate; shared blocks contribute through their group. */
56
+ readonly tokens: number;
57
+ readonly interrupted?: boolean;
58
+ readonly thinkingGroup?: ContextThinkingGroup;
59
+ readonly path?: string;
60
+ readonly info?: string;
61
+ readonly timestamp?: number;
62
+ readonly callId?: string;
63
+ }
64
+ export interface ContextViewCategory {
65
+ id: ContextCategoryId;
66
+ key?: string;
67
+ label: string;
68
+ /** Overview attribution weight, not reported usage; may differ from the entry sum (e.g. Skills subtraction). */
69
+ tokens: number;
70
+ entries: ContextViewEntry[];
71
+ children?: ContextViewCategory[];
72
+ }
73
+ export interface ContextViewData {
74
+ readonly breakdown: ContextBreakdown;
75
+ readonly categories: readonly ContextViewCategory[];
76
+ }
77
+ export {};
@@ -98,6 +98,8 @@ export declare class Editor implements Component, Focusable {
98
98
  describeDecorations: ((lines: readonly string[]) => readonly TspEditorDecoration[]) | undefined;
99
99
  /** TSP code language of the buffer (`python`, `bash`): the terminal highlights it in the mono face. */
100
100
  describeLanguage: (() => string | undefined) | undefined;
101
+ /** Label the TSP field to disable host-side editing while another input owner handles raw keys. */
102
+ nativeKeyPassthrough: boolean;
101
103
  /**
102
104
  * TSP chrome around the `editor` node (the prompt composer's chips, mode
103
105
  * chip, send/stop): the root role, the children with `input` placed where
@@ -22,8 +22,10 @@ import { type ModelBrowserSource } from "./model-browser.js";
22
22
  import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
23
23
  export declare const ADVISOR_REVIEW_MODES: readonly ["turn", "agent-end"];
24
24
  export declare const ADVISOR_SYNC_BACKLOG_MODES: readonly ["off", "1", "3", "5", "strict"];
25
+ export declare const ADVISOR_SESSION_SCOPES: readonly ["main", "subagent", "all"];
25
26
  export type AdvisorReviewMode = (typeof ADVISOR_REVIEW_MODES)[number];
26
27
  export type AdvisorSyncBacklog = (typeof ADVISOR_SYNC_BACKLOG_MODES)[number];
28
+ export type AdvisorSessionScope = (typeof ADVISOR_SESSION_SCOPES)[number];
27
29
  /** One advisor declared in `WATCHDOG.yml`; its instructions specialize the shared baseline. */
28
30
  export interface AdvisorConfig {
29
31
  name: string;
@@ -39,6 +41,10 @@ export interface AdvisorConfig {
39
41
  reviewMode?: AdvisorReviewMode;
40
42
  reviewInterval?: number;
41
43
  syncBacklog?: AdvisorSyncBacklog;
44
+ /** Which session kinds this advisor attaches to (`main`, `subagent`, or `all`; defaults to `all`). */
45
+ scope?: AdvisorSessionScope;
46
+ /** Whether primary assistant thinking blocks are included in updates sent to this advisor (defaults to `true`). */
47
+ includeReasoning?: boolean;
42
48
  }
43
49
  /** Which level a `WATCHDOG.yml` lives at: the project root or the user agent dir. */
44
50
  export type AdvisorConfigScope = "project" | "user";
@@ -1,7 +1,7 @@
1
1
  import { type Focusable, type TUI } from "../index.js";
2
2
  import { type KeybindingsManager } from "../app-keybindings.js";
3
3
  import { type Theme } from "../theme/theme.js";
4
- import type { CodeReviewAnnotation, CodeReviewOverlayResult, ReviewDiffFile, TextReviewAnnotation, TextReviewOverlayResult, TextReviewSource } from "./annotation-types.js";
4
+ import type { AnnotationOverlayDraft, CodeReviewAnnotation, CodeReviewOverlayResult, ReviewDiffFile, TextReviewAnnotation, TextReviewOverlayResult, TextReviewSource } from "./annotation-types.js";
5
5
  import type { TspSpan } from "@oh-my-pi/pi-wire";
6
6
  import { type NativeNode, type NativeUiEvent } from "../native/node.js";
7
7
  export declare const CONTINUE_CODE_REVIEW_ACTION = "Continue with LLM review";
@@ -20,6 +20,8 @@ export interface CodeReviewOverlayCallbacks extends AnnotationOverlayCallbacks {
20
20
  export interface TextReviewOverlayCallbacks extends AnnotationOverlayCallbacks {
21
21
  onComplete(result: TextReviewOverlayResult | undefined): void;
22
22
  }
23
+ /** Clears every note and closes; the host then has nothing to keep. Needs a second confirm. */
24
+ export declare const DISCARD_ANNOTATIONS_ACTION = "Discard notes and close";
23
25
  /** Splits a text source into the overlay's 1-based annotatable lines. */
24
26
  export declare function splitTextLines(text: string): string[];
25
27
  /** The native sheet: full-pane glass, titled by the review kind with what is under review after it. */
@@ -38,6 +40,10 @@ export declare class AnnotationOverlay implements Focusable {
38
40
  setUseTerminalCursor(useTerminalCursor: boolean): void;
39
41
  invalidate(): void;
40
42
  dispose(): void;
43
+ /** Notes, the unfinished note, and any source edit, in the form {@link restoreDraft} replays. */
44
+ getDraft(): AnnotationOverlayDraft;
45
+ /** Replay a draft taken from this same source; anything anchored outside it is dropped. */
46
+ restoreDraft(draft: AnnotationOverlayDraft): void;
41
47
  getAnnotations(): CodeReviewAnnotation[];
42
48
  getTextAnnotations(): TextReviewAnnotation[];
43
49
  /** Repo-relative path of the diff file under the cursor, if this is a code review. */
@@ -84,3 +84,31 @@ export interface TextReviewOverlayResult {
84
84
  /** Source text after an external-editor edit; absent when the source was not edited. */
85
85
  editedText?: string;
86
86
  }
87
+ export type AnnotationOverlayDraft = {
88
+ kind: "diff";
89
+ annotations: {
90
+ fileIndex: number;
91
+ sourceIndex: number;
92
+ annotation: CodeReviewAnnotation;
93
+ }[];
94
+ editor?: {
95
+ fileIndex: number;
96
+ sourceIndex: number;
97
+ scope: "file" | "line";
98
+ editingAnnotationIndex?: number;
99
+ text: string;
100
+ };
101
+ } | {
102
+ kind: "text";
103
+ annotations: {
104
+ sourceIndex: number;
105
+ annotation: TextReviewAnnotation;
106
+ }[];
107
+ editedText?: string;
108
+ editor?: {
109
+ sourceIndex: number;
110
+ scope: "text" | "line";
111
+ editingAnnotationIndex?: number;
112
+ text: string;
113
+ };
114
+ };
@@ -61,14 +61,21 @@ interface AskDialogCallbacks {
61
61
  /** Prompt that accepts pasted images; without it, prompts use `onPrompt`. */
62
62
  onImagePrompt?(prompt: AskDialogPrompt, prefill: AskDialogPromptValue | undefined): Promise<AskDialogPromptValue | undefined>;
63
63
  }
64
+ /**
65
+ * Routes typing to a composer draft that was in progress when the dialog
66
+ * opened, so in-flight keystrokes never answer by accident. The up/down select
67
+ * keys are the explicit hand-off: they release the guard for the rest of the
68
+ * dialog's life and the draft stays parked (intact) beneath it.
69
+ */
64
70
  interface AskDialogInputGuard {
65
71
  isBlocked(): boolean;
66
72
  handleInput(keyData: string): void;
73
+ /** Shown after the release keys while the guard holds input. */
67
74
  hint: string;
68
75
  /** Mirror the guard's blocked state onto the proxied draft surface each
69
76
  * render, so a draft that owns input shows a visible insertion cursor even
70
- * though this dialog holds TUI focus. */
71
- syncPresentation?(): void;
77
+ * though this dialog holds TUI focus, and drops it once the dialog takes over. */
78
+ syncPresentation?(blocked: boolean): void;
72
79
  }
73
80
  interface AskDialogOptions {
74
81
  timeout?: number;
@@ -0,0 +1,42 @@
1
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
2
+ import type { ContextCategoryId, ContextThinkingGroup, ContextViewEntry } from "../chrome/context-view-model.js";
3
+ /** Normalized newlines, control characters removed, tabs expanded. */
4
+ export declare function safeContent(value: string): string;
5
+ /** {@link safeContent} with embedded home paths shortened, for labels and metadata. */
6
+ export declare function safeText(value: string): string;
7
+ /** {@link safeText} collapsed to one row. */
8
+ export declare function safeLine(value: string): string;
9
+ /** Token label of an entry or group: `—` for a grouped entry, `N/A · Interrupted`, else `N token(s)` (unscaled estimate). */
10
+ export declare function tokenEstimate(item: ContextViewEntry | ContextThinkingGroup): string;
11
+ /** `[label] N tokens` as ANSI. */
12
+ export declare function entryHeaderLine(entry: ContextViewEntry, category: ContextCategoryId): string;
13
+ /** `[label] N tokens` as spans. */
14
+ export declare function entryHeaderSpans(entry: ContextViewEntry, category: ContextCategoryId): TspSpan[];
15
+ /** Heading for a shared thinking group: label plus its token estimate. */
16
+ export declare function groupHeaderLine(group: ContextThinkingGroup, category: ContextCategoryId): string;
17
+ /** Truncation marker under a preview; the selected preview also advertises the open key. */
18
+ export declare function previewHint(selected: boolean): string;
19
+ /**
20
+ * Metadata rows: info and path, call id, timestamp. The full-content view also
21
+ * lists the thinking group, which previews show as a shared heading instead.
22
+ */
23
+ export declare function entryMetadata(entry: ContextViewEntry, options: {
24
+ hour12: boolean | undefined;
25
+ withGroup: boolean;
26
+ }): string[];
27
+ /** Preview row budget for a list of `height` rows: room for the entry heading, hint, and group heading. */
28
+ export declare function previewRows(entry: ContextViewEntry, height: number): number;
29
+ export interface EntryPreviewOptions {
30
+ /** Wrap width of preview rows. */
31
+ readonly width: number;
32
+ /** Maximum preview rows. */
33
+ readonly rows: number;
34
+ /** Viewport width; bounds the source read to `sourceWidth × rows × 2` characters before sanitizing and wrapping. */
35
+ readonly sourceWidth: number;
36
+ readonly hour12: boolean | undefined;
37
+ }
38
+ /** Dim metadata rows, then the indented body, cut to `rows`; `complete` is false when anything was omitted. */
39
+ export declare function entryPreview(entry: ContextViewEntry, options: EntryPreviewOptions): {
40
+ lines: string[];
41
+ complete: boolean;
42
+ };
@@ -0,0 +1,70 @@
1
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
2
+ import type { ContextBreakdown } from "../status-line/context-usage.js";
3
+ import { type ContextMapCell } from "../chrome/context-map.js";
4
+ import { type ContextPresentationId } from "../chrome/context-presentation.js";
5
+ import type { NativeNode } from "../native/node.js";
6
+ import type { ThemeColor } from "../theme/index.js";
7
+ import { type ContextViewCategory, type ContextViewData } from "../chrome/context-view-model.js";
8
+ /** Columns between the map and the legend. */
9
+ export declare const MAP_LEGEND_GAP = 3;
10
+ export interface OverviewRow {
11
+ readonly key: string;
12
+ readonly id: ContextPresentationId;
13
+ readonly label: string;
14
+ /** Attributed usage; undefined when the weights cannot scale current usage. */
15
+ readonly tokens: number | undefined;
16
+ /** Category opened on confirm; undefined rows are listed but not selectable. */
17
+ readonly category?: ContextViewCategory;
18
+ readonly child?: boolean;
19
+ /** Right-aligned token column. */
20
+ readonly tokenColumn: string;
21
+ /** Right-aligned share column, including its leading separator. */
22
+ readonly shareColumn: string;
23
+ }
24
+ export interface MapGeometry {
25
+ readonly columns: number;
26
+ readonly rows: number;
27
+ readonly cellWidth: number;
28
+ readonly gap: string;
29
+ readonly width: number;
30
+ }
31
+ /**
32
+ * Attribute current usage to categories by weight, then each category's share to its children.
33
+ * Attributed values are not entry sums: entries keep their unscaled content/replay estimates.
34
+ * Undefined when the top-level weights cannot scale; unscalable children stay unattributed.
35
+ */
36
+ export declare function allocateUsage(categories: readonly ContextViewCategory[], usage: number): Map<ContextViewCategory, number> | undefined;
37
+ /** Overview row label for a category: its Overview-specific label when the weight differs from its content. */
38
+ export declare function overviewLabel(category: ContextViewCategory): string;
39
+ /** Category and child rows, then buffer and free space, with aligned token and share columns. */
40
+ export declare function buildOverviewRows(data: ContextViewData, allocation: ReadonlyMap<ContextViewCategory, number> | undefined): OverviewRow[];
41
+ /** ANSI legend row: cursor, swatch, label padded to `width`, token and share columns. */
42
+ export declare function legendLine(row: OverviewRow, selected: boolean, width: number): string;
43
+ /** Native legend item; `meterGlyphs` swaps map glyphs for the meter's bar glyphs. */
44
+ export declare function legendItem(row: OverviewRow, selected: boolean, meterGlyphs: boolean, window: number): NativeNode;
45
+ /** Map size beside a legend in a `width` × `height` body; undefined when either would not fit. */
46
+ export declare function mapGeometry(width: number, height: number): MapGeometry | undefined;
47
+ /** Map cells per row, in window order: categories, free space, then buffer. */
48
+ export declare function planMapRows(data: ContextViewData, allocation: ReadonlyMap<ContextViewCategory, number>, geometry: MapGeometry): ContextMapCell<ContextPresentationId>[][];
49
+ /** ANSI map row; partially filled cells are dim. */
50
+ export declare function mapRowLine(cells: readonly ContextMapCell<ContextPresentationId>[], geometry: MapGeometry): string;
51
+ /** Native map row; partially filled cells are dim. */
52
+ export declare function mapRowSpans(cells: readonly ContextMapCell<ContextPresentationId>[], geometry: MapGeometry): TspSpan[];
53
+ /** Snapcompact savings lines of the Overview; empty when no snapcompact setting is on. */
54
+ export declare function contextSnapcompactLines(breakdown: ContextBreakdown): string[];
55
+ interface ContextMeterData extends Pick<ContextBreakdown, "contextWindow" | "usedTokens" | "freeTokens" | "autoCompactBufferTokens" | "thresholdTokens"> {
56
+ categories: readonly {
57
+ label: string;
58
+ tokens: number;
59
+ color: ThemeColor;
60
+ }[];
61
+ }
62
+ /** Shared usage and compaction labels for ANSI and native context views. */
63
+ export declare function contextUsageSummary(breakdown: Pick<ContextBreakdown, "contextWindow" | "usedTokens" | "freeTokens" | "thresholdTokens">): {
64
+ used: string;
65
+ detail: string;
66
+ room: string;
67
+ };
68
+ /** Native usage summary and stacked bar; callers provide the category list. */
69
+ export declare function describeContextMeter(breakdown: ContextMeterData): [NativeNode, NativeNode];
70
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { ContextViewData } from "../chrome/context-view-model.js";
2
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node.js";
3
+ import type { Component } from "../tui.js";
4
+ /**
5
+ * Read-only context snapshot with three states: Overview → category previews → full entry content.
6
+ * Navigation state is shared; `render` (ANSI) and `describe` (native) each draw every state,
7
+ * via `#render<State>` and `#describe<State>` respectively.
8
+ */
9
+ export declare class ContextViewer implements Component {
10
+ #private;
11
+ constructor(data: ContextViewData, options: {
12
+ onClose: () => void;
13
+ requestRender: () => void;
14
+ getRows: () => number;
15
+ });
16
+ invalidate(): void;
17
+ dispose(): void;
18
+ get nativeOverlay(): NonNullable<Component["nativeOverlay"]>;
19
+ /** Capture only handled navigation keys; the focus path consumes other modal input. */
20
+ capturesInput(data: string): boolean;
21
+ handleInput(data: string): void;
22
+ handleNativeEvent(event: NativeUiEvent): void;
23
+ render(width: number): readonly string[];
24
+ describe(cx: DescribeContext): NativeNode;
25
+ }
@@ -8,6 +8,7 @@ export interface HookInputOptions {
8
8
  tui?: TUI;
9
9
  timeout?: number;
10
10
  onTimeout?: () => void;
11
+ secret?: boolean;
11
12
  }
12
13
  export declare class HookInputComponent extends OverlayPanel {
13
14
  #private;
@@ -74,6 +74,8 @@ export interface PlanReviewOverlayOptions {
74
74
  slider?: HookSelectorSlider;
75
75
  /** Display label for the external-editor key, surfaced in the footer help. */
76
76
  externalEditorLabel?: string;
77
+ /** The external editor's name ("Notepad", "nvim") for the native Edit button; `$EDITOR` when unset. */
78
+ externalEditorName?: string;
77
79
  /** Serializable annotations restored into this overlay instance. */
78
80
  annotationState?: PlanReviewAnnotationState;
79
81
  }
@@ -1,6 +1,12 @@
1
- import type { AgentHubRegistry } from "./agent-hub-types.js";
1
+ import { type AgentHubRegistry } from "./agent-hub-types.js";
2
2
  export interface RunningSubagentRegistrySource<T extends AgentHubRegistry = AgentHubRegistry> {
3
3
  agentRegistry: T;
4
4
  }
5
5
  export declare function getRunningSubagentBadgeRegistry<T extends AgentHubRegistry>(collabGuest: RunningSubagentRegistrySource<T> | undefined, localRegistry: T): T;
6
6
  export declare function getRunningSubagentBadgeAgentIds(registry: AgentHubRegistry): string[];
7
+ /**
8
+ * Agents the Agent Hub roster can show (every registry ref but the main
9
+ * session), whatever their status: finished, parked and killed subagents
10
+ * stay inspectable after the last one stops running.
11
+ */
12
+ export declare function getInspectableSubagentCount(registry: AgentHubRegistry): number;
@@ -71,6 +71,7 @@ declare class SessionList<T extends SessionSelectorEntry> implements Component {
71
71
  onExit: () => void;
72
72
  onToggleScope?: () => void;
73
73
  onDeleteRequest?: (session: T) => void;
74
+ onRenameRequest?: (session: T) => void;
74
75
  /** Re-render hook for async list updates (fuzzy scan completion, history merge). */
75
76
  onRequestRender?: () => void;
76
77
  constructor(sessions: T[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher, getTerminalRows?: () => number, pinnedIds?: ReadonlySet<string>, currentSessionPath?: string | (() => string | undefined));
@@ -79,6 +80,8 @@ declare class SessionList<T extends SessionSelectorEntry> implements Component {
79
80
  /** Cancel pending async search work; idempotent, called on every picker exit path. */
80
81
  dispose(): void;
81
82
  removeSession(sessionPath: string): void;
83
+ /** Update a session's title in place and refresh the visible list, keeping the selection. */
84
+ renameSessionTitle(sessionPath: string, title: string): void;
82
85
  /** Resolve a list-local rendered-line index to a filtered-session index. */
83
86
  hitTestSession(line: number): number | undefined;
84
87
  /** Wheel notch: move the selection one step (clamped, no wrap). */
@@ -93,6 +96,8 @@ declare class SessionList<T extends SessionSelectorEntry> implements Component {
93
96
  resumeSelected(): void;
94
97
  /** Delete / Backspace on an empty query: ask the parent to confirm deleting the selected session. */
95
98
  requestDelete(): void;
99
+ /** F2: ask the parent to rename the selected session. */
100
+ requestRename(): void;
96
101
  /** Empty the search query (the empty state's "Clear search"). */
97
102
  clearSearch(): void;
98
103
  get selectedSession(): T | undefined;
@@ -120,6 +125,12 @@ declare class SessionList<T extends SessionSelectorEntry> implements Component {
120
125
  }
121
126
  export interface SessionSelectorOptions<T extends SessionSelectorEntry = SessionSelectorEntry> {
122
127
  onDelete?: (session: T) => Promise<boolean>;
128
+ /**
129
+ * Rename the selected session to a user-supplied title; resolve with the
130
+ * title as stored (the session canonicalizes it) or null when the rename
131
+ * did not happen.
132
+ */
133
+ onRename?: (session: T, title: string) => Promise<string | null>;
123
134
  historyMatcher?: SessionHistoryMatcher;
124
135
  /** Loads sessions across all projects for the all-projects scope toggle (Tab). */
125
136
  loadAllSessions?: () => Promise<T[]>;
@@ -188,8 +199,8 @@ export declare class SessionSelectorComponent<T extends SessionSelectorEntry = S
188
199
  /**
189
200
  * With the `picker` kind: the data-first session picker (§4.7). Otherwise
190
201
  * scope `tabs`, loading/error message, then the search `input` and session
191
- * `list` — or the delete-confirmation dialog in their place, as on the ANSI
192
- * path — and the key-hint footer.
202
+ * `list` — or the delete-confirmation / rename dialog in their place, as on
203
+ * the ANSI path — and the key-hint footer.
193
204
  */
194
205
  describe(cx: DescribeContext): NativeNode;
195
206
  /** Picker events (root keypath); fallback: scope tab → toggle scope, click on a session → resume it, exactly like a mouse click. */