@oh-my-pi/pi-tui 18.3.0 → 18.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/THIRD-PARTY-NOTICES.txt +2 -2
- package/dist/types/chat/read-tool-group.d.ts +3 -3
- package/dist/types/chat/user-message.d.ts +4 -1
- package/dist/types/components/editor.d.ts +0 -2
- package/dist/types/components/input.d.ts +16 -0
- package/dist/types/overlays/btw-history-panel.d.ts +4 -1
- package/dist/types/overlays/rewind-selector.d.ts +4 -2
- package/dist/types/overlays/settings-defs.d.ts +5 -0
- package/dist/types/prompt/composer.d.ts +12 -1
- package/dist/types/prompt/custom-editor.d.ts +5 -26
- package/dist/types/space-hold.d.ts +45 -0
- package/dist/types/status-line/host.d.ts +2 -0
- package/dist/types/tools/cfg-render.d.ts +37 -0
- package/dist/types/tools/cfg-url.d.ts +16 -0
- package/dist/types/tools/find.d.ts +2 -2
- package/dist/types/tools/output-meta.d.ts +2 -0
- package/dist/types/tools/proc-render.d.ts +1 -8
- package/dist/types/tools/read.d.ts +14 -3
- package/dist/types/tools/result-card.d.ts +20 -0
- package/dist/types/tools/url-scheme-host.d.ts +29 -0
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/tools/xdev.d.ts +9 -1
- package/package.json +9 -9
- package/src/chat/chat-transcript-builder.ts +5 -1
- package/src/chat/read-tool-group.ts +8 -9
- package/src/chat/tool-execution.ts +7 -5
- package/src/chat/user-message.ts +16 -6
- package/src/components/editor.ts +2 -4
- package/src/components/input.ts +103 -30
- package/src/components/markdown.ts +18 -6
- package/src/overlays/annotation-overlay.ts +0 -1
- package/src/overlays/btw-history-panel.ts +4 -0
- package/src/overlays/model-hub.ts +18 -6
- package/src/overlays/rewind-selector.ts +186 -12
- package/src/overlays/settings-defs.ts +6 -0
- package/src/overlays/settings-selector.ts +4 -3
- package/src/prompt/composer.ts +83 -56
- package/src/prompt/custom-editor.ts +15 -137
- package/src/prompt/tips.txt +1 -0
- package/src/space-hold.ts +143 -0
- package/src/status-line/component.ts +6 -0
- package/src/status-line/host.ts +2 -0
- package/src/status-line/segments.ts +4 -0
- package/src/tools/cfg-render.ts +117 -0
- package/src/tools/cfg-url.ts +30 -0
- package/src/tools/find.ts +7 -6
- package/src/tools/output-meta.ts +2 -0
- package/src/tools/proc-render.ts +2 -26
- package/src/tools/read.ts +109 -68
- package/src/tools/result-card.ts +36 -0
- package/src/tools/url-scheme-host.ts +42 -0
- package/src/tools/write.ts +109 -66
- package/src/tools/xdev.ts +9 -1
- package/dist/types/chat/read-target.d.ts +0 -4
- package/src/chat/read-target.ts +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.3.1] - 2026-09-25
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Replaced the `CustomEditor` space-hold callbacks and `sttHoldEnabled` option with the `spaceHold.handler` API.
|
|
10
|
+
- Removed `Editor.cursorOverrideWidth`; widths for `cursorOverride` glyphs are now measured automatically.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added push-to-talk dictation to `Input`, with live transcription and `cursorOverride` support.
|
|
15
|
+
- Added visual indicators for live-steered user messages and paginated content in read-tool results.
|
|
16
|
+
- Added transcript support for `cfg://` configuration read and write tool calls.
|
|
17
|
+
- Added an Anthropic slow-mode badge to the status-line model segment, showing the priority state, end time, and remaining request percentage when available.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Updated the settings selector so clearing an input field fully unsets the corresponding setting.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fixed dimmed blockquote styling after inline code spans.
|
|
26
|
+
- Fixed rendering of tool calls and results for top-level extension and MCP tools invoked through `xd://` links.
|
|
27
|
+
- Fixed file links in pending Read and Write cards so they open the correct local targets, including paths in the home directory, archives, and databases.
|
|
28
|
+
|
|
5
29
|
## [18.3.0] - 2026-09-24
|
|
6
30
|
|
|
7
31
|
### Added
|
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -78,8 +78,8 @@ below.
|
|
|
78
78
|
uutils coreutils (https://github.com/uutils/coreutils), MIT
|
|
79
79
|
--------------------------------------------------------------------------------
|
|
80
80
|
Covers: base32, base64, basename, cat, cksum (shared checksum machinery),
|
|
81
|
-
b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm,
|
|
82
|
-
date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nproc, paste,
|
|
81
|
+
b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cp,
|
|
82
|
+
cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nproc, paste,
|
|
83
83
|
printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee, touch, tr,
|
|
84
84
|
truncate, uname, uniq, wc, whoami, yes.
|
|
85
85
|
|
|
@@ -7,9 +7,9 @@ export declare function readArgsHaveTarget(args: unknown): boolean;
|
|
|
7
7
|
/**
|
|
8
8
|
* Whether a read collapses into the compact {@link ReadToolGroupComponent}
|
|
9
9
|
* rather than a full tool execution. Filesystem/external targets always
|
|
10
|
-
* collapse;
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* collapse; registered internal-URL schemes render full so their resolved
|
|
11
|
+
* content is visible, unless their spec declares `compactTranscript`
|
|
12
|
+
* (device listings/docs read better in the compact grouped view).
|
|
13
13
|
*/
|
|
14
14
|
export declare function readArgsCollapseIntoGroup(args: unknown): boolean;
|
|
15
15
|
/**
|
|
@@ -6,6 +6,8 @@ export interface UserBubbleOptions {
|
|
|
6
6
|
imageLinks?: readonly (string | undefined)[];
|
|
7
7
|
/** Agent-attributed input: dim, flat prose. */
|
|
8
8
|
synthetic?: boolean;
|
|
9
|
+
/** Delivered into the response that was streaming; marked `*` at the bubble's top-left. */
|
|
10
|
+
liveSteered?: boolean;
|
|
9
11
|
/** SKILL.md path for a skill chip by name; `undefined` leaves the chip unlinked. */
|
|
10
12
|
skillPath?: (name: string) => string | undefined;
|
|
11
13
|
}
|
|
@@ -19,7 +21,8 @@ export interface UserBubbleOptions {
|
|
|
19
21
|
export declare function userBubbleColor(options?: UserBubbleOptions, tokenRegex?: RegExp): (value: string) => string;
|
|
20
22
|
/**
|
|
21
23
|
* Component that renders a user message. Accepts an agent reaction badge
|
|
22
|
-
* (see {@link ReactionTarget}) drawn right-aligned in the bubble's top padding row
|
|
24
|
+
* (see {@link ReactionTarget}) drawn right-aligned in the bubble's top padding row;
|
|
25
|
+
* a live-steered message carries a `*` marker left-aligned in the same row.
|
|
23
26
|
*/
|
|
24
27
|
export declare class UserMessageComponent extends Container implements ReactionTarget {
|
|
25
28
|
#private;
|
|
@@ -69,8 +69,6 @@ export declare class Editor implements Component, Focusable {
|
|
|
69
69
|
focused: boolean;
|
|
70
70
|
/** When set, replaces the normal cursor glyph at end-of-text with this ANSI-styled string. */
|
|
71
71
|
cursorOverride: string | undefined;
|
|
72
|
-
/** Display width of the cursorOverride glyph (needed because override may contain ANSI escapes). */
|
|
73
|
-
cursorOverrideWidth: number | undefined;
|
|
74
72
|
/** Optional hook that decorates displayed user text after source-text layout.
|
|
75
73
|
* Width-changing output is allowed on lines without the cursor; it is truncated
|
|
76
74
|
* to the content width rather than reflowed. Cursor glyphs and inline hints are excluded. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SpaceHoldGesture } from "../space-hold.js";
|
|
1
2
|
import { type Component, type Focusable } from "../tui.js";
|
|
2
3
|
/**
|
|
3
4
|
* Input component - single-line text input with horizontal scrolling
|
|
@@ -10,6 +11,10 @@ export declare class Input implements Component, Focusable {
|
|
|
10
11
|
mask: boolean;
|
|
11
12
|
onSubmit?: (value: string) => void;
|
|
12
13
|
onEscape?: () => void;
|
|
14
|
+
/** Space-bar push-to-talk; set its `handler` to enable it. */
|
|
15
|
+
readonly spaceHold: SpaceHoldGesture;
|
|
16
|
+
/** When set, replaces the cursor glyph at end-of-text with this ANSI-styled string. */
|
|
17
|
+
cursorOverride: string | undefined;
|
|
13
18
|
/** Focusable interface - set by TUI when focus changes */
|
|
14
19
|
focused: boolean;
|
|
15
20
|
getValue(): string;
|
|
@@ -22,6 +27,17 @@ export declare class Input implements Component, Focusable {
|
|
|
22
27
|
/** Apply terminal paste semantics to text from non-bracketed paste transports
|
|
23
28
|
* (e.g. kitty's OSC 5522 enhanced clipboard read). Mirrors `Editor.pasteText`. */
|
|
24
29
|
pasteText(text: string): void;
|
|
30
|
+
/** Programmatically trigger submission (e.g. for voice submit). */
|
|
31
|
+
submit(): void;
|
|
32
|
+
/** Delete up to `count` characters immediately before the cursor. */
|
|
33
|
+
deleteBeforeCursor(count: number): void;
|
|
34
|
+
/** Show or replace a volatile speech-to-text preview at the cursor, outside undo history.
|
|
35
|
+
* Finalize it with {@link commitVolatileText} or drop it with {@link clearVolatileText}. */
|
|
36
|
+
setVolatileText(text: string): void;
|
|
37
|
+
/** Remove the current volatile preview without committing it. */
|
|
38
|
+
clearVolatileText(): void;
|
|
39
|
+
/** Drop any volatile preview, then insert `text` as a single undoable edit. */
|
|
40
|
+
commitVolatileText(text: string): void;
|
|
25
41
|
invalidate(): void;
|
|
26
42
|
render(width: number): readonly string[];
|
|
27
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type Component, type Focusable } from "../index.js";
|
|
1
|
+
import { type Component, type Focusable, Input } from "../index.js";
|
|
2
2
|
import { type BtwHistoryRecord } from "./btw-history.js";
|
|
3
|
+
import type { SpaceHoldHandler } from "../space-hold.js";
|
|
3
4
|
interface BtwHistoryPanelOptions {
|
|
4
5
|
records: readonly BtwHistoryRecord[];
|
|
5
6
|
onClose: () => void;
|
|
@@ -7,6 +8,8 @@ interface BtwHistoryPanelOptions {
|
|
|
7
8
|
onCancel: (record: BtwHistoryRecord) => void;
|
|
8
9
|
canFollowUp?: (record: BtwHistoryRecord) => boolean;
|
|
9
10
|
onFollowUp?: (record: BtwHistoryRecord, question: string, signal: AbortSignal) => Promise<boolean>;
|
|
11
|
+
/** Space-bar push-to-talk for a follow-up composer: dictates into `input` while Space is held. */
|
|
12
|
+
spaceHold?: (input: Input) => SpaceHoldHandler;
|
|
10
13
|
requestRender: () => void;
|
|
11
14
|
getHeight: () => number;
|
|
12
15
|
}
|
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Keys: Up/Down step through rendered items in transcript order (within the
|
|
21
21
|
* active column when a strip is open), Left/Right slide between branch
|
|
22
|
-
* variants at a fork and jump between user turns elsewhere,
|
|
23
|
-
* the
|
|
22
|
+
* variants at a fork and jump between user turns elsewhere, `f` opens a
|
|
23
|
+
* filter (typing narrows the current path to matching items; Esc leaves the
|
|
24
|
+
* filter with the selection kept), Enter rewinds to the outlined item, Esc
|
|
25
|
+
* cancels.
|
|
24
26
|
*/
|
|
25
27
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
26
28
|
import { type Component, type TUI } from "../index.js";
|
|
@@ -57,6 +57,11 @@ export interface SettingsHost {
|
|
|
57
57
|
entries: readonly SettingsDisplayEntry[];
|
|
58
58
|
get(path: string): unknown;
|
|
59
59
|
set(path: string, value: unknown): void;
|
|
60
|
+
/**
|
|
61
|
+
* Removes the value from the global config: a project or other layer, or an environment
|
|
62
|
+
* variable, that configures the setting still applies; otherwise the default does.
|
|
63
|
+
*/
|
|
64
|
+
unset(path: string): void;
|
|
60
65
|
normalizeProviderLimits(value: unknown): Record<string, number>;
|
|
61
66
|
validateProviderLimits(value: unknown): Record<string, number>;
|
|
62
67
|
}
|
|
@@ -56,6 +56,17 @@ export interface ComposerOptions {
|
|
|
56
56
|
readonly exit?: (code: number) => void;
|
|
57
57
|
readonly now?: () => number;
|
|
58
58
|
}
|
|
59
|
+
/** How {@link Composer.setRuntimeChildren} bills below-transcript roots against transcript retirement. */
|
|
60
|
+
export interface RuntimeChildrenOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Below-transcript roots whose growth is momentary (inline dialogs, a tall
|
|
63
|
+
* multi-line editor). They are billed at their smallest height so expansion
|
|
64
|
+
* clips the live tail instead of retiring rows a later shrink could not
|
|
65
|
+
* reclaim (#11007). Every other root is billed at its current height, so
|
|
66
|
+
* settled rows it displaces retire to native scrollback.
|
|
67
|
+
*/
|
|
68
|
+
readonly transient?: readonly Component[];
|
|
69
|
+
}
|
|
59
70
|
/** Controls the first terminal paint for a composer that does not already own the terminal. */
|
|
60
71
|
export interface ComposerStartOptions {
|
|
61
72
|
readonly clearScrollback?: boolean;
|
|
@@ -149,7 +160,7 @@ export declare class Composer implements TerminalFrameProvider {
|
|
|
149
160
|
*/
|
|
150
161
|
setStatusComponent(component: Component): void;
|
|
151
162
|
/** Mount or replace session-aware root children while preserving the header and status hosts. */
|
|
152
|
-
setRuntimeChildren(children: readonly Component[]): void;
|
|
163
|
+
setRuntimeChildren(children: readonly Component[], options?: RuntimeChildrenOptions): void;
|
|
153
164
|
/** Play or replay the welcome intro against the stable header render target. */
|
|
154
165
|
playWelcomeIntro(): void;
|
|
155
166
|
/** Transfer terminal ownership to InteractiveMode without stopping the composer. */
|
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import { Editor, type EditorTextDecorationContext } from "../components/editor.js";
|
|
3
3
|
import { type KeyId } from "../keys.js";
|
|
4
|
+
import { SpaceHoldGesture } from "../space-hold.js";
|
|
4
5
|
import { TUI } from "../tui.js";
|
|
5
6
|
import type { AppKeybinding } from "../app-keybindings.js";
|
|
6
7
|
import { type SpellingFeatures } from "./macos-spelling.js";
|
|
7
8
|
type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.display.reset" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.message.dequeue" | "app.retry" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
|
|
8
|
-
/** Max gap (ms) between two spaces for the later one to count as OS key auto-repeat rather than a
|
|
9
|
-
* deliberate press. OS auto-repeat is fast; a deliberate tap (even a fast one) is slower. */
|
|
10
|
-
export declare const SPACE_REPEAT_MAX_GAP_MS = 120;
|
|
11
|
-
/** Two consecutive inter-space gaps are "mechanical" (machine-driven auto-repeat) when both are
|
|
12
|
-
* within {@link SPACE_REPEAT_MAX_GAP_MS} and differ by no more than this — an absolute jitter floor
|
|
13
|
-
* or, for slower repeat rates, {@link SPACE_REPEAT_JITTER_RATIO} of the smaller gap. OS key-repeat
|
|
14
|
-
* is metronomic; a human smashing the bar is fast but irregular, so its deltas never stay this
|
|
15
|
-
* steady. */
|
|
16
|
-
export declare const SPACE_REPEAT_JITTER_MS = 18;
|
|
17
|
-
export declare const SPACE_REPEAT_JITTER_RATIO = 0.35;
|
|
18
|
-
/** Consecutive mechanical (fast + steady) deltas that confirm the space bar is held and start
|
|
19
|
-
* recording. Needs a sustained metronomic cadence, so jittery smashing and deliberate taps never
|
|
20
|
-
* reach it. */
|
|
21
|
-
export declare const SPACE_HOLD_MECHANICAL_RUN = 2;
|
|
22
|
-
/** Idle gap (ms) after the last repeated space that counts as the space bar being released, ending
|
|
23
|
-
* the push-to-talk recording. Must comfortably exceed the OS key-repeat interval. */
|
|
24
|
-
export declare const SPACE_HOLD_RELEASE_MS = 250;
|
|
25
9
|
/**
|
|
26
10
|
* Extract image-or-other file paths from plain (un-bracketed) clipboard text.
|
|
27
11
|
* Mirrors {@link extractBracketedPastePaths} for terminals/handlers that
|
|
@@ -224,15 +208,10 @@ export declare class CustomEditor extends Editor {
|
|
|
224
208
|
onCapsLock?: () => void;
|
|
225
209
|
/** Called when left-arrow is pressed while the editor is empty (cursor necessarily at start). */
|
|
226
210
|
onLeftAtStart?: () => void;
|
|
227
|
-
/**
|
|
228
|
-
*
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
* spaces) — the push-to-talk STT stop. */
|
|
232
|
-
onSpaceHoldEnd?: () => void;
|
|
233
|
-
/** Gate for the space-hold gesture. Returns false to keep the space bar inserting spaces
|
|
234
|
-
* normally; wired to `stt.enabled` so disabling STT restores plain space behavior. */
|
|
235
|
-
sttHoldEnabled?: () => boolean;
|
|
211
|
+
/** Space-bar push-to-talk; set its `handler` to enable it. It is a text-composition gesture, so it
|
|
212
|
+
* stays out of Vim's Normal/Visual modes (where the space bar is the `l` motion) and away from an
|
|
213
|
+
* open autocomplete menu. */
|
|
214
|
+
readonly spaceHold: SpaceHoldGesture;
|
|
236
215
|
setActionKeys(action: ConfigurableEditorAction, keys: KeyId[]): void;
|
|
237
216
|
/**
|
|
238
217
|
* Register a custom key handler. Extensions use this for shortcuts.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Max gap (ms) between two spaces for the later one to count as OS key auto-repeat rather than a
|
|
2
|
+
* deliberate press. OS auto-repeat is fast; a deliberate tap (even a fast one) is slower. */
|
|
3
|
+
export declare const SPACE_REPEAT_MAX_GAP_MS = 120;
|
|
4
|
+
/** Two consecutive inter-space gaps are "mechanical" (machine-driven auto-repeat) when both are
|
|
5
|
+
* within {@link SPACE_REPEAT_MAX_GAP_MS} and differ by no more than this — an absolute jitter floor
|
|
6
|
+
* or, for slower repeat rates, {@link SPACE_REPEAT_JITTER_RATIO} of the smaller gap. OS key-repeat
|
|
7
|
+
* is metronomic; a human smashing the bar is fast but irregular, so its deltas never stay this
|
|
8
|
+
* steady. */
|
|
9
|
+
export declare const SPACE_REPEAT_JITTER_MS = 18;
|
|
10
|
+
export declare const SPACE_REPEAT_JITTER_RATIO = 0.35;
|
|
11
|
+
/** Consecutive mechanical (fast + steady) deltas that confirm the space bar is held and start
|
|
12
|
+
* recording. Needs a sustained metronomic cadence, so jittery smashing and deliberate taps never
|
|
13
|
+
* reach it. */
|
|
14
|
+
export declare const SPACE_HOLD_MECHANICAL_RUN = 2;
|
|
15
|
+
/** Idle gap (ms) after the last repeated space that counts as the space bar being released, ending
|
|
16
|
+
* the push-to-talk recording. Must comfortably exceed the OS key-repeat interval. */
|
|
17
|
+
export declare const SPACE_HOLD_RELEASE_MS = 250;
|
|
18
|
+
/** What a recognized space-bar hold drives — the push-to-talk start and stop. */
|
|
19
|
+
export interface SpaceHoldHandler {
|
|
20
|
+
/** Gate for the gesture. Returns false to keep the space bar inserting spaces normally, so
|
|
21
|
+
* disabling push-to-talk restores plain space behavior. */
|
|
22
|
+
enabled(): boolean;
|
|
23
|
+
/** A sustained hold was recognized. The optimistically-typed spaces have already been deleted. */
|
|
24
|
+
onStart(): void;
|
|
25
|
+
/** The held space bar was released (an idle gap with no further repeated spaces, or any other key). */
|
|
26
|
+
onEnd(): void;
|
|
27
|
+
}
|
|
28
|
+
/** What the host must do with a keypress after {@link SpaceHoldGesture.process} has seen it:
|
|
29
|
+
* `"pass"` — handle it normally; `"type"` — insert the space now (it is tracked back out if the run
|
|
30
|
+
* turns into a hold); `"swallow"` — drop it, the gesture consumed it. */
|
|
31
|
+
export type SpaceHoldStep = "pass" | "type" | "swallow";
|
|
32
|
+
/** Space-hold push-to-talk state machine. A held space bar emits OS auto-repeat: a *steady* stream
|
|
33
|
+
* of spaces at a fixed fast interval. We watch the inter-space deltas and only recognize a hold once
|
|
34
|
+
* {@link SPACE_HOLD_MECHANICAL_RUN} consecutive deltas are "mechanical" — both auto-repeat-fast and
|
|
35
|
+
* near-identical (see {@link gapsAreMechanical}). Smashing the bar is fast but jittery and deliberate
|
|
36
|
+
* taps are too slow, so neither escalates and both keep typing real spaces; the few spaces typed
|
|
37
|
+
* before a real hold is recognized are tracked back out of the host input. */
|
|
38
|
+
export declare class SpaceHoldGesture {
|
|
39
|
+
#private;
|
|
40
|
+
/** Unset (the default) keeps the space bar typing spaces. */
|
|
41
|
+
handler: SpaceHoldHandler | undefined;
|
|
42
|
+
constructor(deleteTyped: (count: number) => void, allowed?: () => boolean);
|
|
43
|
+
/** Feed one keypress, `isSpace` when it is a plain space bar press. */
|
|
44
|
+
process(isSpace: boolean): SpaceHoldStep;
|
|
45
|
+
}
|
|
@@ -63,6 +63,8 @@ export interface StatusLineSession {
|
|
|
63
63
|
} | undefined;
|
|
64
64
|
autoResolvedThinkingLevel(): string | undefined;
|
|
65
65
|
isFastModeActive(): boolean;
|
|
66
|
+
/** Anthropic usage-limit label (`limit reached · wrapping up · resets 14:30`, `low priority until 14:30 · 62% left`). */
|
|
67
|
+
getAnthropicSlowModeLabel?(): string | undefined;
|
|
66
68
|
getPrewalkState?(): unknown;
|
|
67
69
|
getAsyncJobSnapshot(): {
|
|
68
70
|
running: readonly {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript renderers for `cfg://` settings reads and writes.
|
|
3
|
+
*
|
|
4
|
+
* Reads show the YAML-ish settings listing the model received, highlighted as
|
|
5
|
+
* YAML. Writes show the `previous → value` change, its scope (session or
|
|
6
|
+
* saved), and whether the user approved it.
|
|
7
|
+
*/
|
|
8
|
+
import type { Component } from "../tui.js";
|
|
9
|
+
import { type Theme } from "../theme/theme.js";
|
|
10
|
+
import type { RenderResultOptions } from "./renderer.js";
|
|
11
|
+
import { type CardToolResult } from "./result-card.js";
|
|
12
|
+
/** Summary of a `cfg://` read, attached to read tool details. */
|
|
13
|
+
export interface CfgReadDetails {
|
|
14
|
+
/** Dotted setting path or namespace that was read; empty for the whole tree. */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Settings in the listing. */
|
|
17
|
+
count: number;
|
|
18
|
+
/** Listed settings whose effective value differs from the schema default. */
|
|
19
|
+
modified: number;
|
|
20
|
+
}
|
|
21
|
+
/** How a `cfg://` write ended. */
|
|
22
|
+
export type CfgWriteOutcome = "applied" | "declined" | "unchanged";
|
|
23
|
+
/** A `cfg://` write, attached to write tool details. Values are display-formatted (credentials redacted). */
|
|
24
|
+
export interface CfgWriteDetails {
|
|
25
|
+
path: string;
|
|
26
|
+
/** Persisted to config.yml rather than scoped to the session. */
|
|
27
|
+
save: boolean;
|
|
28
|
+
previous: string;
|
|
29
|
+
value: string;
|
|
30
|
+
outcome: CfgWriteOutcome;
|
|
31
|
+
/** Effective value after saving when a higher-precedence layer still shadows the saved one. */
|
|
32
|
+
effective?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Render `read cfg://…`: pending header, or the highlighted listing with counts. */
|
|
35
|
+
export declare function renderCfgRead(url: string, result: CardToolResult | undefined, details: CfgReadDetails | undefined, options: RenderResultOptions, theme: Theme): Component;
|
|
36
|
+
/** Render `write cfg://…[/save]`: the proposed value while pending, then the approved/declined change. */
|
|
37
|
+
export declare function renderCfgWrite(url: string, content: string | undefined, result: CardToolResult | undefined, details: CfgWriteDetails | undefined, options: RenderResultOptions, theme: Theme): Component;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Canonical prefix for settings URLs. */
|
|
2
|
+
export declare const CFG_URL_PREFIX = "cfg://";
|
|
3
|
+
/** Trailing write segment that persists a `cfg://` change instead of scoping it to the session. */
|
|
4
|
+
export declare const CFG_SAVE_SEGMENT = "save";
|
|
5
|
+
/** Setting addressed by a `cfg://` URL. */
|
|
6
|
+
export interface CfgTarget {
|
|
7
|
+
/** Setting path segments; empty for the root. `/` and `.` both separate segments. */
|
|
8
|
+
segments: string[];
|
|
9
|
+
/** Whether the URL ends in the `/save` suffix, which is removed from {@link segments}. */
|
|
10
|
+
save: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse a `cfg://` URL (`cfg://advisor/enabled`, `cfg://advisor.enabled/save`).
|
|
14
|
+
* Returns `null` for other schemes; query and fragment are ignored.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseCfgUrl(input: string): CfgTarget | null;
|
|
@@ -11,7 +11,7 @@ export interface FindRange {
|
|
|
11
11
|
}
|
|
12
12
|
/** A file whose verified passages cleared the threshold; `ranges` are merged positive spans, strongest first. */
|
|
13
13
|
export interface FindHit {
|
|
14
|
-
/** Display path relative to {@link FindToolDetails.cwd}, or an
|
|
14
|
+
/** Display path relative to {@link FindToolDetails.cwd}, or an internal URL under URL scopes. */
|
|
15
15
|
rel: string;
|
|
16
16
|
/** Filename judgment, when the name batch answered. */
|
|
17
17
|
nameScore?: number;
|
|
@@ -55,7 +55,7 @@ export interface FindToolDetails {
|
|
|
55
55
|
elapsedMs: number;
|
|
56
56
|
/** Session cwd; hit paths are relative to it. */
|
|
57
57
|
cwd: string;
|
|
58
|
-
/** Display form of the searched directory when narrower than cwd. */
|
|
58
|
+
/** Display form of the searched directory or file when narrower than cwd. */
|
|
59
59
|
scopePath?: string;
|
|
60
60
|
meta?: OutputMeta;
|
|
61
61
|
}
|
|
@@ -96,6 +96,8 @@ export interface OutputMeta {
|
|
|
96
96
|
/** Capture failure of this output itself; aggregate reports keep source failures on their entries. */
|
|
97
97
|
artifactError?: OutputArtifactError;
|
|
98
98
|
source?: SourceMeta;
|
|
99
|
+
/** The output is a bounded page of session artifact storage its `source` re-reads with line selectors; spill-to-artifact skips it. */
|
|
100
|
+
pagedSource?: true;
|
|
99
101
|
diagnostics?: DiagnosticMeta;
|
|
100
102
|
limits?: LimitsMeta;
|
|
101
103
|
}
|
|
@@ -3,6 +3,7 @@ import type { Theme } from "../theme/theme.js";
|
|
|
3
3
|
import type { RenderResultOptions } from "./renderer.js";
|
|
4
4
|
import type { AgentActivitySnapshot, CoordinationDetails, JobSnapshot } from "./wait.js";
|
|
5
5
|
import type { DaemonSnapshot } from "./daemon.js";
|
|
6
|
+
import { type CardToolResult as ToolResult } from "./result-card.js";
|
|
6
7
|
export interface ProcReadDetails {
|
|
7
8
|
jobs?: JobSnapshot[];
|
|
8
9
|
agents?: AgentActivitySnapshot[];
|
|
@@ -20,15 +21,7 @@ export type ProcWriteDetails = CoordinationDetails | {
|
|
|
20
21
|
};
|
|
21
22
|
/** Process operation selected by a write URL, independent of its content. */
|
|
22
23
|
export type ProcWriteAction = "stdin" | "mode" | "kill";
|
|
23
|
-
interface ToolResult {
|
|
24
|
-
content: Array<{
|
|
25
|
-
type: string;
|
|
26
|
-
text?: string;
|
|
27
|
-
}>;
|
|
28
|
-
isError?: boolean;
|
|
29
|
-
}
|
|
30
24
|
export declare function renderAgentWrite(to: string, body: string, result: ToolResult | undefined, details: CoordinationDetails | undefined, options: RenderResultOptions, theme: Theme): Component;
|
|
31
25
|
/** Render live and completed process writes with the URL-selected operation. */
|
|
32
26
|
export declare function renderProcWrite(id: string, action: ProcWriteAction, content: string | undefined, result: ToolResult | undefined, details: ProcWriteDetails | undefined, options: RenderResultOptions, theme: Theme): Component;
|
|
33
27
|
export declare function renderProcRead(id: string, result: ToolResult | undefined, details: ProcReadDetails | undefined, options: RenderResultOptions, theme: Theme): Component;
|
|
34
|
-
export {};
|
|
@@ -5,12 +5,15 @@ import type { Theme } from "../theme/theme.js";
|
|
|
5
5
|
import type { OutputMeta } from "./output-meta.js";
|
|
6
6
|
import type { TruncationResult } from "./streaming-output.js";
|
|
7
7
|
import { type ProcReadDetails } from "./proc-render.js";
|
|
8
|
+
import { type CfgReadDetails } from "./cfg-render.js";
|
|
9
|
+
import { type InternalUrlSchemeSpec } from "./url-scheme-host.js";
|
|
8
10
|
/** Read result metadata retains truncation statistics, not a second copy of the body. */
|
|
9
11
|
export type ReadTruncationStats = Omit<TruncationResult, "content">;
|
|
10
12
|
/** Display metadata for file and URL reads. */
|
|
11
13
|
export interface ReadToolDetails {
|
|
12
14
|
kind?: "file" | "url";
|
|
13
15
|
proc?: ProcReadDetails;
|
|
16
|
+
cfg?: CfgReadDetails;
|
|
14
17
|
/** Filesystem hyperlink target resolved by the executing tool. */
|
|
15
18
|
displayTarget?: string;
|
|
16
19
|
truncation?: ReadTruncationStats;
|
|
@@ -71,12 +74,16 @@ export declare function splitPathAndSel(rawPath: string): {
|
|
|
71
74
|
* This function iteratively peels selector-shaped chunks (well-formed plus
|
|
72
75
|
* common malformed shapes like `:-N-M`) so the rest of the read tool can pass a
|
|
73
76
|
* clean URL to the protocol handler and surface selector errors via parseSel
|
|
74
|
-
* instead of as misleading "host invalid" errors from the handler.
|
|
75
|
-
*
|
|
77
|
+
* instead of as misleading "host invalid" errors from the handler.
|
|
78
|
+
*
|
|
79
|
+
* Only schemes whose spec declares `lines` selectors peel; server-defined URIs
|
|
80
|
+
* (`opaque`), selector-free schemes, and unregistered schemes pass through
|
|
81
|
+
* verbatim. `specOf` defaults to the installed scheme host, so nothing peels
|
|
82
|
+
* before a host is installed.
|
|
76
83
|
*
|
|
77
84
|
* Falls back to the input unchanged when nothing matches.
|
|
78
85
|
*/
|
|
79
|
-
export declare function splitInternalUrlSel(rawPath: string): {
|
|
86
|
+
export declare function splitInternalUrlSel(rawPath: string, specOf?: (scheme: string) => InternalUrlSchemeSpec | undefined): {
|
|
80
87
|
path: string;
|
|
81
88
|
sel?: string;
|
|
82
89
|
};
|
|
@@ -91,6 +98,10 @@ export interface ReadRenderArgs {
|
|
|
91
98
|
limit?: number;
|
|
92
99
|
raw?: boolean;
|
|
93
100
|
}
|
|
101
|
+
/** Local file a pending read/write input points at, before the tool resolves it:
|
|
102
|
+
* expands `~` and drops archive-member / SQLite-row selectors so the link opens
|
|
103
|
+
* the containing file. */
|
|
104
|
+
export declare function pendingFileLinkPath(inputPath: string): string;
|
|
94
105
|
/** Absolute fs path the read result actually resolved to, used as the OSC 8 link
|
|
95
106
|
* target when the structured `resolvedPath` isn't set (the common plain-file and
|
|
96
107
|
* image reads only record the path in `meta.source`). URL/internal sources are
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-based status cards shared by the internal-URL renderers (`proc://`,
|
|
3
|
+
* `agent://`, `cfg://`): a header plus sanitized, width-truncated body lines.
|
|
4
|
+
*/
|
|
5
|
+
import type { Component } from "../tui.js";
|
|
6
|
+
import type { RenderResultOptions } from "./renderer.js";
|
|
7
|
+
/** Tool result fields the card renderers read. */
|
|
8
|
+
export interface CardToolResult {
|
|
9
|
+
content: Array<{
|
|
10
|
+
type: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
}>;
|
|
13
|
+
isError?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** First text block of a tool result, or `""`. */
|
|
16
|
+
export declare function firstText(result: CardToolResult): string;
|
|
17
|
+
/** Sanitize one display line: tabs become spaces, carriage returns are dropped. */
|
|
18
|
+
export declare function safe(value: string): string;
|
|
19
|
+
/** Padded card whose lines are sanitized and truncated, re-rendered when the expanded state flips. */
|
|
20
|
+
export declare function card(lines: (width: number, expanded: boolean) => string[], options: RenderResultOptions): Component;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheme facts supplied by the internal URL host. pi-tui cannot import the
|
|
3
|
+
* coding-agent router, so the router installs this bridge when it loads;
|
|
4
|
+
* selector peeling and transcript renderers consult it instead of hardcoding
|
|
5
|
+
* scheme names.
|
|
6
|
+
*/
|
|
7
|
+
/** Renderer-relevant subset of a registered scheme's declared spec. */
|
|
8
|
+
export interface InternalUrlSchemeSpec {
|
|
9
|
+
/** `lines`: a trailing `:<selector>` chain is a read selector; `none`/`opaque`: never peel. */
|
|
10
|
+
readonly selectors: "lines" | "none" | "opaque";
|
|
11
|
+
/** A trailing `:N` with no path after the authority is a port, not a selector (ssh://host:2222). */
|
|
12
|
+
readonly portAuthority?: boolean;
|
|
13
|
+
/** Read cards collapse into the compact read group like plain files instead of expanding. */
|
|
14
|
+
readonly compactTranscript?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Scheme registry capabilities installed by the internal URL host. */
|
|
17
|
+
export interface InternalUrlSchemeHost {
|
|
18
|
+
/** Declared spec of a registered scheme (case-insensitive); undefined when unregistered. */
|
|
19
|
+
spec(scheme: string): InternalUrlSchemeSpec | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Install the scheme registry. Until one is installed, no URL counts as an internal scheme. */
|
|
22
|
+
export declare function setInternalUrlSchemeHost(host: InternalUrlSchemeHost): void;
|
|
23
|
+
/** Declared spec of `scheme`; undefined when it is unregistered or no host is installed. */
|
|
24
|
+
export declare function internalUrlSchemeSpec(scheme: string): InternalUrlSchemeSpec | undefined;
|
|
25
|
+
/** Split a hierarchical `scheme://rest` URL into its lowercased scheme and the text after `://`. */
|
|
26
|
+
export declare function splitUrlScheme(input: string): {
|
|
27
|
+
scheme: string;
|
|
28
|
+
rest: string;
|
|
29
|
+
} | undefined;
|
|
@@ -3,6 +3,7 @@ import type { Component } from "../tui.js";
|
|
|
3
3
|
import { type Theme } from "../theme/theme.js";
|
|
4
4
|
import type { CoordinationDetails } from "./wait.js";
|
|
5
5
|
import { type ProcWriteDetails } from "./proc-render.js";
|
|
6
|
+
import { type CfgWriteDetails } from "./cfg-render.js";
|
|
6
7
|
import type { FileDiagnosticsResult } from "./lsp.js";
|
|
7
8
|
import type { OutputMeta } from "./output-meta.js";
|
|
8
9
|
import type { RenderResultOptions, ToolActivityContext, ToolActivitySummary } from "./renderer.js";
|
|
@@ -20,6 +21,7 @@ export interface WriteToolDetails {
|
|
|
20
21
|
xdev?: XdevRenderDispatch;
|
|
21
22
|
message?: CoordinationDetails;
|
|
22
23
|
proc?: ProcWriteDetails;
|
|
24
|
+
cfg?: CfgWriteDetails;
|
|
23
25
|
}
|
|
24
26
|
interface WriteRenderArgs {
|
|
25
27
|
path?: unknown;
|
|
@@ -9,10 +9,18 @@ export interface XdevMountedRenderer {
|
|
|
9
9
|
renderResult?(...args: Parameters<ToolRenderer["renderResult"]>): unknown;
|
|
10
10
|
mergeCallAndResult?: boolean;
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
12
|
+
/** Tool presentation state supplied by the host's canonical tool map. */
|
|
13
13
|
export interface XdevMountedState {
|
|
14
14
|
readonly mountedNames: ReadonlySet<string>;
|
|
15
15
|
readonly tools: ReadonlyMap<string, XdevMountedRenderer>;
|
|
16
|
+
/**
|
|
17
|
+
* Canonical renderer for a device name, supplied by the host with the same
|
|
18
|
+
* predicate as dispatch (`resolveXdevTool`: mounted devices plus active
|
|
19
|
+
* top-level tools, which the `write` transport also accepts). The TUI keeps
|
|
20
|
+
* no predicate copy of its own — a second copy is what dropped a top-level
|
|
21
|
+
* dispatch to the generic card.
|
|
22
|
+
*/
|
|
23
|
+
readonly resolve?: (name: string) => XdevMountedRenderer | undefined;
|
|
16
24
|
}
|
|
17
25
|
/** Result metadata consumed by delegated device rendering. */
|
|
18
26
|
export interface XdevRenderDispatch {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "18.3.
|
|
4
|
+
"version": "18.3.2",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@oh-my-pi/omptype": "18.3.
|
|
44
|
-
"@oh-my-pi/pi-agent-core": "18.3.
|
|
45
|
-
"@oh-my-pi/pi-ai": "18.3.
|
|
46
|
-
"@oh-my-pi/pi-catalog": "18.3.
|
|
47
|
-
"@oh-my-pi/pi-natives": "18.3.
|
|
48
|
-
"@oh-my-pi/pi-utils": "18.3.
|
|
49
|
-
"@oh-my-pi/pi-wire": "18.3.
|
|
50
|
-
"@oh-my-pi/snapcompact": "18.3.
|
|
43
|
+
"@oh-my-pi/omptype": "18.3.2",
|
|
44
|
+
"@oh-my-pi/pi-agent-core": "18.3.2",
|
|
45
|
+
"@oh-my-pi/pi-ai": "18.3.2",
|
|
46
|
+
"@oh-my-pi/pi-catalog": "18.3.2",
|
|
47
|
+
"@oh-my-pi/pi-natives": "18.3.2",
|
|
48
|
+
"@oh-my-pi/pi-utils": "18.3.2",
|
|
49
|
+
"@oh-my-pi/pi-wire": "18.3.2",
|
|
50
|
+
"@oh-my-pi/snapcompact": "18.3.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -310,7 +310,11 @@ export class ChatTranscriptBuilder {
|
|
|
310
310
|
this.#trackExpandable(collapsed);
|
|
311
311
|
this.container.addChild(collapsed);
|
|
312
312
|
} else {
|
|
313
|
-
this.container.addChild(
|
|
313
|
+
this.container.addChild(
|
|
314
|
+
new UserMessageComponent(userText, {
|
|
315
|
+
liveSteered: message.role === "user" && message.liveSteered === true,
|
|
316
|
+
}),
|
|
317
|
+
);
|
|
314
318
|
}
|
|
315
319
|
}
|
|
316
320
|
break;
|