@oh-my-pi/pi-tui 18.2.6 → 18.2.7
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 +19 -0
- package/THIRD-PARTY-NOTICES.txt +0 -37
- package/dist/types/glyph-protocol.d.ts +62 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/overlays/model-browser.d.ts +9 -3
- package/dist/types/prompt/gradient-highlight.d.ts +2 -2
- package/dist/types/prompt/magic-keywords.d.ts +37 -10
- package/dist/types/setup/scenes/glyph.d.ts +6 -1
- package/dist/types/terminal-capabilities.d.ts +8 -0
- package/dist/types/terminal.d.ts +16 -0
- package/dist/types/theme/mermaid-cache.d.ts +2 -2
- package/dist/types/tools/eval.d.ts +5 -4
- package/dist/types/tools/find.d.ts +82 -0
- package/dist/types/tools/web-search.d.ts +4 -0
- package/package.json +9 -9
- package/src/glyph-protocol.ts +143 -0
- package/src/index.ts +2 -0
- package/src/overlays/model-browser.ts +47 -6
- package/src/overlays/model-hub.ts +122 -33
- package/src/prompt/gradient-highlight.ts +3 -3
- package/src/prompt/macos-spelling.ts +7 -1
- package/src/prompt/magic-keywords.ts +103 -21
- package/src/prompt/markdown-prose.ts +2 -2
- package/src/prompt/tips.txt +1 -0
- package/src/setup/scenes/glyph.ts +8 -1
- package/src/terminal-capabilities.ts +12 -0
- package/src/terminal.ts +151 -2
- package/src/theme/glyph-bundle.json +797 -0
- package/src/theme/mermaid-cache.ts +5 -4
- package/src/tools/eval.ts +14 -7
- package/src/tools/find.ts +255 -0
- package/src/tools/hub.ts +2 -0
- package/src/tools/index.ts +2 -0
- package/src/tools/web-search.ts +5 -0
- package/src/tui.ts +7 -0
- package/dist/types/prompt/magic-keyword-boundary.d.ts +0 -9
- package/dist/types/prompt/orchestrate.d.ts +0 -13
- package/dist/types/prompt/ultrathink.d.ts +0 -13
- package/dist/types/prompt/workflow.d.ts +0 -13
- package/src/prompt/magic-keyword-boundary.ts +0 -23
- package/src/prompt/orchestrate.ts +0 -26
- package/src/prompt/ultrathink.ts +0 -26
- package/src/prompt/workflow.ts +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.7] - 2026-09-21
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Removed specialized keyword modules in favor of a centralized registration system
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added `find` tool renderer to display search results with hit ranking and score visualization
|
|
14
|
+
- Supported collapsing/expanding search hit details and range snippets
|
|
15
|
+
- Enabled file hyperlinking for navigation to absolute paths in search results
|
|
16
|
+
- Added streaming progress display for incomplete find tool operations
|
|
17
|
+
- Added Glyph Protocol support for rendering icons without requiring patched fonts
|
|
18
|
+
- Added `setMagicKeywords` for dynamic configuration of highlightable magic keywords
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Prevented magic keywords from triggering spelling autocorrect and underlining
|
|
23
|
+
|
|
5
24
|
## [18.2.5] - 2026-09-17
|
|
6
25
|
|
|
7
26
|
### Added
|
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -335,43 +335,6 @@ This license allows the work and adaptations of it to be shared and used
|
|
|
335
335
|
commercially, as long as it is attributed to Poppy Works. The font is bundled
|
|
336
336
|
here (crates/pi-natives/src/fonts/Silver.ttf) as a CJK/Unicode bitmap fallback.
|
|
337
337
|
|
|
338
|
-
-------------------------------------------------------------------------------
|
|
339
|
-
packages/utils/src/vendor/mermaid-ascii/NOTICE
|
|
340
|
-
|
|
341
|
-
This directory contains an in-house Mermaid-diagram-to-ASCII renderer adapted
|
|
342
|
-
from beautiful-mermaid (https://github.com/lukilabs/beautiful-mermaid), used
|
|
343
|
-
under the MIT License.
|
|
344
|
-
|
|
345
|
-
Copyright (c) 2026 Craft Docs
|
|
346
|
-
|
|
347
|
-
Only the ASCII rendering pipeline is ported (flowchart/state, sequence, class,
|
|
348
|
-
ER, and xychart diagrams); the SVG renderer and its `elkjs` graph-layout
|
|
349
|
-
dependency, the browser entry point, and the SVG theme/style modules were
|
|
350
|
-
dropped. Terminal display width is reimplemented on `Bun.stringWidth`, and
|
|
351
|
-
inline label formatting (HTML tags, markdown emphasis) is reduced to plain text
|
|
352
|
-
for ASCII output. Layout and edge-routing logic is preserved faithfully so
|
|
353
|
-
ASCII output matches the upstream package.
|
|
354
|
-
|
|
355
|
-
MIT License
|
|
356
|
-
|
|
357
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
358
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
359
|
-
in the Software without restriction, including without limitation the rights
|
|
360
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
361
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
362
|
-
furnished to do so, subject to the following conditions:
|
|
363
|
-
|
|
364
|
-
The above copyright notice and this permission notice shall be included in all
|
|
365
|
-
copies or substantial portions of the Software.
|
|
366
|
-
|
|
367
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
368
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
369
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
370
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
371
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
372
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
373
|
-
SOFTWARE.
|
|
374
|
-
|
|
375
338
|
-------------------------------------------------------------------------------
|
|
376
339
|
packages/coding-agent/src/markit/NOTICE
|
|
377
340
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** One bundled outline: base64 simple-glyph record plus its scale policy. */
|
|
2
|
+
export interface GlyphBundleEntry {
|
|
3
|
+
/** Base64 OpenType `glyf` simple-glyph record (§8.2 subset). */
|
|
4
|
+
glyf: string;
|
|
5
|
+
/** Fill the cell edge to edge (`size=stretch`, powerline); otherwise `size=contain`. */
|
|
6
|
+
stretch?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Generated icon bundle: shared design metrics plus outlines keyed by lowercase hex codepoint. */
|
|
9
|
+
export interface GlyphBundle {
|
|
10
|
+
upm: number;
|
|
11
|
+
/** Authored advance width — identical for every glyph of a Mono face. */
|
|
12
|
+
aw: number;
|
|
13
|
+
/** Authored line height (ascender − descender); outlines are lifted so y=0 is the descender line. */
|
|
14
|
+
lh: number;
|
|
15
|
+
glyphs: Record<string, GlyphBundleEntry>;
|
|
16
|
+
}
|
|
17
|
+
export declare const GLYPH_BUNDLE: GlyphBundle;
|
|
18
|
+
/**
|
|
19
|
+
* Codepoint the handshake queries after registration to confirm the bundle
|
|
20
|
+
* was accepted: the omp mark (`icon.omp`), which the status line always shows.
|
|
21
|
+
*/
|
|
22
|
+
export declare const GLYPH_CONFIRMATION_CODEPOINT = 986455;
|
|
23
|
+
/** Terminal reply to any Glyph Protocol verb, decoded from its APC body. */
|
|
24
|
+
export type GlyphProtocolReply = {
|
|
25
|
+
verb: "s";
|
|
26
|
+
formats: string[];
|
|
27
|
+
} | {
|
|
28
|
+
verb: "q";
|
|
29
|
+
cp: number;
|
|
30
|
+
coverage: string[];
|
|
31
|
+
} | {
|
|
32
|
+
verb: "r";
|
|
33
|
+
cp: number;
|
|
34
|
+
status: number;
|
|
35
|
+
reason?: string;
|
|
36
|
+
} | {
|
|
37
|
+
verb: "c";
|
|
38
|
+
status: number;
|
|
39
|
+
reason?: string;
|
|
40
|
+
};
|
|
41
|
+
/** Whether `cp` lies in one of the three Private Use Areas the protocol accepts. */
|
|
42
|
+
export declare function isPrivateUseCodepoint(cp: number): boolean;
|
|
43
|
+
/** `s` verb: doubles as the protocol-detection ping (any reply confirms support). */
|
|
44
|
+
export declare function encodeGlyphSupportQuery(): string;
|
|
45
|
+
/** `q` verb: ask which sources (system font, session glossary) render `cp`. */
|
|
46
|
+
export declare function encodeGlyphCoverageQuery(cp: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* `r` verb for one bundled outline at `cp`. Layout hints follow the bundle's
|
|
49
|
+
* design metrics; `reply=0` suppresses the acknowledgement so bulk startup
|
|
50
|
+
* registration leaves nothing on stdin to drain.
|
|
51
|
+
*/
|
|
52
|
+
export declare function encodeGlyphRegistration(cp: number, entry: GlyphBundleEntry, metrics?: GlyphBundle): string;
|
|
53
|
+
/** Every bundled icon as one contiguous write. */
|
|
54
|
+
export declare function encodeBundledGlyphRegistrations(metrics?: GlyphBundle): string;
|
|
55
|
+
/** Whether `sequence` is a complete Glyph Protocol APC message. */
|
|
56
|
+
export declare function isGlyphProtocolSequence(sequence: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Decode a terminal reply. Returns null for anything that is not a well-formed
|
|
59
|
+
* Glyph Protocol message; unknown keys are ignored per §11 so future
|
|
60
|
+
* parameters never break detection.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseGlyphProtocolReply(sequence: string): GlyphProtocolReply | null;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export type * from "./editor-component.js";
|
|
|
37
37
|
export * from "./fuzzy.js";
|
|
38
38
|
export * from "./keybindings.js";
|
|
39
39
|
export * from "./keys.js";
|
|
40
|
+
export * from "./glyph-protocol.js";
|
|
40
41
|
export * from "./kitty-graphics.js";
|
|
41
42
|
export * from "./latex-block.js";
|
|
42
43
|
export * from "./latex-to-unicode.js";
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { ModelKind } from "@oh-my-pi/pi-catalog/types";
|
|
2
3
|
import type { Component } from "../tui.js";
|
|
3
4
|
import type { SgrMouseEvent } from "../mouse.js";
|
|
4
5
|
import { type ConfiguredThinkingLevel } from "../thinking.js";
|
|
5
6
|
import { type ThemeColor } from "../theme/theme.js";
|
|
6
7
|
/** Canonical display ordering of built-in model roles. */
|
|
7
|
-
export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "commit" | "tiny" | "task" | "advisor";
|
|
8
|
+
export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "commit" | "tiny" | "memory" | "task" | "advisor" | "image" | "web" | "speech" | "dictation" | "judge";
|
|
8
9
|
export declare const MODEL_ROLE_IDS: ModelRole[];
|
|
10
|
+
export declare const CHAT_MODEL_ROLE_IDS: ModelRole[];
|
|
11
|
+
export declare const KIND_ROLE_IDS: ModelRole[];
|
|
9
12
|
/** Measured model performance shown in browser rows. */
|
|
10
13
|
export interface ModelBrowserPerf {
|
|
11
14
|
samples: number;
|
|
@@ -18,6 +21,8 @@ export interface ModelBrowserRoleInfo {
|
|
|
18
21
|
name: string;
|
|
19
22
|
color?: ThemeColor;
|
|
20
23
|
hidden?: boolean;
|
|
24
|
+
section: "chat" | "kind";
|
|
25
|
+
accepts(model: Model): boolean;
|
|
21
26
|
}
|
|
22
27
|
/** Role lookup used for scoped model resolution. */
|
|
23
28
|
export interface ModelRoleLookup {
|
|
@@ -38,13 +43,14 @@ export interface ModelBrowserSource extends ModelRoleLookup {
|
|
|
38
43
|
readonly mruOrder: readonly string[];
|
|
39
44
|
readonly modelPerf: ReadonlyMap<string, ModelBrowserPerf>;
|
|
40
45
|
getRoleInfo(role: string): ModelBrowserRoleInfo;
|
|
46
|
+
defaultRoleChain(role: string): string[];
|
|
41
47
|
resolveRoleValue(value: string | undefined, models: Model[], roleLookup?: ModelRoleLookup): ResolvedModelRoleValue;
|
|
42
48
|
}
|
|
43
49
|
/** Read-only catalog surface consumed by model browsers. */
|
|
44
50
|
export interface ModelBrowserRegistry {
|
|
45
51
|
getError(): unknown;
|
|
46
|
-
getAvailable(): Model[];
|
|
47
|
-
getAll(): Model[];
|
|
52
|
+
getAvailable(kind?: ModelKind | "all"): Model[];
|
|
53
|
+
getAll(kind?: ModelKind | "all"): Model[];
|
|
48
54
|
}
|
|
49
55
|
/** One selectable row. `selector` is a canonical model key or host-specific virtual key. */
|
|
50
56
|
export interface ModelBrowserItem {
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
export type KeywordHighlighter = (text: string, resetTo?: string, phase?: number) => string;
|
|
10
10
|
/** Declarative spec for {@link createGradientHighlighter}. */
|
|
11
11
|
export interface GradientHighlightSpec {
|
|
12
|
-
/**
|
|
13
|
-
probe:
|
|
12
|
+
/** Literal substring whose absence skips the boundary regex on most lines. */
|
|
13
|
+
probe: string;
|
|
14
14
|
/** Global, word-bounded match regex walked by `.replace`. */
|
|
15
15
|
highlight: RegExp;
|
|
16
16
|
/** Number of color stops swept across the gradient. */
|
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
2
|
+
* Magic-keyword engine: standalone prose words the host registers via
|
|
3
|
+
* {@link setMagicKeywords} glow with a per-word gradient in the editor and in
|
|
4
|
+
* sent bubbles, and are exempt from spelling autocorrect. The host (coding-agent
|
|
5
|
+
* `modes/magic-keywords.ts`) owns the word list and the notices each word
|
|
6
|
+
* injects; this module only knows how to find and paint them.
|
|
7
|
+
*/
|
|
8
|
+
/** One registered magic keyword: the prose trigger and its editor gradient. */
|
|
9
|
+
export interface MagicKeywordSpec {
|
|
10
|
+
/** Exact lowercase trigger, matched only as standalone prose. */
|
|
11
|
+
readonly word: string;
|
|
12
|
+
/** HSL hue sweep `[from, to]` in degrees painted across the word; `to` may exceed 360 to wrap through red. */
|
|
13
|
+
readonly hue: readonly [number, number];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Replace the registered keyword set. The host calls this once at startup;
|
|
17
|
+
* until then nothing glows and no word is exempt from autocorrect.
|
|
18
|
+
*/
|
|
19
|
+
export declare function setMagicKeywords(specs: readonly MagicKeywordSpec[]): void;
|
|
20
|
+
/** Whether `word` is exactly a registered magic keyword (used to shield it from spelling autocorrect). */
|
|
21
|
+
export declare function isMagicKeyword(word: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Whether `text` contains `word` as standalone lowercase prose — never inside
|
|
24
|
+
* a code block, inline code span, or XML/HTML section. Pure: does not require
|
|
25
|
+
* `word` to be registered.
|
|
26
|
+
*/
|
|
27
|
+
export declare function containsMagicKeyword(text: string, word: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Gradient-highlight every registered keyword that appears as standalone
|
|
30
|
+
* prose, skipping any occurrence inside a code block, inline code span, or
|
|
31
|
+
* XML/HTML section. Each pass paints one word with its own gradient, so order
|
|
32
|
+
* is irrelevant — earlier passes only inject zero-width SGR escapes (no
|
|
33
|
+
* backticks or angle brackets), which never confuse later passes' markdown
|
|
34
|
+
* masking.
|
|
8
35
|
*
|
|
9
36
|
* `resetTo` is the SGR foreground sequence restored after each painted keyword;
|
|
10
37
|
* pass the surrounding text color when decorating already-colored content (e.g.
|
|
@@ -18,9 +45,9 @@
|
|
|
18
45
|
*/
|
|
19
46
|
export declare function highlightMagicKeywords(text: string, resetTo?: string, phase?: number): string;
|
|
20
47
|
/**
|
|
21
|
-
* Cheap test for "does this text contain any
|
|
22
|
-
* Short-circuits on a substring probe before paying for the
|
|
23
|
-
* prose check, so the common "no keyword in buffer" path is
|
|
24
|
-
* `String#
|
|
48
|
+
* Cheap test for "does this text contain any registered keyword as standalone
|
|
49
|
+
* prose?". Short-circuits on a substring probe before paying for the
|
|
50
|
+
* markdown-aware prose check, so the common "no keyword in buffer" path is one
|
|
51
|
+
* `String#includes` per word. Used by the live editor to gate the shimmer timer.
|
|
25
52
|
*/
|
|
26
53
|
export declare function hasMagicKeyword(text: string): boolean;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { SetupScene } from "./types.js";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Preview and persist the terminal glyph preset. Skipped once the Glyph
|
|
4
|
+
* Protocol handshake confirmed the terminal renders omp's bundled icons: every
|
|
5
|
+
* row renders cleanly there, and the default `unicode` preset already upgrades
|
|
6
|
+
* to nerd at runtime while staying safe on terminals without the protocol.
|
|
7
|
+
*/
|
|
3
8
|
export declare const glyphSetupScene: SetupScene;
|
|
@@ -215,6 +215,12 @@ export interface RuntimeTerminal extends TerminalInfo {
|
|
|
215
215
|
textSizing: boolean;
|
|
216
216
|
/** Whether the terminal implements colon-subparameter styled underlines (curly + colored). */
|
|
217
217
|
styledUnderlines: boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Whether the terminal answered the Glyph Protocol support query with a
|
|
220
|
+
* `glyf`-capable reply and the bundled icons have been registered. Probe-
|
|
221
|
+
* driven: false until {@link ProcessTerminal} resolves it.
|
|
222
|
+
*/
|
|
223
|
+
glyphProtocol: boolean;
|
|
218
224
|
}
|
|
219
225
|
export declare const TERMINAL: RuntimeTerminal;
|
|
220
226
|
/**
|
|
@@ -227,6 +233,8 @@ export declare function setTerminalImageProtocol(imageProtocol: ImageProtocol |
|
|
|
227
233
|
* resolved once at import and force-disabled under the test runtime.
|
|
228
234
|
*/
|
|
229
235
|
export declare function setTerminalDeccara(enabled: boolean): void;
|
|
236
|
+
/** Record the Glyph Protocol probe result (called by ProcessTerminal). */
|
|
237
|
+
export declare function setTerminalGlyphProtocol(supported: boolean): void;
|
|
230
238
|
/** Override screen-to-scrollback clear support for targeted renderer tests. */
|
|
231
239
|
export declare function setTerminalScreenToScrollback(enabled: boolean): void;
|
|
232
240
|
/**
|
package/dist/types/terminal.d.ts
CHANGED
|
@@ -106,6 +106,13 @@ export type TerminalAppearanceRequestToken = number;
|
|
|
106
106
|
* set, 4 permanently reset) when the terminal answered DECRQM.
|
|
107
107
|
*/
|
|
108
108
|
export type PrivateModeReportHandler = (mode: number, supported: boolean, confirmed?: boolean, status?: number) => void;
|
|
109
|
+
/**
|
|
110
|
+
* Fired once when the Glyph Protocol handshake resolves. `supported` is true
|
|
111
|
+
* only after the bundled icons were written and the terminal confirmed (via a
|
|
112
|
+
* `q` coverage query) that a registered codepoint is served from its
|
|
113
|
+
* glossary, so a host can safely repaint — or switch to the nerd preset.
|
|
114
|
+
*/
|
|
115
|
+
export type GlyphProtocolReportHandler = (supported: boolean) => void;
|
|
109
116
|
/**
|
|
110
117
|
* Cursor shapes addressable via DECSCUSR (`CSI <n> SP q`). `"default"` (0) hands the shape back to
|
|
111
118
|
* the terminal's own configuration, which is what teardown restores rather than guessing a shape
|
|
@@ -208,6 +215,14 @@ export interface Terminal {
|
|
|
208
215
|
* `status` is the DECRPM value when the terminal answered DECRQM.
|
|
209
216
|
*/
|
|
210
217
|
onPrivateModeReport?(callback: PrivateModeReportHandler): void;
|
|
218
|
+
/**
|
|
219
|
+
* Register a callback fired once the startup Glyph Protocol handshake
|
|
220
|
+
* resolves (see {@link GlyphProtocolReportHandler}). A subscriber that
|
|
221
|
+
* arrives after the handshake already resolved is called immediately with
|
|
222
|
+
* the stored outcome. Optional so custom Terminals built against older
|
|
223
|
+
* pi-tui versions keep working.
|
|
224
|
+
*/
|
|
225
|
+
onGlyphProtocolReport?(callback: GlyphProtocolReportHandler): void;
|
|
211
226
|
}
|
|
212
227
|
/**
|
|
213
228
|
* True when stdout flows through a ConPTY pseudo-console (native win32, or
|
|
@@ -254,6 +269,7 @@ export declare class ProcessTerminal implements Terminal {
|
|
|
254
269
|
*/
|
|
255
270
|
refreshAppearance(requestToken?: TerminalAppearanceRequestToken): TerminalAppearanceRequestToken | void;
|
|
256
271
|
onPrivateModeReport(callback: PrivateModeReportHandler): void;
|
|
272
|
+
onGlyphProtocolReport(callback: GlyphProtocolReportHandler): void;
|
|
257
273
|
start(onInput: (data: string) => void, onResize: () => void, onDisconnect?: () => void, options?: TerminalStartOptions): void;
|
|
258
274
|
enableInput(): void;
|
|
259
275
|
drainInput(maxMs?: number, idleMs?: number): Promise<void>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MermaidRenderOptions } from "@oh-my-pi/pi-natives";
|
|
2
2
|
/**
|
|
3
3
|
* Options controlling how fenced Mermaid source is resolved to terminal ASCII.
|
|
4
4
|
* Extends the raw render options (theme, color mode, spacing, `useAscii`) with a
|
|
5
5
|
* viewport-fitting hint.
|
|
6
6
|
*/
|
|
7
|
-
export interface MermaidResolveOptions extends
|
|
7
|
+
export interface MermaidResolveOptions extends MermaidRenderOptions {
|
|
8
8
|
/**
|
|
9
9
|
* Maximum display width (terminal columns) the diagram should occupy. A
|
|
10
10
|
* layout that overflows this width is re-rendered in the perpendicular
|
|
@@ -68,10 +68,11 @@ interface EvalRenderContext {
|
|
|
68
68
|
timeout?: number;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* Append or replace a status event. `agent` events are
|
|
72
|
-
* by `id`, so they coalesce in place (preserving
|
|
73
|
-
* op is a discrete action and simply appends.
|
|
74
|
-
* bounded even when a subagent
|
|
71
|
+
* Append or replace a status event. `agent` and `judge_batch` events are
|
|
72
|
+
* progress snapshots keyed by `id`, so they coalesce in place (preserving
|
|
73
|
+
* first-seen order); every other op is a discrete action and simply appends.
|
|
74
|
+
* Keeps the persisted event list bounded even when a subagent or batch emits
|
|
75
|
+
* hundreds of throttled progress ticks.
|
|
75
76
|
*/
|
|
76
77
|
export declare function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEvent): void;
|
|
77
78
|
/** Render eval code cells, structured display output, and progress events. */
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Theme } from "../theme/theme.js";
|
|
2
|
+
import type { Component } from "../tui.js";
|
|
3
|
+
import type { OutputMeta } from "./output-meta.js";
|
|
4
|
+
import type { RenderResultOptions } from "./renderer.js";
|
|
5
|
+
/** A verified line range with its yes-probability and a one-line preview. */
|
|
6
|
+
export interface FindRange {
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
p: number;
|
|
10
|
+
snippet: string;
|
|
11
|
+
}
|
|
12
|
+
/** A file whose verified passages cleared the threshold; `ranges` are merged positive spans, strongest first. */
|
|
13
|
+
export interface FindHit {
|
|
14
|
+
/** Display path relative to {@link FindToolDetails.cwd}. */
|
|
15
|
+
rel: string;
|
|
16
|
+
/** Filename judgment, when the name batch answered. */
|
|
17
|
+
nameScore?: number;
|
|
18
|
+
/** Best verified passage probability. */
|
|
19
|
+
contentScore: number;
|
|
20
|
+
ranges: FindRange[];
|
|
21
|
+
/** Lines of content actually judged, and whether the file held more. */
|
|
22
|
+
linesSeen: number;
|
|
23
|
+
truncated: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Search accounting reported alongside the hits. */
|
|
26
|
+
export interface FindStats {
|
|
27
|
+
/** Eligible files under the root. */
|
|
28
|
+
listed: number;
|
|
29
|
+
requests: number;
|
|
30
|
+
errors: number;
|
|
31
|
+
/** Entries judged by name. */
|
|
32
|
+
judged: number;
|
|
33
|
+
/** Files whose content was read and sent. */
|
|
34
|
+
filesRead: number;
|
|
35
|
+
fileBytes: number;
|
|
36
|
+
inputTokens: number;
|
|
37
|
+
outputTokens: number;
|
|
38
|
+
cost: number;
|
|
39
|
+
apiMs: number;
|
|
40
|
+
windowsJudged: number;
|
|
41
|
+
windowsPruned: number;
|
|
42
|
+
mapCards: number;
|
|
43
|
+
/** Distinct request failures, phase-prefixed. */
|
|
44
|
+
failures: string[];
|
|
45
|
+
}
|
|
46
|
+
/** Display metadata for find tool results. */
|
|
47
|
+
export interface FindToolDetails {
|
|
48
|
+
query: string;
|
|
49
|
+
/** Lexical keywords actually used: derived from the query plus `grep_keywords`. */
|
|
50
|
+
keywords: string[];
|
|
51
|
+
/** Verified-passage probability at or above which a file is a hit. */
|
|
52
|
+
threshold: number;
|
|
53
|
+
hits: FindHit[];
|
|
54
|
+
stats: FindStats;
|
|
55
|
+
elapsedMs: number;
|
|
56
|
+
/** Session cwd; hit paths are relative to it. */
|
|
57
|
+
cwd: string;
|
|
58
|
+
/** Display form of the searched directory when narrower than cwd. */
|
|
59
|
+
scopePath?: string;
|
|
60
|
+
meta?: OutputMeta;
|
|
61
|
+
}
|
|
62
|
+
interface FindRenderArgs {
|
|
63
|
+
query?: string;
|
|
64
|
+
grep_keywords?: string[];
|
|
65
|
+
path?: string;
|
|
66
|
+
}
|
|
67
|
+
/** Render find calls and results in the transcript. */
|
|
68
|
+
export declare const findToolRenderer: {
|
|
69
|
+
renderCall(args: FindRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component;
|
|
70
|
+
renderResult(result: {
|
|
71
|
+
content: Array<{
|
|
72
|
+
type: string;
|
|
73
|
+
text?: string;
|
|
74
|
+
}>;
|
|
75
|
+
details?: FindToolDetails;
|
|
76
|
+
isError?: boolean;
|
|
77
|
+
}, options: RenderResultOptions, uiTheme: Theme, args?: FindRenderArgs): Component;
|
|
78
|
+
mergeCallAndResult: true;
|
|
79
|
+
animatedPendingPreview: true;
|
|
80
|
+
animatedPartialResult: true;
|
|
81
|
+
};
|
|
82
|
+
export {};
|
|
@@ -66,6 +66,10 @@ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
|
|
|
66
66
|
readonly value: "xai";
|
|
67
67
|
readonly label: "xAI";
|
|
68
68
|
readonly description: "Grok web search via xAI Responses API (uses SuperGrok/X Premium+ OAuth via /login xai-oauth, or XAI_API_KEY)";
|
|
69
|
+
}, {
|
|
70
|
+
readonly value: "openrouter";
|
|
71
|
+
readonly label: "OpenRouter";
|
|
72
|
+
readonly description: "OpenRouter plugins-based web search with model-selected grounding";
|
|
69
73
|
}, {
|
|
70
74
|
readonly value: "zai";
|
|
71
75
|
readonly label: "Z.AI";
|
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.2.
|
|
4
|
+
"version": "18.2.7",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Stencil Labs, Inc.",
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@oh-my-pi/omptype": "18.2.
|
|
41
|
-
"@oh-my-pi/pi-agent-core": "18.2.
|
|
42
|
-
"@oh-my-pi/pi-ai": "18.2.
|
|
43
|
-
"@oh-my-pi/pi-catalog": "18.2.
|
|
44
|
-
"@oh-my-pi/pi-natives": "18.2.
|
|
45
|
-
"@oh-my-pi/pi-utils": "18.2.
|
|
46
|
-
"@oh-my-pi/pi-wire": "18.2.
|
|
47
|
-
"@oh-my-pi/snapcompact": "18.2.
|
|
40
|
+
"@oh-my-pi/omptype": "18.2.7",
|
|
41
|
+
"@oh-my-pi/pi-agent-core": "18.2.7",
|
|
42
|
+
"@oh-my-pi/pi-ai": "18.2.7",
|
|
43
|
+
"@oh-my-pi/pi-catalog": "18.2.7",
|
|
44
|
+
"@oh-my-pi/pi-natives": "18.2.7",
|
|
45
|
+
"@oh-my-pi/pi-utils": "18.2.7",
|
|
46
|
+
"@oh-my-pi/pi-wire": "18.2.7",
|
|
47
|
+
"@oh-my-pi/snapcompact": "18.2.7"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glyph Protocol client: ships the TUI's private-use icons to the terminal so
|
|
3
|
+
* the nerd symbol preset renders without a patched font installed.
|
|
4
|
+
*
|
|
5
|
+
* Transport is APC `ESC _ 25a1 ; <verb> [; k=v]* [; payload] ESC \` with four
|
|
6
|
+
* verbs — `s` (support query), `q` (coverage query), `r` (register), `c`
|
|
7
|
+
* (clear). {@link ProcessTerminal} drives the handshake: `s` behind its DA1
|
|
8
|
+
* sentinel at startup; on a `glyf`-capable reply it writes
|
|
9
|
+
* {@link encodeBundledGlyphRegistrations} in one shot followed by a `q` for
|
|
10
|
+
* {@link GLYPH_CONFIRMATION_CODEPOINT}, and a `glossary` answer confirms the
|
|
11
|
+
* bundle landed. Registrations are fire-and-forget (`reply=0`),
|
|
12
|
+
* session-scoped, and confined to the PUA ranges, so they can never restyle
|
|
13
|
+
* real text.
|
|
14
|
+
*
|
|
15
|
+
* Spec: https://github.com/raphamorim/rio/blob/main/specs/glyph-protocol.md
|
|
16
|
+
* The bundle is generated by `scripts/gen-glyphs.ts` (`bun run gen:glyphs`).
|
|
17
|
+
*/
|
|
18
|
+
import bundle from "./theme/glyph-bundle.json" with { type: "json" };
|
|
19
|
+
|
|
20
|
+
/** Protocol identifier: U+25A1 WHITE SQUARE as lowercase hex. */
|
|
21
|
+
const GLYPH_PROTOCOL_ID = "25a1";
|
|
22
|
+
const APC = "\x1b_";
|
|
23
|
+
const ST = "\x1b\\";
|
|
24
|
+
|
|
25
|
+
/** One bundled outline: base64 simple-glyph record plus its scale policy. */
|
|
26
|
+
export interface GlyphBundleEntry {
|
|
27
|
+
/** Base64 OpenType `glyf` simple-glyph record (§8.2 subset). */
|
|
28
|
+
glyf: string;
|
|
29
|
+
/** Fill the cell edge to edge (`size=stretch`, powerline); otherwise `size=contain`. */
|
|
30
|
+
stretch?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Generated icon bundle: shared design metrics plus outlines keyed by lowercase hex codepoint. */
|
|
34
|
+
export interface GlyphBundle {
|
|
35
|
+
upm: number;
|
|
36
|
+
/** Authored advance width — identical for every glyph of a Mono face. */
|
|
37
|
+
aw: number;
|
|
38
|
+
/** Authored line height (ascender − descender); outlines are lifted so y=0 is the descender line. */
|
|
39
|
+
lh: number;
|
|
40
|
+
glyphs: Record<string, GlyphBundleEntry>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const GLYPH_BUNDLE: GlyphBundle = bundle;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Codepoint the handshake queries after registration to confirm the bundle
|
|
47
|
+
* was accepted: the omp mark (`icon.omp`), which the status line always shows.
|
|
48
|
+
*/
|
|
49
|
+
export const GLYPH_CONFIRMATION_CODEPOINT = 0xf0d57;
|
|
50
|
+
|
|
51
|
+
/** Terminal reply to any Glyph Protocol verb, decoded from its APC body. */
|
|
52
|
+
export type GlyphProtocolReply =
|
|
53
|
+
| { verb: "s"; formats: string[] }
|
|
54
|
+
| { verb: "q"; cp: number; coverage: string[] }
|
|
55
|
+
| { verb: "r"; cp: number; status: number; reason?: string }
|
|
56
|
+
| { verb: "c"; status: number; reason?: string };
|
|
57
|
+
|
|
58
|
+
/** Whether `cp` lies in one of the three Private Use Areas the protocol accepts. */
|
|
59
|
+
export function isPrivateUseCodepoint(cp: number): boolean {
|
|
60
|
+
return (cp >= 0xe000 && cp <= 0xf8ff) || (cp >= 0xf0000 && cp <= 0xffffd) || (cp >= 0x100000 && cp <= 0x10fffd);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** `s` verb: doubles as the protocol-detection ping (any reply confirms support). */
|
|
64
|
+
export function encodeGlyphSupportQuery(): string {
|
|
65
|
+
return `${APC}${GLYPH_PROTOCOL_ID};s${ST}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** `q` verb: ask which sources (system font, session glossary) render `cp`. */
|
|
69
|
+
export function encodeGlyphCoverageQuery(cp: number): string {
|
|
70
|
+
return `${APC}${GLYPH_PROTOCOL_ID};q;cp=${cp.toString(16)}${ST}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `r` verb for one bundled outline at `cp`. Layout hints follow the bundle's
|
|
75
|
+
* design metrics; `reply=0` suppresses the acknowledgement so bulk startup
|
|
76
|
+
* registration leaves nothing on stdin to drain.
|
|
77
|
+
*/
|
|
78
|
+
export function encodeGlyphRegistration(
|
|
79
|
+
cp: number,
|
|
80
|
+
entry: GlyphBundleEntry,
|
|
81
|
+
metrics: GlyphBundle = GLYPH_BUNDLE,
|
|
82
|
+
): string {
|
|
83
|
+
if (!isPrivateUseCodepoint(cp))
|
|
84
|
+
throw new RangeError(`U+${cp.toString(16).toUpperCase()} is not a private-use codepoint`);
|
|
85
|
+
const size = entry.stretch ? "stretch" : "contain";
|
|
86
|
+
return `${APC}${GLYPH_PROTOCOL_ID};r;cp=${cp.toString(16)};reply=0;upm=${metrics.upm};aw=${metrics.aw};lh=${metrics.lh};size=${size};${entry.glyf}${ST}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Every bundled icon as one contiguous write. */
|
|
90
|
+
export function encodeBundledGlyphRegistrations(metrics: GlyphBundle = GLYPH_BUNDLE): string {
|
|
91
|
+
let out = "";
|
|
92
|
+
for (const hex in metrics.glyphs) {
|
|
93
|
+
out += encodeGlyphRegistration(Number.parseInt(hex, 16), metrics.glyphs[hex]!, metrics);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Whether `sequence` is a complete Glyph Protocol APC message. */
|
|
99
|
+
export function isGlyphProtocolSequence(sequence: string): boolean {
|
|
100
|
+
return sequence.startsWith(`${APC}${GLYPH_PROTOCOL_ID};`) && sequence.endsWith(ST);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Decode a terminal reply. Returns null for anything that is not a well-formed
|
|
105
|
+
* Glyph Protocol message; unknown keys are ignored per §11 so future
|
|
106
|
+
* parameters never break detection.
|
|
107
|
+
*/
|
|
108
|
+
export function parseGlyphProtocolReply(sequence: string): GlyphProtocolReply | null {
|
|
109
|
+
if (!isGlyphProtocolSequence(sequence)) return null;
|
|
110
|
+
const body = sequence.slice(APC.length + GLYPH_PROTOCOL_ID.length + 1, -ST.length);
|
|
111
|
+
const parts = body.split(";");
|
|
112
|
+
const verb = parts[0];
|
|
113
|
+
const params: Record<string, string> = {};
|
|
114
|
+
for (let i = 1; i < parts.length; i++) {
|
|
115
|
+
const part = parts[i]!;
|
|
116
|
+
const eq = part.indexOf("=");
|
|
117
|
+
if (eq > 0) params[part.slice(0, eq)] = part.slice(eq + 1);
|
|
118
|
+
}
|
|
119
|
+
// Empty list values (`fmt=` / `status=`) mean "none", not one empty name.
|
|
120
|
+
const list = (value: string | undefined): string[] => (value ? value.split(",") : []);
|
|
121
|
+
switch (verb) {
|
|
122
|
+
case "s":
|
|
123
|
+
return { verb, formats: list(params.fmt) };
|
|
124
|
+
case "q": {
|
|
125
|
+
const cp = Number.parseInt(params.cp ?? "", 16);
|
|
126
|
+
if (!Number.isFinite(cp)) return null;
|
|
127
|
+
return { verb, cp, coverage: list(params.status) };
|
|
128
|
+
}
|
|
129
|
+
case "r": {
|
|
130
|
+
const cp = Number.parseInt(params.cp ?? "", 16);
|
|
131
|
+
const status = Number.parseInt(params.status ?? "", 10);
|
|
132
|
+
if (!Number.isFinite(cp) || !Number.isFinite(status)) return null;
|
|
133
|
+
return params.reason === undefined ? { verb, cp, status } : { verb, cp, status, reason: params.reason };
|
|
134
|
+
}
|
|
135
|
+
case "c": {
|
|
136
|
+
const status = Number.parseInt(params.status ?? "", 10);
|
|
137
|
+
if (!Number.isFinite(status)) return null;
|
|
138
|
+
return params.reason === undefined ? { verb, status } : { verb, status, reason: params.reason };
|
|
139
|
+
}
|
|
140
|
+
default:
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -48,6 +48,8 @@ export * from "./fuzzy";
|
|
|
48
48
|
export * from "./keybindings";
|
|
49
49
|
// Kitty keyboard protocol helpers
|
|
50
50
|
export * from "./keys";
|
|
51
|
+
// Glyph Protocol: in-band icon registration (APC 25a1)
|
|
52
|
+
export * from "./glyph-protocol";
|
|
51
53
|
// Kitty graphics: Unicode placeholders
|
|
52
54
|
export * from "./kitty-graphics";
|
|
53
55
|
// LaTeX → Unicode/ANSI math rendering
|