@oh-my-pi/pi-tui 18.6.3 → 18.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -109
- package/dist/types/app-keybindings.d.ts +1 -1
- package/dist/types/apps/debug/log-viewer.d.ts +4 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
- package/dist/types/autocomplete.d.ts +5 -2
- package/dist/types/charts/chart-plan.d.ts +92 -0
- package/dist/types/charts/chart-svg.d.ts +30 -0
- package/dist/types/charts/table-data.d.ts +107 -0
- package/dist/types/chat/assistant-message.d.ts +4 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +2 -0
- package/dist/types/chat/fence-figure.d.ts +42 -0
- package/dist/types/chat/figure-markdown.d.ts +42 -0
- package/dist/types/chat/svg-figure.d.ts +33 -0
- package/dist/types/chat/svg-source.d.ts +49 -0
- package/dist/types/chat/table-chart.d.ts +88 -0
- package/dist/types/chat/tool-execution.d.ts +2 -0
- package/dist/types/components/editor.d.ts +9 -4
- package/dist/types/components/image.d.ts +9 -0
- package/dist/types/components/markdown.d.ts +16 -2
- package/dist/types/fuzzy.d.ts +29 -1
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/native/backend.d.ts +2 -1
- package/dist/types/native/blobs.d.ts +4 -2
- package/dist/types/native/encode.d.ts +3 -4
- package/dist/types/overlays/agent-transcript-viewer.d.ts +8 -1
- package/dist/types/overlays/agents-hub.d.ts +9 -0
- package/dist/types/overlays/annotation-overlay.d.ts +5 -2
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/model-browser.d.ts +31 -3
- package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
- package/dist/types/prompt/custom-editor.d.ts +7 -4
- package/dist/types/prompt/interactive-context-helpers.d.ts +4 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/render/composite.d.ts +2 -0
- package/dist/types/tools/glob.d.ts +4 -0
- package/dist/types/tools/renderer.d.ts +22 -0
- package/dist/types/tools/streaming-output.d.ts +11 -1
- package/dist/types/tools/write.d.ts +8 -1
- package/dist/types/utils.d.ts +6 -0
- package/package.json +9 -9
- package/src/apps/debug/log-viewer.ts +188 -72
- package/src/apps/debug/raw-sse-buffer.ts +8 -0
- package/src/apps/debug/raw-sse.ts +39 -5
- package/src/apps/git/diff-pane.ts +26 -5
- package/src/autocomplete.ts +67 -43
- package/src/charts/chart-plan.ts +367 -0
- package/src/charts/chart-svg.ts +693 -0
- package/src/charts/table-data.ts +436 -0
- package/src/chat/assistant-message.ts +169 -39
- package/src/chat/chat-transcript-builder.ts +4 -0
- package/src/chat/fence-figure.ts +80 -0
- package/src/chat/figure-markdown.ts +174 -0
- package/src/chat/svg-figure.ts +362 -0
- package/src/chat/svg-source.ts +188 -0
- package/src/chat/table-chart.ts +301 -0
- package/src/chat/tool-execution.ts +53 -4
- package/src/chrome/transcript-container.ts +7 -1
- package/src/components/editor.ts +68 -33
- package/src/components/image.ts +27 -1
- package/src/components/markdown.ts +80 -304
- package/src/fuzzy.ts +115 -30
- package/src/keybindings.ts +1 -1
- package/src/native/backend.ts +170 -15
- package/src/native/blobs.ts +4 -2
- package/src/native/encode.ts +58 -31
- package/src/overlays/agent-hub-projection.ts +70 -2
- package/src/overlays/agent-hub.ts +3 -2
- package/src/overlays/agent-transcript-viewer.ts +66 -13
- package/src/overlays/agents-hub.ts +28 -8
- package/src/overlays/annotation-overlay.ts +179 -80
- package/src/overlays/ask-dialog.ts +1 -1
- package/src/overlays/copy-selector.ts +30 -8
- package/src/overlays/extensions/state-manager.ts +52 -12
- package/src/overlays/history-search.ts +100 -7
- package/src/overlays/jobs-panel.ts +30 -2
- package/src/overlays/model-browser.ts +269 -90
- package/src/overlays/model-hub.ts +34 -7
- package/src/overlays/oauth-selector.ts +41 -26
- package/src/overlays/plan-review-overlay.ts +183 -68
- package/src/overlays/rewind-selector.ts +86 -17
- package/src/overlays/session-selector.ts +24 -4
- package/src/overlays/settings-selector.ts +21 -6
- package/src/overlays/tree-selector.ts +20 -4
- package/src/overlays/usage-dashboard.ts +12 -15
- package/src/prompt/attachment-chips.ts +2 -1
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer.ts +2 -14
- package/src/prompt/custom-editor.ts +48 -19
- package/src/prompt/interactive-context-helpers.ts +30 -18
- package/src/prompt/macos-spelling.ts +7 -0
- package/src/prompt/magic-keywords.ts +11 -2
- package/src/prompt/model-mention-autocomplete.ts +14 -14
- package/src/prompt/word-completion.ts +38 -5
- package/src/render/composite.ts +62 -0
- package/src/setup/scenes/splash.ts +109 -45
- package/src/status-line/component.ts +220 -64
- package/src/status-line/segments.ts +8 -3
- package/src/terminal.ts +3 -2
- package/src/tools/ast-edit.ts +59 -35
- package/src/tools/ast-grep.ts +35 -16
- package/src/tools/default-renderer.ts +35 -19
- package/src/tools/eval-format/index.ts +28 -2
- package/src/tools/eval-format/javascript.ts +7 -5
- package/src/tools/eval.ts +164 -78
- package/src/tools/glob.ts +23 -6
- package/src/tools/grep.ts +81 -48
- package/src/tools/lsp.ts +81 -59
- package/src/tools/mcp.ts +98 -68
- package/src/tools/renderer.ts +27 -0
- package/src/tools/streaming-output.ts +120 -48
- package/src/tools/task.ts +111 -54
- package/src/tools/todo.ts +115 -29
- package/src/tools/wait.ts +34 -24
- package/src/tools/write.ts +77 -39
- package/src/tui.ts +118 -105
- package/src/utils.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.8.0] - 2026-10-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- SVG and Mermaid files now render as images or diagrams beneath their file cards, with SVG previews updating while the file streams and Mermaid previews appearing when the file is complete.
|
|
10
|
+
- Native tool cards can open expanded regardless of the transcript’s expansion state; the todo checklist uses this behavior.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- TSP composer placeholders now appear as the composer title in italicized curly quotes, with “What are we cooking?” used when no title is provided.
|
|
15
|
+
- TSP image transfers are more efficient across reconnects and multiple surfaces: images are sent once per connection, existing terminal blobs are detected before upload, and images in the Tern blob cache can be reused without crossing the terminal pty.
|
|
16
|
+
- Improved performance and responsiveness across the TUI, including large TSP messages and Markdown documents, streaming output, tool-result cards, debug logs, raw SSE and Git diff views, path and model searches, session and settings lists, plan review, agent transcripts, status updates, assistant links, Kitty images, and large prompt or evaluation content.
|
|
17
|
+
- Large debug logs and plan-review histories now retain bounded history to keep the interface responsive, while preserving the newest log entries.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed slow Markdown processing for certain LaTeX environments and incomplete delimiters.
|
|
22
|
+
- Fixed excessive slowdown when formatting long semicolon-free JavaScript evaluations.
|
|
23
|
+
- Fixed prompt-editor lag in large drafts containing magic keywords.
|
|
24
|
+
|
|
25
|
+
## [18.7.0] - 2026-10-06
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Assistant SVG code blocks now render as inline, theme-colored images on terminals with graphics support, updating as responses stream and adapting to terminal width; SVG that cannot be rendered remains available as code.
|
|
30
|
+
- Numeric tables in assistant responses can now include automatically selected, themed charts based on the table’s structure and units.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- The status line now recognizes projects located in the user’s `repos` directory.
|
|
35
|
+
- Model mentions, `/switch` completions, and model-picker search now update immediately while typing, including with large model catalogs.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Fixed terminal resizing issues that could cause flicker or briefly display an empty frame.
|
|
40
|
+
- Improved `/annotate` handling for long source lines and filenames, preserving indentation and typed note text.
|
|
41
|
+
- Fixed fullscreen inputs that could hide the cursor when hardware-cursor support was enabled.
|
|
42
|
+
- Fixed model picker and mention-list ordering for same-provider `-latest` models so results remain alphabetically stable.
|
|
43
|
+
- Model browser performance metrics now show the correct measurements for each service tier and identify the tier.
|
|
44
|
+
- Fixed plan review keyboard navigation so horizontal options use Left/Right and model-slider adjustments use Shift+Left/Right.
|
|
45
|
+
- Improved the Ask dialog footer so question-switching keyboard shortcuts are clearly labeled.
|
|
46
|
+
- Fixed creating a new agent when its generated system prompt contains a Markdown code fence.
|
|
47
|
+
- Timed-out `glob` scans are now labeled as timed out rather than truncated.
|
|
48
|
+
- Ctrl+Delete now deletes the word after the cursor, matching Ctrl+Backspace behavior.
|
|
49
|
+
|
|
5
50
|
## [18.6.3] - 2026-10-06
|
|
6
51
|
|
|
7
52
|
### Breaking Changes
|
|
@@ -2947,112 +2992,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
|
|
|
2947
2992
|
|
|
2948
2993
|
- **Experimental:** Overlay compositing for `ctx.ui.custom()` with `{ overlay: true }` option ([#558](https://github.com/badlogic/pi-mono/pull/558) by [@nicobailon](https://github.com/nicobailon))
|
|
2949
2994
|
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
### Added
|
|
2953
|
-
|
|
2954
|
-
- `EditorComponent` interface for custom editor implementations
|
|
2955
|
-
- `StdinBuffer` class to split batched stdin into individual sequences (adapted from [OpenTUI](https://github.com/anomalyco/opentui), MIT license)
|
|
2956
|
-
|
|
2957
|
-
### Fixed
|
|
2958
|
-
|
|
2959
|
-
- Key presses no longer dropped when batched with other events over SSH ([#538](https://github.com/badlogic/pi-mono/pull/538))
|
|
2960
|
-
|
|
2961
|
-
## [0.37.8] - 2026-01-07
|
|
2962
|
-
|
|
2963
|
-
### Added
|
|
2964
|
-
|
|
2965
|
-
- `Component.wantsKeyRelease` property to opt-in to key release events (default false)
|
|
2966
|
-
|
|
2967
|
-
### Fixed
|
|
2968
|
-
|
|
2969
|
-
- TUI now filters out key release events by default, preventing double-processing of keys in editors and other components
|
|
2970
|
-
|
|
2971
|
-
## [0.37.7] - 2026-01-07
|
|
2972
|
-
|
|
2973
|
-
### Fixed
|
|
2974
|
-
|
|
2975
|
-
- `matchesKey()` now correctly matches Kitty protocol sequences for unmodified letter keys (needed for key release events)
|
|
2976
|
-
|
|
2977
|
-
## [0.37.6] - 2026-01-06
|
|
2978
|
-
|
|
2979
|
-
### Added
|
|
2980
|
-
|
|
2981
|
-
- Kitty keyboard protocol flag 2 support for key release events. New exports: `isKeyRelease(data)`, `isKeyRepeat(data)`, `KeyEventType` type. Terminals supporting Kitty protocol (Kitty, Ghostty, WezTerm) now send proper key-up events.
|
|
2982
|
-
|
|
2983
|
-
## [0.37.0] - 2026-01-05
|
|
2984
|
-
|
|
2985
|
-
### Fixed
|
|
2986
|
-
|
|
2987
|
-
- Crash when pasting text with trailing whitespace exceeding terminal width through Markdown rendering ([#457](https://github.com/badlogic/pi-mono/pull/457) by [@robinwander](https://github.com/robinwander))
|
|
2988
|
-
|
|
2989
|
-
## [0.34.1] - 2026-01-04
|
|
2990
|
-
|
|
2991
|
-
### Added
|
|
2992
|
-
|
|
2993
|
-
- Symbol key support in keybinding system: `SymbolKey` type with 32 symbol keys, `Key` constants (e.g., `Key.backtick`, `Key.comma`), updated `matchesKey()` and `parseKey()` to handle symbol input ([#450](https://github.com/badlogic/pi-mono/pull/450) by [@kaofelix](https://github.com/kaofelix))
|
|
2994
|
-
|
|
2995
|
-
## [0.34.0] - 2026-01-04
|
|
2996
|
-
|
|
2997
|
-
### Added
|
|
2998
|
-
|
|
2999
|
-
- `Editor.getExpandedText()` method that returns text with paste markers expanded to their actual content ([#444](https://github.com/badlogic/pi-mono/pull/444) by [@aliou](https://github.com/aliou))
|
|
3000
|
-
|
|
3001
|
-
## [0.33.0] - 2026-01-04
|
|
3002
|
-
|
|
3003
|
-
### Breaking Changes
|
|
3004
|
-
|
|
3005
|
-
- **Key detection functions removed**: All `isXxx()` key detection functions (`isEnter()`, `isEscape()`, `isCtrlC()`, etc.) have been removed. Use `matchesKey(data, keyId)` instead (e.g., `matchesKey(data, "enter")`, `matchesKey(data, "ctrl+c")`). This affects hooks and custom tools that use `ctx.ui.custom()` with keyboard input handling. ([#405](https://github.com/badlogic/pi-mono/pull/405))
|
|
3006
|
-
|
|
3007
|
-
### Added
|
|
3008
|
-
|
|
3009
|
-
- `Editor.insertTextAtCursor(text)` method for programmatic text insertion ([#419](https://github.com/badlogic/pi-mono/issues/419))
|
|
3010
|
-
- `EditorKeybindingsManager` for configurable editor keybindings. Components now use `matchesKey()` and keybindings manager instead of individual `isXxx()` functions. ([#405](https://github.com/badlogic/pi-mono/pull/405) by [@hjanuschka](https://github.com/hjanuschka))
|
|
3011
|
-
|
|
3012
|
-
### Changed
|
|
3013
|
-
|
|
3014
|
-
- Key detection refactored: consolidated `is*()` functions into generic `matchesKey(data, keyId)` function that accepts key identifiers like `"ctrl+c"`, `"shift+enter"`, `"alt+left"`, etc.
|
|
3015
|
-
|
|
3016
|
-
## [0.32.2] - 2026-01-03
|
|
3017
|
-
|
|
3018
|
-
### Fixed
|
|
3019
|
-
|
|
3020
|
-
- Slash command autocomplete now triggers for commands starting with `.`, `-`, or `_` (e.g., `/.land`, `/-foo`) ([#422](https://github.com/badlogic/pi-mono/issues/422))
|
|
3021
|
-
|
|
3022
|
-
## [0.32.0] - 2026-01-03
|
|
3023
|
-
|
|
3024
|
-
### Changed
|
|
3025
|
-
|
|
3026
|
-
- Editor component now uses word wrapping instead of character-level wrapping for better readability ([#382](https://github.com/badlogic/pi-mono/pull/382) by [@nickseelert](https://github.com/nickseelert))
|
|
3027
|
-
|
|
3028
|
-
### Fixed
|
|
3029
|
-
|
|
3030
|
-
- Shift+Space, Shift+Backspace, and Shift+Delete now work correctly in Kitty-protocol terminals (Kitty, WezTerm, etc.) instead of being silently ignored ([#411](https://github.com/badlogic/pi-mono/pull/411) by [@nathyong](https://github.com/nathyong))
|
|
3031
|
-
|
|
3032
|
-
## [0.31.1] - 2026-01-02
|
|
3033
|
-
|
|
3034
|
-
### Fixed
|
|
3035
|
-
|
|
3036
|
-
- `visibleWidth()` now strips OSC 8 hyperlink sequences, fixing text wrapping for clickable links ([#396](https://github.com/badlogic/pi-mono/pull/396) by [@Cursivez](https://github.com/Cursivez))
|
|
3037
|
-
|
|
3038
|
-
## [0.31.0] - 2026-01-02
|
|
3039
|
-
|
|
3040
|
-
### Added
|
|
3041
|
-
|
|
3042
|
-
- `isShiftCtrlO()` key detection function for Shift+Ctrl+O (Kitty protocol)
|
|
3043
|
-
- `isShiftCtrlD()` key detection function for Shift+Ctrl+D (Kitty protocol)
|
|
3044
|
-
- `TUI.onDebug` callback for global debug key handling (Shift+Ctrl+D)
|
|
3045
|
-
- `wrapTextWithAnsi()` utility now exported (wraps text to width, preserving ANSI codes)
|
|
3046
|
-
|
|
3047
|
-
### Changed
|
|
3048
|
-
|
|
3049
|
-
- README.md completely rewritten with accurate component documentation, theme interfaces, and examples
|
|
3050
|
-
- `visibleWidth()` reimplemented with grapheme-based width calculation, 10x faster on Bun and ~15% faster on Node ([#369](https://github.com/badlogic/pi-mono/pull/369) by [@nathyong](https://github.com/nathyong))
|
|
3051
|
-
|
|
3052
|
-
### Fixed
|
|
3053
|
-
|
|
3054
|
-
- Markdown component now renders HTML tags as plain text instead of silently dropping them ([#359](https://github.com/badlogic/pi-mono/issues/359))
|
|
3055
|
-
- Crash in `visibleWidth()` and grapheme iteration when encountering undefined code points ([#372](https://github.com/badlogic/pi-mono/pull/372) by [@HACKE-RC](https://github.com/HACKE-RC))
|
|
3056
|
-
- ZWJ emoji sequences (rainbow flag, family, etc.) now render with correct width instead of being split into multiple characters ([#369](https://github.com/badlogic/pi-mono/pull/369) by [@nathyong](https://github.com/nathyong))
|
|
3057
|
-
|
|
3058
|
-
Older entries are archived in [packages/tui/CHANGELOG.md@bac7e83b5b0e](https://github.com/can1357/oh-my-pi/blob/bac7e83b5b0eb86c909c17830a6666efc359578b/packages/tui/CHANGELOG.md).
|
|
2995
|
+
Older entries are archived in [packages/tui/CHANGELOG.md@fa14205f838f](https://github.com/can1357/oh-my-pi/blob/fa14205f838f282fcea048c64fca74026789a492/packages/tui/CHANGELOG.md).
|
|
@@ -119,7 +119,7 @@ export declare const KEYBINDINGS: {
|
|
|
119
119
|
readonly description: "Delete word backward";
|
|
120
120
|
};
|
|
121
121
|
readonly "tui.editor.deleteWordForward": {
|
|
122
|
-
readonly defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"];
|
|
122
|
+
readonly defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"];
|
|
123
123
|
readonly description: "Delete word forward";
|
|
124
124
|
};
|
|
125
125
|
readonly "tui.editor.deleteToLineStart": {
|
|
@@ -15,6 +15,8 @@ type DebugLogViewerModelOptions = {
|
|
|
15
15
|
processPid?: number;
|
|
16
16
|
hasOlderLogs?: () => boolean;
|
|
17
17
|
loadOlderLogs?: (limitDays?: number) => Promise<string>;
|
|
18
|
+
/** Most entries kept; older history beyond it is not loaded. Defaults to {@link MAX_LOG_ENTRIES}. */
|
|
19
|
+
maxLogEntries?: number;
|
|
18
20
|
};
|
|
19
21
|
type ViewerRow = {
|
|
20
22
|
kind: "warning";
|
|
@@ -33,6 +35,8 @@ export declare class DebugLogViewerModel {
|
|
|
33
35
|
#private;
|
|
34
36
|
constructor(logText: string, options?: DebugLogViewerModelOptions);
|
|
35
37
|
get logCount(): number;
|
|
38
|
+
/** True once the entry cap is reached, so older history no longer loads. */
|
|
39
|
+
get historyLimitReached(): boolean;
|
|
36
40
|
get visibleLogCount(): number;
|
|
37
41
|
get rows(): readonly ViewerRow[];
|
|
38
42
|
get cursorRowIndex(): number | undefined;
|
|
@@ -41,6 +41,8 @@ export declare function rawSseRecordLines(record: RawSseDebugRecord): string[];
|
|
|
41
41
|
/** Bounded, observable capture of raw provider responses and SSE frames. */
|
|
42
42
|
export declare class RawSseDebugBuffer {
|
|
43
43
|
#private;
|
|
44
|
+
/** Bumped on every change to the captured window (append, eviction, clear); equal revisions mean equal snapshots. */
|
|
45
|
+
get revision(): number;
|
|
44
46
|
subscribe(listener: () => void): () => void;
|
|
45
47
|
recordResponse(response: ProviderResponseMetadata, model?: Model): void;
|
|
46
48
|
recordEvent(event: RawSseEvent, model?: Model): void;
|
|
@@ -77,8 +77,11 @@ export interface AutocompleteProvider {
|
|
|
77
77
|
};
|
|
78
78
|
/** Get inline hint text to show as dim ghost text after the cursor */
|
|
79
79
|
getInlineHint?(lines: string[], cursorLine: number, cursorCol: number): string | null;
|
|
80
|
-
/**
|
|
81
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Synchronously list slash command-name completions for a leading slash token (no async I/O).
|
|
82
|
+
* Mirrors the command-name branch of {@link getSuggestions}, including the bare `/` listing and
|
|
83
|
+
* the collapsed `/skill:` namespace row. Returns null outside a command-name token or with no match.
|
|
84
|
+
*/
|
|
82
85
|
trySyncSlashCompletion?(textBeforeCursor: string): {
|
|
83
86
|
items: AutocompleteItem[];
|
|
84
87
|
prefix: string;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which chart a table becomes and the data it plots. {@link planChart} is the
|
|
3
|
+
* local best guess over a {@link TableAnalysis}: the chart kind, the label
|
|
4
|
+
* column and the measure columns to draw. A host may substitute its own
|
|
5
|
+
* {@link ChartPlan} (a model's pick for a multi-series table); either way
|
|
6
|
+
* {@link buildChart} turns it into the {@link ChartSpec} that
|
|
7
|
+
* {@link renderChartSvg} draws, and {@link worthCharting} decides whether
|
|
8
|
+
* the picture says more than the table already does.
|
|
9
|
+
*
|
|
10
|
+
* The heuristics were fitted on ~7k tables from real assistant answers: the
|
|
11
|
+
* label is the first text column (index columns like `#`/`Rank` never are),
|
|
12
|
+
* table order is kept (most tables are deliberately unsorted), total rows stay
|
|
13
|
+
* out of the scale, and units never share an axis.
|
|
14
|
+
*/
|
|
15
|
+
import { type Dimension, type TableAnalysis } from "./table-data.js";
|
|
16
|
+
/**
|
|
17
|
+
* Chart kinds, by the table shapes they fit:
|
|
18
|
+
* - `bar`: one measure across categories.
|
|
19
|
+
* - `paired`: two same-unit measures per category (before/after, A vs B), or `a → b` cells.
|
|
20
|
+
* - `grouped`: three or four same-unit measures per category.
|
|
21
|
+
* - `line`: measures over an ordered axis (dates, runs, sizes).
|
|
22
|
+
* - `heatmap`: a matrix of same-unit values.
|
|
23
|
+
* - `multiples`: measures in different units, each scaled on its own; transposed when each row is its own metric.
|
|
24
|
+
* - `share`: parts of a whole (percentages summing to 100).
|
|
25
|
+
* - `diverging`: signed changes around zero.
|
|
26
|
+
* - `scatter`: two continuous measures per item.
|
|
27
|
+
*/
|
|
28
|
+
export type ChartKind = "bar" | "paired" | "grouped" | "line" | "heatmap" | "multiples" | "share" | "diverging" | "scatter";
|
|
29
|
+
/** What to draw from a table: the kind, the column naming each category, and the columns plotted. */
|
|
30
|
+
export interface ChartPlan {
|
|
31
|
+
readonly kind: ChartKind;
|
|
32
|
+
/** Column naming each category (or holding the x values of a line); rows are numbered without one. */
|
|
33
|
+
readonly label: number | undefined;
|
|
34
|
+
/** Plotted columns, in order. */
|
|
35
|
+
readonly series: readonly number[];
|
|
36
|
+
/** Each data row is its own series (a metric with its own unit) and the plotted columns are the categories. */
|
|
37
|
+
readonly transpose: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** One plotted value. */
|
|
40
|
+
export interface ChartPoint {
|
|
41
|
+
/** Value in base units (seconds, bytes, …). */
|
|
42
|
+
readonly value: number;
|
|
43
|
+
/** The number as the table wrote it (`~$250`, `12.5 ms`), shown as the value label. */
|
|
44
|
+
readonly text: string;
|
|
45
|
+
/** The table bolded the cell. */
|
|
46
|
+
readonly emphasis: boolean;
|
|
47
|
+
/** Upper end of a range cell (`24–72 h`). */
|
|
48
|
+
readonly upper?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface ChartSeries {
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly dim: Dimension;
|
|
53
|
+
/** Currency symbol or rate unit the axis prints; empty for other dimensions. */
|
|
54
|
+
readonly unit: string;
|
|
55
|
+
/** One per category; `null` where the cell holds no number of this series' dimension. */
|
|
56
|
+
readonly points: readonly (ChartPoint | null)[];
|
|
57
|
+
/** Status words standing in for a value (`TIMEOUT`, `OOM`), one per category. */
|
|
58
|
+
readonly notes: readonly (string | undefined)[];
|
|
59
|
+
}
|
|
60
|
+
/** The data a chart draws, independent of how it is drawn. */
|
|
61
|
+
export interface ChartSpec {
|
|
62
|
+
readonly kind: ChartKind;
|
|
63
|
+
readonly categories: readonly string[];
|
|
64
|
+
readonly series: readonly ChartSeries[];
|
|
65
|
+
/** Numeric x positions of a line or the x measure of a scatter, one per category. */
|
|
66
|
+
readonly x?: {
|
|
67
|
+
readonly name: string;
|
|
68
|
+
readonly dim: Dimension;
|
|
69
|
+
readonly unit: string;
|
|
70
|
+
readonly values: readonly number[];
|
|
71
|
+
};
|
|
72
|
+
/** Total/summary rows, printed under the chart instead of skewing its scale. */
|
|
73
|
+
readonly caption?: string;
|
|
74
|
+
/** Name of the category axis (the label column's header). */
|
|
75
|
+
readonly axis: string;
|
|
76
|
+
}
|
|
77
|
+
/** The local best guess at a chart for `table`, or `undefined` when no chart fits. */
|
|
78
|
+
export declare function planChart(table: TableAnalysis): ChartPlan | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* The data `plan` draws from `table`, or `undefined` when it leaves fewer than
|
|
81
|
+
* two categories or no series with two values. The kind is fitted to the
|
|
82
|
+
* series it ends up with ({@link fitKind}), so any plan — a model's pick
|
|
83
|
+
* included — draws as something the renderer supports.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildChart(table: TableAnalysis, plan: ChartPlan): ChartSpec | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Whether a chart of `spec` reads faster than its table: at least four
|
|
88
|
+
* categories, and either nine plotted values or a 3× spread within a series.
|
|
89
|
+
* On a model-judged sample of assistant tables this gate kept 85% of the
|
|
90
|
+
* tables a chart clearly helped while rejecting most two- and three-row ones.
|
|
91
|
+
*/
|
|
92
|
+
export declare function worthCharting(spec: ChartSpec): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draws a {@link ChartSpec} as a standalone SVG document colored only with
|
|
3
|
+
* figure tokens — `var(--fg)`, `var(--muted)`, `var(--border)`,
|
|
4
|
+
* `var(--accent)`, `var(--surface)`, `var(--c1)`…`var(--c6)` — on a
|
|
5
|
+
* transparent background — the token vocabulary of assistant ```svg figures —
|
|
6
|
+
* so the host resolves them against the live theme (`prepareSvg`) for both
|
|
7
|
+
* the rasterized terminal image and the native TSP blob.
|
|
8
|
+
*
|
|
9
|
+
* Geometry follows the terminal: 16 user units per row and a monospace face,
|
|
10
|
+
* so 13-unit labels land near the terminal's own glyph size. Marks are flat
|
|
11
|
+
* and square (no rounding, gradients or shadows); bolded table cells draw at
|
|
12
|
+
* full strength while their neighbours recede.
|
|
13
|
+
*/
|
|
14
|
+
import type { ChartSpec } from "./chart-plan.js";
|
|
15
|
+
import type { Dimension } from "./table-data.js";
|
|
16
|
+
/** A drawn chart: the SVG document and its size in user units. */
|
|
17
|
+
export interface ChartSvg {
|
|
18
|
+
readonly svg: string;
|
|
19
|
+
readonly width: number;
|
|
20
|
+
readonly height: number;
|
|
21
|
+
}
|
|
22
|
+
/** The SVG document for `spec`. */
|
|
23
|
+
export declare function renderChartSvg(spec: ChartSpec): ChartSvg;
|
|
24
|
+
/** One-line description of the chart, for screen readers and terminals that show the alt text. */
|
|
25
|
+
export declare function chartAlt(spec: ChartSpec): string;
|
|
26
|
+
/**
|
|
27
|
+
* A value in base units as an axis label: durations and sizes in the unit
|
|
28
|
+
* their magnitude reads best in, counts compacted (`12k`, `3.4M`).
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatValue(value: number, dim: Dimension, unit: string): string;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Numeric reading of GFM table cells and columns, the input to
|
|
3
|
+
* {@link planChart}: what number a cell holds (in base units, with its
|
|
4
|
+
* dimension and annotations) and which role each column plays — a measure to
|
|
5
|
+
* plot, a category label, an ordered x axis, or a row index to ignore.
|
|
6
|
+
*
|
|
7
|
+
* Cells are model-written prose, not CSV: `~1,400`, `**4** ✅`, `17 (21.5%)`,
|
|
8
|
+
* `24–72 h`, `12 → 15`, `5/8`, `1m 56s`, `TIMEOUT`. The reader keeps the first
|
|
9
|
+
* number and its unit and classifies the rest, so a column of mostly clean
|
|
10
|
+
* numbers survives a few annotated or sentinel cells.
|
|
11
|
+
*/
|
|
12
|
+
/** What a number measures; values of one dimension share an axis after unit normalization. */
|
|
13
|
+
export type Dimension = "count" | "percent" | "duration" | "bytes" | "currency" | "ratio" | "fraction" | "rate";
|
|
14
|
+
/**
|
|
15
|
+
* How cleanly a cell reads as its number: bare (`12 ms`), with a short note
|
|
16
|
+
* (`17 (21.5%)`, `16 pass`), a range (`24–72 h`), a transition (`12 → 15`), a
|
|
17
|
+
* fraction (`5/8`), or a number leading prose (`~1,400w, nearly ready`).
|
|
18
|
+
*/
|
|
19
|
+
export type CellFit = "pure" | "note" | "range" | "arrow" | "fraction" | "prose";
|
|
20
|
+
/** A cell that reads as a number. */
|
|
21
|
+
export interface NumberCell {
|
|
22
|
+
readonly kind: "number";
|
|
23
|
+
/** Value in base units: seconds, bytes, a plain count, percent points. */
|
|
24
|
+
readonly value: number;
|
|
25
|
+
readonly dim: Dimension;
|
|
26
|
+
/** Unit or currency symbol as written (`ms`, `KiB`, `$`, `tok/s`); empty for bare numbers. */
|
|
27
|
+
readonly unit: string;
|
|
28
|
+
readonly fit: CellFit;
|
|
29
|
+
/** Written as an estimate or bound (`~`, `≈`, `<`, `≥`). */
|
|
30
|
+
readonly approx: boolean;
|
|
31
|
+
/** Written with an explicit sign (`+12%`, `-3`). */
|
|
32
|
+
readonly signed: boolean;
|
|
33
|
+
/** The cell was bolded: models bold the value they want noticed. */
|
|
34
|
+
readonly emphasis: boolean;
|
|
35
|
+
/** The cell text without Markdown decoration. */
|
|
36
|
+
readonly text: string;
|
|
37
|
+
/** The number as written, with approximation, sign, currency and unit (`~$250`, `12.5 ms`, `24–72 h`). */
|
|
38
|
+
readonly figure: string;
|
|
39
|
+
/** `a → b`: `b`, in the same base units. */
|
|
40
|
+
readonly to?: number;
|
|
41
|
+
/** `a → b`: `b` as written. */
|
|
42
|
+
readonly toFigure?: string;
|
|
43
|
+
/** `a–b`: `b`, in the same base units. */
|
|
44
|
+
readonly upper?: number;
|
|
45
|
+
/** `a/b`: `b`. */
|
|
46
|
+
readonly denominator?: number;
|
|
47
|
+
}
|
|
48
|
+
/** A cell that is not a quantity. */
|
|
49
|
+
export interface OtherCell {
|
|
50
|
+
readonly kind: "missing" | "date" | "time" | "version" | "id" | "text";
|
|
51
|
+
readonly text: string;
|
|
52
|
+
readonly emphasis: boolean;
|
|
53
|
+
}
|
|
54
|
+
export type Cell = NumberCell | OtherCell;
|
|
55
|
+
/**
|
|
56
|
+
* What a column contributes to a chart: `measure` values to plot, `label`
|
|
57
|
+
* category names, `temporal` dates or times, `sequence` an ordered step
|
|
58
|
+
* (`Run`, `Day`, `Workers`), `index` a row number or identifier never plotted.
|
|
59
|
+
*/
|
|
60
|
+
export type ColumnRole = "measure" | "label" | "temporal" | "sequence" | "index";
|
|
61
|
+
export interface TableColumn {
|
|
62
|
+
readonly index: number;
|
|
63
|
+
/** Header text without Markdown decoration. */
|
|
64
|
+
readonly header: string;
|
|
65
|
+
readonly role: ColumnRole;
|
|
66
|
+
readonly cells: readonly Cell[];
|
|
67
|
+
/** Dominant dimension of the numeric cells. */
|
|
68
|
+
readonly dim: Dimension | undefined;
|
|
69
|
+
/** Representative unit of the dominant dimension (`$`, `tok/s`); empty when bare. */
|
|
70
|
+
readonly unit: string;
|
|
71
|
+
/** Numeric cells disagree on dimension (a metric-per-row table). */
|
|
72
|
+
readonly mixed: boolean;
|
|
73
|
+
/** Every numeric data cell holds the same value: an echoed setting, not a measure. */
|
|
74
|
+
readonly constant: boolean;
|
|
75
|
+
/** Share of numeric cells written with an explicit sign. */
|
|
76
|
+
readonly signedShare: number;
|
|
77
|
+
/** Share of numeric cells written as `a → b`. */
|
|
78
|
+
readonly arrowShare: number;
|
|
79
|
+
}
|
|
80
|
+
/** A table read for charting. */
|
|
81
|
+
export interface TableAnalysis {
|
|
82
|
+
readonly columns: readonly TableColumn[];
|
|
83
|
+
/** Category labels: the first text or temporal column, else a sequence or index column. */
|
|
84
|
+
readonly label: TableColumn | undefined;
|
|
85
|
+
/** Plottable measure columns, constant ones excluded. */
|
|
86
|
+
readonly measures: readonly TableColumn[];
|
|
87
|
+
/** Data rows, in table order, without total/summary rows. */
|
|
88
|
+
readonly rows: readonly number[];
|
|
89
|
+
/** Total/summary rows (`Total`, `Average`, …), kept out of the scale. */
|
|
90
|
+
readonly totals: readonly number[];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Strip inline Markdown from a cell: links keep their text; bold, italics,
|
|
94
|
+
* strikethrough, code spans and `<br>` keep their content.
|
|
95
|
+
*/
|
|
96
|
+
export declare function plainCell(markdown: string): {
|
|
97
|
+
text: string;
|
|
98
|
+
emphasis: boolean;
|
|
99
|
+
};
|
|
100
|
+
/** Parse the first number of a (Markdown) cell, or classify why it is not one. */
|
|
101
|
+
export declare function parseCell(markdown: string): Cell;
|
|
102
|
+
/** Read a table's columns and rows for charting. Cells are the raw Markdown of each cell. */
|
|
103
|
+
export declare function analyzeTable(header: readonly string[], rows: readonly (readonly string[])[]): TableAnalysis;
|
|
104
|
+
/** Strictly increasing or strictly decreasing. */
|
|
105
|
+
export declare function isMonotonic(values: readonly number[]): boolean;
|
|
106
|
+
/** Whether `cell` reads as a number. */
|
|
107
|
+
export declare function isNumber(cell: Cell | undefined): cell is NumberCell;
|
|
@@ -86,6 +86,8 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
86
86
|
*/
|
|
87
87
|
setExpanded(expanded: boolean): void;
|
|
88
88
|
isTranscriptBlockFinalized(): boolean;
|
|
89
|
+
/** Whether a figure still waits for the raster of its final source; the transcript holds retirement meanwhile. */
|
|
90
|
+
isTranscriptBlockPending(): boolean;
|
|
89
91
|
render(width: number): readonly string[];
|
|
90
92
|
/**
|
|
91
93
|
* A `col` (role `omp.assistant`) of `md` nodes keyed by content index, so
|
|
@@ -123,6 +125,8 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
123
125
|
messagePersistenceKey(): string | undefined;
|
|
124
126
|
/** Toggle rendering for assistant-native and tool-result images. */
|
|
125
127
|
setImagesVisible(visible: boolean): void;
|
|
128
|
+
/** Toggle charts under numeric tables (the main session's transcript only, never a subagent's). */
|
|
129
|
+
setTableChartsVisible(visible: boolean): void;
|
|
126
130
|
/** Toggle only images produced by tool results; assistant-native images remain governed by setImagesVisible. */
|
|
127
131
|
setToolResultImagesVisible(visible: boolean): void;
|
|
128
132
|
setToolResultImages(toolCallId: string, images: ImageContent[]): void;
|
|
@@ -28,6 +28,8 @@ export interface ChatTranscriptBuilderDeps {
|
|
|
28
28
|
expandThinkingBlocks?: () => boolean;
|
|
29
29
|
/** Session-scoped resolved destinations for model-authored Markdown links. */
|
|
30
30
|
linkTargets?: ReadonlyMap<string, string>;
|
|
31
|
+
/** Draw charts under numeric tables; false for transcripts that are not the main session's. Default: true. */
|
|
32
|
+
tableCharts?: boolean;
|
|
31
33
|
requestRender: () => void;
|
|
32
34
|
}
|
|
33
35
|
export declare class ChatTranscriptBuilder {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tool call's {@link ToolFigure} drawn under its card, the way assistant
|
|
3
|
+
* Markdown draws that fence: ```svg as an inline image ({@link SvgFigure}),
|
|
4
|
+
* redrawn as the body streams; ```mermaid as ASCII art once the body is
|
|
5
|
+
* final. The card already shows the source, so unlike the assistant's fence
|
|
6
|
+
* it never falls back to code: {@link FenceFigure.draws} turns down fences
|
|
7
|
+
* this terminal shows as code, and an svg that does not rasterize stays blank.
|
|
8
|
+
*/
|
|
9
|
+
import type { ImageBudget } from "../components/image.js";
|
|
10
|
+
import type { ToolFigure } from "../tools/renderer.js";
|
|
11
|
+
import type { Component } from "../tui.js";
|
|
12
|
+
/** Fence languages a {@link FenceFigure} draws. */
|
|
13
|
+
export type FenceFigureLang = "svg" | "mermaid";
|
|
14
|
+
export interface FenceFigureOptions {
|
|
15
|
+
/** Shared inline-image budget for an svg's rasters. */
|
|
16
|
+
budget?: ImageBudget;
|
|
17
|
+
/** The figure's rows changed outside a render: a raster landed. */
|
|
18
|
+
onChange: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class FenceFigure implements Component {
|
|
21
|
+
#private;
|
|
22
|
+
/**
|
|
23
|
+
* Whether this terminal draws `figure` now: an svg where inline images show
|
|
24
|
+
* (`showImages` and a graphics protocol), a closed mermaid fence when
|
|
25
|
+
* diagram rendering is on and the source renders.
|
|
26
|
+
*/
|
|
27
|
+
static draws(figure: ToolFigure, options: {
|
|
28
|
+
showImages: boolean;
|
|
29
|
+
}): figure is ToolFigure & {
|
|
30
|
+
readonly lang: FenceFigureLang;
|
|
31
|
+
};
|
|
32
|
+
readonly lang: FenceFigureLang;
|
|
33
|
+
constructor(lang: FenceFigureLang, options: FenceFigureOptions);
|
|
34
|
+
/** Feed the fence as it stands; its `lang` is this figure's. */
|
|
35
|
+
update(figure: ToolFigure): void;
|
|
36
|
+
/** Whether a closed svg's raster is still on its way. */
|
|
37
|
+
get pending(): boolean;
|
|
38
|
+
/** The drawing; no rows while an svg draws, or when it does not. */
|
|
39
|
+
render(width: number): readonly string[];
|
|
40
|
+
invalidate(): void;
|
|
41
|
+
dispose(): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ImageBudget } from "../components/image.js";
|
|
2
|
+
import type { Markdown } from "../components/markdown.js";
|
|
3
|
+
import { Container } from "../tui.js";
|
|
4
|
+
export interface FigureMarkdownOptions {
|
|
5
|
+
/** Markdown for one prose run (and a failed figure's code fallback); FigureMarkdown drives its transience. */
|
|
6
|
+
markdown: (text: string) => Markdown;
|
|
7
|
+
/** Draw charts under numeric tables; off for transcripts that are not the main session's. */
|
|
8
|
+
charts: boolean;
|
|
9
|
+
/** Shared inline-image budget for the figures. */
|
|
10
|
+
budget?: ImageBudget;
|
|
11
|
+
/** A figure's rows changed outside a text update (raster landed, fell back to code). */
|
|
12
|
+
onChange: () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Assistant Markdown whose top-level ```svg fences are lifted out of the prose
|
|
16
|
+
* and drawn as images ({@link SvgFigure}), and whose numeric tables get a chart
|
|
17
|
+
* drawn under them ({@link TableChartFigure}), with ordinary {@link Markdown}
|
|
18
|
+
* for the prose between them. Stands in for Markdown on an assistant text
|
|
19
|
+
* block that holds an svg fence or a chartable table: {@link setText} streams
|
|
20
|
+
* in place, reusing every part whose kind is unchanged, and
|
|
21
|
+
* {@link transientRenderCache} marks the block's tail as still streaming — the
|
|
22
|
+
* last prose run renders transient, the last figure throttles its rasters
|
|
23
|
+
* until its fence closes, and a table at the tail waits for its last row.
|
|
24
|
+
*/
|
|
25
|
+
export declare class FigureMarkdown extends Container {
|
|
26
|
+
#private;
|
|
27
|
+
constructor(text: string, options: FigureMarkdownOptions);
|
|
28
|
+
/** Replace the source; returns whether it changed. */
|
|
29
|
+
setText(text: string): boolean;
|
|
30
|
+
get transientRenderCache(): boolean;
|
|
31
|
+
set transientRenderCache(value: boolean);
|
|
32
|
+
/**
|
|
33
|
+
* The trimmed prose ahead of the first figure, or "" when the block opens
|
|
34
|
+
* with one. These are the only rows plain Markdown reproduces byte for
|
|
35
|
+
* byte, so they are all a transcript may publish ahead of the figure.
|
|
36
|
+
*/
|
|
37
|
+
get leadingProse(): string;
|
|
38
|
+
/** Whether a figure's final source still waits for its raster, or a chart for its pick or raster. */
|
|
39
|
+
get pending(): boolean;
|
|
40
|
+
/** Rebuild the prose runs through the Markdown factory after its theme changed; figures keep their rasters. */
|
|
41
|
+
restyle(): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ImageBudget } from "../components/image.js";
|
|
2
|
+
import { type Markdown } from "../components/markdown.js";
|
|
3
|
+
import type { Component } from "../tui.js";
|
|
4
|
+
/** The active theme's color per figure token, for resolving a figure with `prepareSvg`. */
|
|
5
|
+
export declare function svgFigurePalette(): Record<string, string>;
|
|
6
|
+
/** Turn lifting ```svg fences into images on or off (the host's `tui.renderSvg`); the host rebuilds the transcript after. */
|
|
7
|
+
export declare function setSvgFigureRendering(enabled: boolean): void;
|
|
8
|
+
/** Whether assistant ```svg fences render as images where the terminal can show them. */
|
|
9
|
+
export declare function svgFigureRendering(): boolean;
|
|
10
|
+
export interface SvgFigureOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Markdown for the fenced-code fallback shown when the final source does not
|
|
13
|
+
* render. Without it the figure decorates content shown elsewhere (a chart
|
|
14
|
+
* under its table): it stays blank until drawn, and when it cannot be.
|
|
15
|
+
*/
|
|
16
|
+
markdown?: (text: string) => Markdown;
|
|
17
|
+
/** Shared inline-image budget; superseded rasters are released from it. */
|
|
18
|
+
budget?: ImageBudget;
|
|
19
|
+
/** The figure's rows changed outside a text update: a raster landed or rendering fell back to code. */
|
|
20
|
+
onChange: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare class SvgFigure implements Component {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(options: SvgFigureOptions);
|
|
25
|
+
/** Feed the fence body; `final` once the fence closed or the message stopped streaming. */
|
|
26
|
+
update(source: string, final: boolean): void;
|
|
27
|
+
/** Whether the final source still waits for its raster (or for failing to render). */
|
|
28
|
+
get pending(): boolean;
|
|
29
|
+
render(width: number): readonly string[];
|
|
30
|
+
invalidate(): void;
|
|
31
|
+
dispose(): void;
|
|
32
|
+
debugState(): Record<string, unknown>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-level handling of ```svg fences in assistant Markdown: splitting
|
|
3
|
+
* prose around them ({@link splitSvgFences}), turning a fence that is still
|
|
4
|
+
* streaming into a document an SVG parser accepts ({@link closePartialSvg}),
|
|
5
|
+
* and resolving the theme tokens figures color themselves with
|
|
6
|
+
* ({@link prepareSvg}). `FigureMarkdown` lifts the fences out as `SvgFigure`
|
|
7
|
+
* images.
|
|
8
|
+
*/
|
|
9
|
+
/** One run of an assistant text block: prose, or the body of a ```svg fence. */
|
|
10
|
+
export type FigureSegment = {
|
|
11
|
+
readonly kind: "markdown";
|
|
12
|
+
readonly text: string;
|
|
13
|
+
}
|
|
14
|
+
/** `closed` once the fence's closing line arrived. */
|
|
15
|
+
| {
|
|
16
|
+
readonly kind: "svg";
|
|
17
|
+
readonly source: string;
|
|
18
|
+
readonly closed: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** Whether `markdown` holds a ```svg fence {@link splitSvgFences} would lift. */
|
|
21
|
+
export declare function hasSvgFence(markdown: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Split `markdown` into prose and ```svg fence bodies, in order. Only
|
|
24
|
+
* top-level fences lift; an svg fence nested in another fence, a list's
|
|
25
|
+
* indented block or a blockquote stays prose. Blank prose runs are dropped.
|
|
26
|
+
* An svg fence still open at the end is the last segment, `closed: false`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function splitSvgFences(markdown: string): FigureSegment[];
|
|
29
|
+
/**
|
|
30
|
+
* Turn a possibly truncated SVG source into a well-formed document: cut the
|
|
31
|
+
* trailing construct still being written (a tag without its `>`, an
|
|
32
|
+
* unterminated comment, CDATA section, processing instruction or declaration,
|
|
33
|
+
* a dangling `&entity`) and close every element left open, innermost first.
|
|
34
|
+
* A complete document passes through unchanged. Returns null until the root
|
|
35
|
+
* `<svg …>` start tag is complete — before that there is nothing to draw.
|
|
36
|
+
*/
|
|
37
|
+
export declare function closePartialSvg(source: string): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Make a figure's source what an SVG rasterizer draws as written, in the
|
|
40
|
+
* reader's theme. Rasterizers resolve neither CSS custom properties nor an
|
|
41
|
+
* inherited text color, and reject a root without the SVG namespace, so:
|
|
42
|
+
* - `var(--name)` / `var(--name, fallback)` become `palette[name]` (an
|
|
43
|
+
* unknown name takes its fallback, else `palette.fg`);
|
|
44
|
+
* - a root `<svg>` lacking them gets `color` = `palette.fg` (so
|
|
45
|
+
* `currentColor` follows the theme), a sans-serif `font-family` (instead
|
|
46
|
+
* of the rasterizer's Times), `xmlns`, and `xmlns:xlink` when the source
|
|
47
|
+
* uses `xlink:` attributes.
|
|
48
|
+
*/
|
|
49
|
+
export declare function prepareSvg(svg: string, palette: Readonly<Record<string, string>>): string;
|