@sagmans/dsh-tui 0.1.2 → 0.3.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/README.md +196 -17
- package/cordis.patch.yml +4 -2
- package/lib/agent/host.d.ts +14 -0
- package/lib/agent/host.d.ts.map +1 -1
- package/lib/agent/host.js +20 -4
- package/lib/agent/host.js.map +1 -1
- package/lib/agent/model.d.ts +50 -0
- package/lib/agent/model.d.ts.map +1 -1
- package/lib/agent/model.js +87 -1
- package/lib/agent/model.js.map +1 -1
- package/lib/agent/present.d.ts +7 -1
- package/lib/agent/present.d.ts.map +1 -1
- package/lib/agent/present.js +33 -4
- package/lib/agent/present.js.map +1 -1
- package/lib/agent/presets.d.ts +7 -1
- package/lib/agent/presets.d.ts.map +1 -1
- package/lib/agent/presets.js +7 -3
- package/lib/agent/presets.js.map +1 -1
- package/lib/agent/status.d.ts +10 -0
- package/lib/agent/status.d.ts.map +1 -1
- package/lib/agent/status.js +2 -0
- package/lib/agent/status.js.map +1 -1
- package/lib/cards.d.ts +127 -7
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +381 -52
- package/lib/cards.js.map +1 -1
- package/lib/export.d.ts +5 -4
- package/lib/export.d.ts.map +1 -1
- package/lib/export.js +62 -13
- package/lib/export.js.map +1 -1
- package/lib/fold-cursor.d.ts +23 -0
- package/lib/fold-cursor.d.ts.map +1 -0
- package/lib/fold-cursor.js +31 -0
- package/lib/fold-cursor.js.map +1 -0
- package/lib/gates.d.ts +145 -2
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +335 -40
- package/lib/gates.js.map +1 -1
- package/lib/index.d.ts +7 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +651 -92
- package/lib/index.js.map +1 -1
- package/lib/input/actions.d.ts +136 -0
- package/lib/input/actions.d.ts.map +1 -0
- package/lib/input/actions.js +740 -0
- package/lib/input/actions.js.map +1 -0
- package/lib/input/keymap-settings.d.ts +21 -0
- package/lib/input/keymap-settings.d.ts.map +1 -0
- package/lib/input/keymap-settings.js +28 -0
- package/lib/input/keymap-settings.js.map +1 -0
- package/lib/input/keymap.d.ts +91 -0
- package/lib/input/keymap.d.ts.map +1 -0
- package/lib/input/keymap.js +170 -0
- package/lib/input/keymap.js.map +1 -0
- package/lib/input/match.d.ts +10 -0
- package/lib/input/match.d.ts.map +1 -0
- package/lib/input/match.js +83 -0
- package/lib/input/match.js.map +1 -0
- package/lib/input/submission.d.ts +8 -1
- package/lib/input/submission.d.ts.map +1 -1
- package/lib/input/submission.js +9 -2
- package/lib/input/submission.js.map +1 -1
- package/lib/input.d.ts +17 -0
- package/lib/input.d.ts.map +1 -0
- package/lib/input.js +27 -0
- package/lib/input.js.map +1 -0
- package/lib/keys-command.d.ts +16 -0
- package/lib/keys-command.d.ts.map +1 -0
- package/lib/keys-command.js +60 -0
- package/lib/keys-command.js.map +1 -0
- package/lib/queue.d.ts +6 -0
- package/lib/queue.d.ts.map +1 -0
- package/lib/queue.js +68 -0
- package/lib/queue.js.map +1 -0
- package/lib/settings-notice.d.ts +19 -0
- package/lib/settings-notice.d.ts.map +1 -0
- package/lib/settings-notice.js +30 -0
- package/lib/settings-notice.js.map +1 -0
- package/lib/terminal/warning-screen.d.ts +8 -0
- package/lib/terminal/warning-screen.d.ts.map +1 -0
- package/lib/terminal/warning-screen.js +66 -0
- package/lib/terminal/warning-screen.js.map +1 -0
- package/lib/theme-capability.d.ts +36 -0
- package/lib/theme-capability.d.ts.map +1 -0
- package/lib/theme-capability.js +190 -0
- package/lib/theme-capability.js.map +1 -0
- package/lib/theme-command.d.ts +10 -0
- package/lib/theme-command.d.ts.map +1 -0
- package/lib/theme-command.js +61 -0
- package/lib/theme-command.js.map +1 -0
- package/lib/theme-settings.d.ts +196 -0
- package/lib/theme-settings.d.ts.map +1 -0
- package/lib/theme-settings.js +229 -0
- package/lib/theme-settings.js.map +1 -0
- package/lib/theme-tokens.d.ts +110 -0
- package/lib/theme-tokens.d.ts.map +1 -0
- package/lib/theme-tokens.js +427 -0
- package/lib/theme-tokens.js.map +1 -0
- package/lib/theme.d.ts +32 -35
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +112 -63
- package/lib/theme.js.map +1 -1
- package/lib/tokens.d.ts +15 -0
- package/lib/tokens.d.ts.map +1 -0
- package/lib/tokens.js +29 -0
- package/lib/tokens.js.map +1 -0
- package/lib/transcript.d.ts +26 -1
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +153 -25
- package/lib/transcript.js.map +1 -1
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +67 -28
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts +51 -0
- package/lib/ui/editor.d.ts.map +1 -0
- package/lib/ui/editor.js +159 -0
- package/lib/ui/editor.js.map +1 -0
- package/lib/ui/frame.d.ts +54 -0
- package/lib/ui/frame.d.ts.map +1 -0
- package/lib/ui/frame.js +79 -0
- package/lib/ui/frame.js.map +1 -0
- package/lib/ui/gate-input.d.ts +20 -0
- package/lib/ui/gate-input.d.ts.map +1 -0
- package/lib/ui/gate-input.js +96 -0
- package/lib/ui/gate-input.js.map +1 -0
- package/lib/ui/markdown.d.ts +19 -2
- package/lib/ui/markdown.d.ts.map +1 -1
- package/lib/ui/markdown.js +37 -6
- package/lib/ui/markdown.js.map +1 -1
- package/lib/ui/mermaid.d.ts +44 -0
- package/lib/ui/mermaid.d.ts.map +1 -0
- package/lib/ui/mermaid.js +178 -0
- package/lib/ui/mermaid.js.map +1 -0
- package/lib/ui/picker.d.ts +66 -7
- package/lib/ui/picker.d.ts.map +1 -1
- package/lib/ui/picker.js +112 -19
- package/lib/ui/picker.js.map +1 -1
- package/lib/ui/prompt.d.ts +30 -0
- package/lib/ui/prompt.d.ts.map +1 -0
- package/lib/ui/prompt.js +45 -0
- package/lib/ui/prompt.js.map +1 -0
- package/lib/ui/queue.d.ts +24 -0
- package/lib/ui/queue.d.ts.map +1 -0
- package/lib/ui/queue.js +57 -0
- package/lib/ui/queue.js.map +1 -0
- package/lib/ui/status.d.ts +7 -1
- package/lib/ui/status.d.ts.map +1 -1
- package/lib/ui/status.js +84 -24
- package/lib/ui/status.js.map +1 -1
- package/lib/ui/view.d.ts +65 -2
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +319 -59
- package/lib/ui/view.js.map +1 -1
- package/lib/work.d.ts +48 -0
- package/lib/work.d.ts.map +1 -1
- package/lib/work.js +44 -0
- package/lib/work.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Marked, visibleWidth } from '@earendil-works/pi-tui';
|
|
2
|
+
import { render } from 'lovely-mermaid';
|
|
3
|
+
/** The one fence language that asks for a drawing. */
|
|
4
|
+
const MERMAID_FENCE_LANG = 'mermaid';
|
|
5
|
+
/** The cheap guard before lexing; case-insensitive because a fence may shout. */
|
|
6
|
+
const MERMAID_MENTION = /mermaid/iu;
|
|
7
|
+
/** Drawings kept before the oldest is laid out again; a streaming reply redraws per delta. */
|
|
8
|
+
export const MERMAID_CACHE_LIMIT = 32;
|
|
9
|
+
/**
|
|
10
|
+
* The largest source this surface lays out.
|
|
11
|
+
*
|
|
12
|
+
* Layout is synchronous and happens inside a frame, and a streaming reply asks
|
|
13
|
+
* for it again on every delta, so past this the frame costs more than the
|
|
14
|
+
* drawing is worth and the source stays. Well above what the renderer's own
|
|
15
|
+
* node cap can fill, so no drawing a reader actually sees is kept out.
|
|
16
|
+
*/
|
|
17
|
+
export const MERMAID_MAX_SOURCE = 32 * 1024;
|
|
18
|
+
/** What ends a row without starting a paragraph; two trailing spaces are CommonMark's hard break. */
|
|
19
|
+
const HARD_BREAK = ' \n';
|
|
20
|
+
/** An empty code span has no height, so a blank row stands on a non-breaking space. */
|
|
21
|
+
const BLANK_ROW = '\u00a0';
|
|
22
|
+
const WARNING_LEAD = 'Mermaid diagram not rendered: ';
|
|
23
|
+
const WARNING_MORE = ' (+';
|
|
24
|
+
/** A backtick run inside a row needs a longer delimiter, and a row may hold one inside a label. */
|
|
25
|
+
const BACKTICK_RUN = /`+/gu;
|
|
26
|
+
/**
|
|
27
|
+
* Which element each run of a drawing is, as the token that draws it.
|
|
28
|
+
*
|
|
29
|
+
* The renderer reports what a run *is* and never a colour, so this table is the
|
|
30
|
+
* only place that relates a diagram to the theme; everything else works with
|
|
31
|
+
* roles. Author-assigned classes are deliberately not consulted: a reader's
|
|
32
|
+
* theme is the surface's, not the diagram's.
|
|
33
|
+
*/
|
|
34
|
+
const ROLE_TOKEN = {
|
|
35
|
+
border: 'markdown.diagram.border',
|
|
36
|
+
text: 'markdown.diagram.text',
|
|
37
|
+
edge: 'markdown.diagram.edge',
|
|
38
|
+
edgeLabel: 'markdown.diagram.edgeLabel',
|
|
39
|
+
title: 'markdown.diagram.title',
|
|
40
|
+
};
|
|
41
|
+
function isMermaidFence(token) {
|
|
42
|
+
// The info string may carry more than the language, and a fence may shout.
|
|
43
|
+
return token.type === 'code' && token.lang?.trim().split(/\s+/, 1)[0]?.toLowerCase() === MERMAID_FENCE_LANG;
|
|
44
|
+
}
|
|
45
|
+
/** One drawing row as the code span that keeps its spacing. */
|
|
46
|
+
function codeSpan(row) {
|
|
47
|
+
const content = row === '' ? BLANK_ROW : row;
|
|
48
|
+
let longest = 0;
|
|
49
|
+
// Iterated, not spread: a row can carry more runs than a call holds arguments.
|
|
50
|
+
for (const run of content.matchAll(BACKTICK_RUN)) {
|
|
51
|
+
if (run[0].length > longest)
|
|
52
|
+
longest = run[0].length;
|
|
53
|
+
}
|
|
54
|
+
const fence = '`'.repeat(longest + 1);
|
|
55
|
+
// A row that starts or ends with a backtick would otherwise be read as the delimiter itself.
|
|
56
|
+
const padding = content.startsWith('`') || content.endsWith('`') ? ' ' : '';
|
|
57
|
+
return `${fence}${padding}${content}${padding}${fence}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The columns a drawing really occupies.
|
|
61
|
+
*
|
|
62
|
+
* The renderer measures with its own tables, and they are not always the
|
|
63
|
+
* terminal's: a halfwidth kana plus a combining mark counts one column there
|
|
64
|
+
* and two on screen. The rows are what the reader gets, so the rows decide.
|
|
65
|
+
*/
|
|
66
|
+
function drawnWidth(art) {
|
|
67
|
+
let widest = 0;
|
|
68
|
+
for (const row of art.plain) {
|
|
69
|
+
const columns = visibleWidth(row);
|
|
70
|
+
if (columns > widest)
|
|
71
|
+
widest = columns;
|
|
72
|
+
}
|
|
73
|
+
return widest;
|
|
74
|
+
}
|
|
75
|
+
function warningText(art) {
|
|
76
|
+
const first = art.warnings[0] ?? '';
|
|
77
|
+
const rest = art.warnings.length - 1;
|
|
78
|
+
return `${WARNING_LEAD}${first}${rest > 0 ? `${WARNING_MORE}${rest} more)` : ''}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Lay out each distinct source once.
|
|
82
|
+
*
|
|
83
|
+
* A streaming reply asks for the same fences again on every delta, and laying
|
|
84
|
+
* out a diagram is the expensive half of drawing it; the other half is styling
|
|
85
|
+
* runs, which stays per call so a theme swap needs no invalidation.
|
|
86
|
+
*/
|
|
87
|
+
function artCache() {
|
|
88
|
+
const drawn = new Map();
|
|
89
|
+
return source => {
|
|
90
|
+
if (drawn.has(source))
|
|
91
|
+
return drawn.get(source) ?? null;
|
|
92
|
+
const art = render(source);
|
|
93
|
+
if (drawn.size >= MERMAID_CACHE_LIMIT) {
|
|
94
|
+
const oldest = drawn.keys().next();
|
|
95
|
+
if (oldest.done !== true)
|
|
96
|
+
drawn.delete(oldest.value);
|
|
97
|
+
}
|
|
98
|
+
drawn.set(source, art);
|
|
99
|
+
return art;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Draw a reply's mermaid fences as terminal art.
|
|
104
|
+
*
|
|
105
|
+
* Replacements are spliced into the message at the offsets the lexer reported,
|
|
106
|
+
* never rebuilt from the tokens: lexing can decide something is not worth a
|
|
107
|
+
* token — a duplicate reference definition, for one — and a message that merely
|
|
108
|
+
* mentions mermaid would then change under a reader who asked for nothing. Text
|
|
109
|
+
* the transform does not draw is copied through byte for byte.
|
|
110
|
+
*
|
|
111
|
+
* A fence is replaced before the markdown is parsed, because that is the only
|
|
112
|
+
* moment the source is still whole: once tokens are flowing the drawing's rows
|
|
113
|
+
* would be re-wrapped as prose and lose the spacing they are made of. Each row
|
|
114
|
+
* is therefore emitted as an inline code span, which the markdown renderer
|
|
115
|
+
* keeps verbatim, and rows are separated by hard breaks so a diagram survives
|
|
116
|
+
* as one block instead of one paragraph.
|
|
117
|
+
*/
|
|
118
|
+
export function createMermaidTransform(options) {
|
|
119
|
+
const parser = new Marked();
|
|
120
|
+
const draw = artCache();
|
|
121
|
+
/**
|
|
122
|
+
* The block a body becomes, held apart from the text on either side.
|
|
123
|
+
*
|
|
124
|
+
* Once drawn, the rows are a paragraph, so a blank line on each side is what
|
|
125
|
+
* stops them joining the prose before them or turning a `---` after them into
|
|
126
|
+
* a heading underline. Source that was not drawn is already a block of its own
|
|
127
|
+
* and is left exactly as written.
|
|
128
|
+
*/
|
|
129
|
+
function isolated(body, before, after) {
|
|
130
|
+
const lead = before === '' || before.endsWith('\n\n') ? '' : '\n';
|
|
131
|
+
return `${lead}${body}${after === '' ? '\n' : '\n\n'}`;
|
|
132
|
+
}
|
|
133
|
+
/** What one fence becomes: art, or its source with the reason it stayed source. */
|
|
134
|
+
function fenceBlock(token, before, after, availableWidth, live) {
|
|
135
|
+
if (token.text.length > MERMAID_MAX_SOURCE)
|
|
136
|
+
return token.raw;
|
|
137
|
+
const art = draw(token.text);
|
|
138
|
+
// A settled drawing that lost part of its source is worth reporting whether
|
|
139
|
+
// or not it would have fit, because the reader is looking at the source.
|
|
140
|
+
if (!live && art !== null && art.warnings.length > 0) {
|
|
141
|
+
const reason = options.theme.style('markdown.diagram.warning', warningText(art));
|
|
142
|
+
return isolated(`${token.raw}\n${codeSpan(reason)}`, before, after);
|
|
143
|
+
}
|
|
144
|
+
if (art === null || drawnWidth(art) > availableWidth)
|
|
145
|
+
return token.raw;
|
|
146
|
+
const rows = art.styled.map(row => row
|
|
147
|
+
.map(span => (span.role === 'none' ? span.text : options.theme.style(ROLE_TOKEN[span.role], span.text)))
|
|
148
|
+
.join(''));
|
|
149
|
+
return isolated(rows.map(codeSpan).join(HARD_BREAK), before, after);
|
|
150
|
+
}
|
|
151
|
+
return (markdown, availableWidth, live) => {
|
|
152
|
+
const mode = options.mode();
|
|
153
|
+
// A reply that is still arriving is only drawn in streaming mode; the other
|
|
154
|
+
// modes wait for the settled text, which is also the only text whose losses
|
|
155
|
+
// are worth reporting.
|
|
156
|
+
if (mode === 'off' || (live && mode !== 'streaming'))
|
|
157
|
+
return markdown;
|
|
158
|
+
// Lexing is the cost this guard avoids: no fence can be present without the word.
|
|
159
|
+
if (!MERMAID_MENTION.test(markdown))
|
|
160
|
+
return markdown;
|
|
161
|
+
let out = '';
|
|
162
|
+
let cursor = 0;
|
|
163
|
+
for (const token of parser.lexer(markdown)) {
|
|
164
|
+
const at = markdown.indexOf(token.raw, cursor);
|
|
165
|
+
// A lexer that rewrote its own input cannot be spliced back into it, and
|
|
166
|
+
// the message is worth more than the drawing: it stays as written.
|
|
167
|
+
if (at < 0)
|
|
168
|
+
return markdown;
|
|
169
|
+
const body = isMermaidFence(token)
|
|
170
|
+
? fenceBlock(token, out, markdown.slice(at + token.raw.length), availableWidth, live)
|
|
171
|
+
: token.raw;
|
|
172
|
+
out += markdown.slice(cursor, at) + body;
|
|
173
|
+
cursor = at + token.raw.length;
|
|
174
|
+
}
|
|
175
|
+
return out + markdown.slice(cursor);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=mermaid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../src/ui/mermaid.ts"],"names":[],"mappings":"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"}
|
package/lib/ui/picker.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type Keymap } from '../input/actions.ts';
|
|
1
2
|
import type { StoredSession } from '../agent/history.ts';
|
|
3
|
+
import { type ModelChoice, type ModelRoute } from '../agent/model.ts';
|
|
2
4
|
import { type PresetSummary } from '../agent/presets.ts';
|
|
3
5
|
/** One selectable row of the picker. */
|
|
4
6
|
export interface PickerRow {
|
|
@@ -34,10 +36,15 @@ export type PickerAction = {
|
|
|
34
36
|
* window stays around the cursor instead, and the counts say what is hidden.
|
|
35
37
|
*/
|
|
36
38
|
export declare const PICKER_WINDOW = 12;
|
|
37
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* The hint lines a list uses when it is empty and when it holds rows.
|
|
41
|
+
*
|
|
42
|
+
* Read at paint time rather than built once, because a settings edit while the
|
|
43
|
+
* list is open moves the keys the hint names.
|
|
44
|
+
*/
|
|
38
45
|
export interface PickerHints {
|
|
39
|
-
readonly empty: string;
|
|
40
|
-
readonly listed: string;
|
|
46
|
+
readonly empty: () => string;
|
|
47
|
+
readonly listed: () => string;
|
|
41
48
|
}
|
|
42
49
|
/** Human age of a session, so a list of ids becomes a list of moments. */
|
|
43
50
|
export declare function describeAge(createdAt: number, now: number): string;
|
|
@@ -59,6 +66,8 @@ export declare class ListPicker<Row> {
|
|
|
59
66
|
/** Extra text the filter matches besides the row's own label. */
|
|
60
67
|
private readonly haystackOf;
|
|
61
68
|
private readonly hints;
|
|
69
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
70
|
+
private readonly keys;
|
|
62
71
|
private cursor;
|
|
63
72
|
private filter;
|
|
64
73
|
private note;
|
|
@@ -66,8 +75,10 @@ export declare class ListPicker<Row> {
|
|
|
66
75
|
/** The value a pick settles on. */
|
|
67
76
|
idOf: (row: Row) => string, describe: (row: Row) => PickerRow,
|
|
68
77
|
/** Extra text the filter matches besides the row's own label. */
|
|
69
|
-
haystackOf: (row: Row) => string, hints: PickerHints
|
|
70
|
-
/**
|
|
78
|
+
haystackOf: (row: Row) => string, hints: PickerHints,
|
|
79
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
80
|
+
keys: () => Keymap);
|
|
81
|
+
/** Rows matching the typed filter, best match first. */
|
|
71
82
|
visible(): readonly Row[];
|
|
72
83
|
/**
|
|
73
84
|
* Say why the row under the cursor cannot be taken.
|
|
@@ -89,7 +100,7 @@ export declare class ListPicker<Row> {
|
|
|
89
100
|
* first paint would make opening the picker as slow as the slowest session.
|
|
90
101
|
*/
|
|
91
102
|
export declare class SessionPicker extends ListPicker<StoredSession> {
|
|
92
|
-
constructor(sessions: readonly StoredSession[], titles: () => ReadonlyMap<string, string>, now
|
|
103
|
+
constructor(sessions: readonly StoredSession[], titles: () => ReadonlyMap<string, string>, now: (() => number) | undefined, keys: () => Keymap);
|
|
93
104
|
}
|
|
94
105
|
/**
|
|
95
106
|
* One agent preset chosen by key press.
|
|
@@ -98,6 +109,54 @@ export declare class SessionPicker extends ListPicker<StoredSession> {
|
|
|
98
109
|
* the picker is open is present or gone without reopening it.
|
|
99
110
|
*/
|
|
100
111
|
export declare class PresetPicker extends ListPicker<PresetSummary> {
|
|
101
|
-
constructor(presets: () => readonly PresetSummary[], currentId: () => string | undefined);
|
|
112
|
+
constructor(presets: () => readonly PresetSummary[], currentId: () => string | undefined, keys: () => Keymap);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* One configured model route chosen by key press.
|
|
116
|
+
*
|
|
117
|
+
* Rows are the caller's and are re-read on every key and paint, so a provider
|
|
118
|
+
* whose model list arrives after the picker opened appears in it without
|
|
119
|
+
* reopening, and the filter the reader already typed applies to those late
|
|
120
|
+
* rows too.
|
|
121
|
+
*/
|
|
122
|
+
export declare class ModelPicker extends ListPicker<ModelRoute> {
|
|
123
|
+
constructor(routes: () => readonly ModelRoute[], current: () => ModelChoice | undefined, keys: () => Keymap);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The pick id that clears an explicit effort.
|
|
127
|
+
*
|
|
128
|
+
* An absent effort is a real choice — it restores the model's own default — so
|
|
129
|
+
* it needs an id, and no adapter-owned effort may be empty.
|
|
130
|
+
*/
|
|
131
|
+
export declare const PROVIDER_DEFAULT_EFFORT_ID = "";
|
|
132
|
+
/** One reasoning level a route offers, as the picker shows it. */
|
|
133
|
+
export interface EffortChoice {
|
|
134
|
+
readonly id: string;
|
|
135
|
+
readonly name: string;
|
|
136
|
+
readonly description?: string;
|
|
137
|
+
/** Whether this is the effort in force, which the row says in words. */
|
|
138
|
+
readonly current: boolean;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Turn a route's advertised levels into picker rows.
|
|
142
|
+
*
|
|
143
|
+
* The provider default always leads, because clearing an explicit effort is a
|
|
144
|
+
* choice in its own right: the reader who raised it must be able to put it back
|
|
145
|
+
* without knowing what the adapter would otherwise send.
|
|
146
|
+
*/
|
|
147
|
+
export declare function effortChoices(efforts: readonly {
|
|
148
|
+
readonly id: string;
|
|
149
|
+
readonly name: string;
|
|
150
|
+
readonly description?: string;
|
|
151
|
+
}[], effective: string | undefined): readonly EffortChoice[];
|
|
152
|
+
/**
|
|
153
|
+
* One reasoning effort chosen by key press.
|
|
154
|
+
*
|
|
155
|
+
* The levels are fixed once the reader asks for the list, because they come
|
|
156
|
+
* from the route that was in force when the picker opened; the route itself
|
|
157
|
+
* cannot change while the list owns the keyboard.
|
|
158
|
+
*/
|
|
159
|
+
export declare class EffortPicker extends ListPicker<EffortChoice> {
|
|
160
|
+
constructor(choices: () => readonly EffortChoice[], heading: string, keys: () => Keymap);
|
|
102
161
|
}
|
|
103
162
|
//# sourceMappingURL=picker.d.ts.map
|
package/lib/ui/picker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["../../src/ui/picker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExE,wCAAwC;AACxC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,iDAAiD;AACjD,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE/B;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B
|
|
1
|
+
{"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["../../src/ui/picker.ts"],"names":[],"mappings":"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"}
|
package/lib/ui/picker.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { matchesKey } from '@earendil-works/pi-tui';
|
|
2
|
+
import { hintKeys, matchesAction, moveHint } from "../input/actions.js";
|
|
3
|
+
import { pastedText } from "../input.js";
|
|
4
|
+
import { matchScore } from "../input/match.js";
|
|
5
|
+
import { describeModelRoute, modelRouteKey } from "../agent/model.js";
|
|
2
6
|
import { describePreset } from "../agent/presets.js";
|
|
3
7
|
/**
|
|
4
8
|
* Rows the picker shows at once.
|
|
@@ -38,6 +42,7 @@ export class ListPicker {
|
|
|
38
42
|
describe;
|
|
39
43
|
haystackOf;
|
|
40
44
|
hints;
|
|
45
|
+
keys;
|
|
41
46
|
cursor = 0;
|
|
42
47
|
filter = '';
|
|
43
48
|
note;
|
|
@@ -45,20 +50,29 @@ export class ListPicker {
|
|
|
45
50
|
/** The value a pick settles on. */
|
|
46
51
|
idOf, describe,
|
|
47
52
|
/** Extra text the filter matches besides the row's own label. */
|
|
48
|
-
haystackOf, hints
|
|
53
|
+
haystackOf, hints,
|
|
54
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
55
|
+
keys) {
|
|
49
56
|
this.source = source;
|
|
50
57
|
this.heading = heading;
|
|
51
58
|
this.idOf = idOf;
|
|
52
59
|
this.describe = describe;
|
|
53
60
|
this.haystackOf = haystackOf;
|
|
54
61
|
this.hints = hints;
|
|
62
|
+
this.keys = keys;
|
|
55
63
|
}
|
|
56
|
-
/** Rows matching the typed filter,
|
|
64
|
+
/** Rows matching the typed filter, best match first. */
|
|
57
65
|
visible() {
|
|
58
|
-
const needle = this.filter.trim()
|
|
66
|
+
const needle = this.filter.trim();
|
|
59
67
|
if (needle === '')
|
|
60
68
|
return this.source();
|
|
61
|
-
|
|
69
|
+
// Ties keep the order the caller listed them in, so rows do not shuffle
|
|
70
|
+
// under the cursor while the reader is still typing.
|
|
71
|
+
return this.source()
|
|
72
|
+
.map(row => ({ row, score: matchScore(needle, this.haystackOf(row)) }))
|
|
73
|
+
.filter((entry) => entry.score !== undefined)
|
|
74
|
+
.sort((left, right) => right.score - left.score)
|
|
75
|
+
.map(entry => entry.row);
|
|
62
76
|
}
|
|
63
77
|
/**
|
|
64
78
|
* Say why the row under the cursor cannot be taken.
|
|
@@ -74,17 +88,20 @@ export class ListPicker {
|
|
|
74
88
|
handleKey(data) {
|
|
75
89
|
this.note = undefined;
|
|
76
90
|
const rows = this.visible();
|
|
77
|
-
|
|
91
|
+
// A picker owns the keyboard while it is open, so the interrupt key has to
|
|
92
|
+
// mean "leave this list" here: swallowing it would strand the reader.
|
|
93
|
+
const keys = this.keys();
|
|
94
|
+
if (matchesAction(keys, 'picker.cancel', data))
|
|
78
95
|
return { kind: 'cancel' };
|
|
79
|
-
if (
|
|
96
|
+
if (matchesAction(keys, 'picker.confirm', data)) {
|
|
80
97
|
const chosen = rows[Math.min(this.cursor, Math.max(0, rows.length - 1))];
|
|
81
98
|
return chosen === undefined ? undefined : { kind: 'pick', id: this.idOf(chosen) };
|
|
82
99
|
}
|
|
83
|
-
if (
|
|
100
|
+
if (matchesAction(keys, 'picker.up', data)) {
|
|
84
101
|
this.cursor = Math.max(0, this.cursor - 1);
|
|
85
102
|
return undefined;
|
|
86
103
|
}
|
|
87
|
-
if (
|
|
104
|
+
if (matchesAction(keys, 'picker.down', data)) {
|
|
88
105
|
this.cursor = Math.min(Math.max(0, rows.length - 1), this.cursor + 1);
|
|
89
106
|
return undefined;
|
|
90
107
|
}
|
|
@@ -98,8 +115,9 @@ export class ListPicker {
|
|
|
98
115
|
this.cursor = 0;
|
|
99
116
|
return undefined;
|
|
100
117
|
}
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
const text = pastedText(data) ?? (data.length === 1 && data >= ' ' ? data : undefined);
|
|
119
|
+
if (text !== undefined) {
|
|
120
|
+
this.filter += text;
|
|
103
121
|
this.cursor = 0;
|
|
104
122
|
}
|
|
105
123
|
return undefined;
|
|
@@ -119,7 +137,7 @@ export class ListPicker {
|
|
|
119
137
|
above: start,
|
|
120
138
|
below: Math.max(0, rows.length - start - window.length),
|
|
121
139
|
filter: this.filter,
|
|
122
|
-
hint: rows.length === 0 ? this.hints.empty : this.hints.listed,
|
|
140
|
+
hint: rows.length === 0 ? this.hints.empty() : this.hints.listed(),
|
|
123
141
|
};
|
|
124
142
|
}
|
|
125
143
|
}
|
|
@@ -131,7 +149,7 @@ export class ListPicker {
|
|
|
131
149
|
* first paint would make opening the picker as slow as the slowest session.
|
|
132
150
|
*/
|
|
133
151
|
export class SessionPicker extends ListPicker {
|
|
134
|
-
constructor(sessions, titles, now = () => Date.now()) {
|
|
152
|
+
constructor(sessions, titles, now = () => Date.now(), keys) {
|
|
135
153
|
const labelOf = (session) => titles().get(session.id) ?? session.id;
|
|
136
154
|
super(() => sessions, () => `resume a session · ${sessions.length} stored`, session => session.id, session => ({
|
|
137
155
|
label: labelOf(session),
|
|
@@ -143,9 +161,9 @@ export class SessionPicker extends ListPicker {
|
|
|
143
161
|
// The card marks the row under the cursor, which the list decides.
|
|
144
162
|
current: false,
|
|
145
163
|
}), session => [labelOf(session), session.id, session.cwd ?? ''].join(' '), {
|
|
146
|
-
empty:
|
|
147
|
-
listed: '
|
|
148
|
-
});
|
|
164
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
165
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} open · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
166
|
+
}, keys);
|
|
149
167
|
}
|
|
150
168
|
}
|
|
151
169
|
/**
|
|
@@ -155,11 +173,86 @@ export class SessionPicker extends ListPicker {
|
|
|
155
173
|
* the picker is open is present or gone without reopening it.
|
|
156
174
|
*/
|
|
157
175
|
export class PresetPicker extends ListPicker {
|
|
158
|
-
constructor(presets, currentId) {
|
|
176
|
+
constructor(presets, currentId, keys) {
|
|
159
177
|
super(presets, () => `agent preset · ${presets().length} available`, preset => preset.id, preset => describePreset(preset, currentId()), preset => [preset.id, preset.name ?? '', preset.description ?? ''].join(' '), {
|
|
160
|
-
empty:
|
|
161
|
-
listed: '
|
|
162
|
-
});
|
|
178
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
179
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} switch · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
180
|
+
}, keys);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* One configured model route chosen by key press.
|
|
185
|
+
*
|
|
186
|
+
* Rows are the caller's and are re-read on every key and paint, so a provider
|
|
187
|
+
* whose model list arrives after the picker opened appears in it without
|
|
188
|
+
* reopening, and the filter the reader already typed applies to those late
|
|
189
|
+
* rows too.
|
|
190
|
+
*/
|
|
191
|
+
export class ModelPicker extends ListPicker {
|
|
192
|
+
constructor(routes, current, keys) {
|
|
193
|
+
super(routes, () => {
|
|
194
|
+
const chosen = current();
|
|
195
|
+
if (chosen === undefined)
|
|
196
|
+
return 'model · no route in use';
|
|
197
|
+
const effort = chosen.reasoningEffort === undefined ? '' : ` (${chosen.reasoningEffort})`;
|
|
198
|
+
return `model · current ${chosen.provider}/${chosen.model}${effort}`;
|
|
199
|
+
}, route => modelRouteKey(route), route => describeModelRoute(route, current()), route => [route.provider, route.model, route.name].join(' '), {
|
|
200
|
+
empty: () => `nothing matched · /model <provider>/<model> takes any id · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
201
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} switch · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
202
|
+
}, keys);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The pick id that clears an explicit effort.
|
|
207
|
+
*
|
|
208
|
+
* An absent effort is a real choice — it restores the model's own default — so
|
|
209
|
+
* it needs an id, and no adapter-owned effort may be empty.
|
|
210
|
+
*/
|
|
211
|
+
export const PROVIDER_DEFAULT_EFFORT_ID = '';
|
|
212
|
+
/**
|
|
213
|
+
* Turn a route's advertised levels into picker rows.
|
|
214
|
+
*
|
|
215
|
+
* The provider default always leads, because clearing an explicit effort is a
|
|
216
|
+
* choice in its own right: the reader who raised it must be able to put it back
|
|
217
|
+
* without knowing what the adapter would otherwise send.
|
|
218
|
+
*/
|
|
219
|
+
export function effortChoices(efforts, effective) {
|
|
220
|
+
return [
|
|
221
|
+
{
|
|
222
|
+
id: PROVIDER_DEFAULT_EFFORT_ID,
|
|
223
|
+
name: 'provider default',
|
|
224
|
+
description: 'clear the explicit effort',
|
|
225
|
+
current: effective === undefined,
|
|
226
|
+
},
|
|
227
|
+
...efforts.map(effort => ({
|
|
228
|
+
id: effort.id,
|
|
229
|
+
name: effort.name,
|
|
230
|
+
...(effort.description === undefined ? {} : { description: effort.description }),
|
|
231
|
+
current: effort.id === effective,
|
|
232
|
+
})),
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* One reasoning effort chosen by key press.
|
|
237
|
+
*
|
|
238
|
+
* The levels are fixed once the reader asks for the list, because they come
|
|
239
|
+
* from the route that was in force when the picker opened; the route itself
|
|
240
|
+
* cannot change while the list owns the keyboard.
|
|
241
|
+
*/
|
|
242
|
+
export class EffortPicker extends ListPicker {
|
|
243
|
+
constructor(choices, heading, keys) {
|
|
244
|
+
super(choices, () => heading, choice => choice.id, choice => ({
|
|
245
|
+
label: choice.name,
|
|
246
|
+
description: [
|
|
247
|
+
choice.description,
|
|
248
|
+
choice.id !== choice.name ? choice.id : undefined,
|
|
249
|
+
choice.current ? 'current' : undefined,
|
|
250
|
+
].filter(part => part !== undefined && part !== '').join(' · ') || undefined,
|
|
251
|
+
current: choice.current,
|
|
252
|
+
}), choice => [choice.name, choice.id, choice.description ?? ''].join(' '), {
|
|
253
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
254
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} apply · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
255
|
+
}, keys);
|
|
163
256
|
}
|
|
164
257
|
}
|
|
165
258
|
//# sourceMappingURL=picker.js.map
|
package/lib/ui/picker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"picker.js","sourceRoot":"","sources":["../../src/ui/picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"picker.js","sourceRoot":"","sources":["../../src/ui/picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Component } from '@earendil-works/pi-tui';
|
|
2
|
+
import type { BoxedEditor } from './editor.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The prompt bar, and the question that borrows it.
|
|
5
|
+
*
|
|
6
|
+
* A question is answered in the reader's own editor, because that is the one
|
|
7
|
+
* with everything they expect of it — completion, history, undo, and the keys
|
|
8
|
+
* their terminal sends — so the question takes the bar rather than a copy of it.
|
|
9
|
+
* The bar hides while the question is open, and the prompt nobody has sent yet
|
|
10
|
+
* is held aside and put back afterwards.
|
|
11
|
+
*/
|
|
12
|
+
export declare class PromptBar implements Component {
|
|
13
|
+
private readonly editor;
|
|
14
|
+
private borrowed;
|
|
15
|
+
private held;
|
|
16
|
+
constructor(editor: BoxedEditor);
|
|
17
|
+
/**
|
|
18
|
+
* Borrow the editor for a gate that collects answers in it.
|
|
19
|
+
*
|
|
20
|
+
* The builder runs after the prompt is held aside, because a gate empties the
|
|
21
|
+
* editor for its first answer as it is built, and a prompt is not an answer.
|
|
22
|
+
*/
|
|
23
|
+
borrow<T>(build: () => T): T;
|
|
24
|
+
/** Give the editor back, with the prompt that was in it. */
|
|
25
|
+
giveBack(): void;
|
|
26
|
+
/** The rows the bar occupies, which a borrowing question leaves empty. */
|
|
27
|
+
render(width: number): string[];
|
|
28
|
+
invalidate(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/ui/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C;;;;;;;;GAQG;AACH,qBAAa,SAAU,YAAW,SAAS;IAI7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,IAAI,CAAK;gBAEY,MAAM,EAAE,WAAW;IAEhD;;;;;OAKG;IACH,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;IAO5B,4DAA4D;IAC5D,QAAQ,IAAI,IAAI;IAOhB,0EAA0E;IAC1E,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAI/B,UAAU,IAAI,IAAI;CAGnB"}
|
package/lib/ui/prompt.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The prompt bar, and the question that borrows it.
|
|
3
|
+
*
|
|
4
|
+
* A question is answered in the reader's own editor, because that is the one
|
|
5
|
+
* with everything they expect of it — completion, history, undo, and the keys
|
|
6
|
+
* their terminal sends — so the question takes the bar rather than a copy of it.
|
|
7
|
+
* The bar hides while the question is open, and the prompt nobody has sent yet
|
|
8
|
+
* is held aside and put back afterwards.
|
|
9
|
+
*/
|
|
10
|
+
export class PromptBar {
|
|
11
|
+
editor;
|
|
12
|
+
borrowed = false;
|
|
13
|
+
held = '';
|
|
14
|
+
constructor(editor) {
|
|
15
|
+
this.editor = editor;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Borrow the editor for a gate that collects answers in it.
|
|
19
|
+
*
|
|
20
|
+
* The builder runs after the prompt is held aside, because a gate empties the
|
|
21
|
+
* editor for its first answer as it is built, and a prompt is not an answer.
|
|
22
|
+
*/
|
|
23
|
+
borrow(build) {
|
|
24
|
+
this.held = this.editor.getExpandedText();
|
|
25
|
+
this.editor.setText('');
|
|
26
|
+
this.borrowed = true;
|
|
27
|
+
return build();
|
|
28
|
+
}
|
|
29
|
+
/** Give the editor back, with the prompt that was in it. */
|
|
30
|
+
giveBack() {
|
|
31
|
+
if (!this.borrowed)
|
|
32
|
+
return;
|
|
33
|
+
this.borrowed = false;
|
|
34
|
+
this.editor.setText(this.held);
|
|
35
|
+
this.held = '';
|
|
36
|
+
}
|
|
37
|
+
/** The rows the bar occupies, which a borrowing question leaves empty. */
|
|
38
|
+
render(width) {
|
|
39
|
+
return this.borrowed ? [] : this.editor.render(width);
|
|
40
|
+
}
|
|
41
|
+
invalidate() {
|
|
42
|
+
this.editor.invalidate();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/ui/prompt.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IAIS;IAHrB,QAAQ,GAAG,KAAK,CAAA;IAChB,IAAI,GAAG,EAAE,CAAA;IAEjB,YAA6B,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAEpD;;;;;OAKG;IACH,MAAM,CAAI,KAAc;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAA;QACzC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,OAAO,KAAK,EAAE,CAAA;IAChB,CAAC;IAED,4DAA4D;IAC5D,QAAQ;QACN,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAC1B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;IAChB,CAAC;IAED,0EAA0E;IAC1E,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAA;IAC1B,CAAC;CACF"}
|