@sagmans/dsh-tui 0.2.0 → 0.4.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 +282 -25
- package/cordis.patch.yml +14 -0
- package/lib/agent/model.d.ts +26 -0
- package/lib/agent/model.d.ts.map +1 -1
- package/lib/agent/model.js +41 -0
- package/lib/agent/model.js.map +1 -1
- package/lib/agent/projections.d.ts +22 -6
- package/lib/agent/projections.d.ts.map +1 -1
- package/lib/agent/projections.js +21 -10
- package/lib/agent/projections.js.map +1 -1
- package/lib/agent/prompt-history.d.ts +89 -0
- package/lib/agent/prompt-history.d.ts.map +1 -0
- package/lib/agent/prompt-history.js +380 -0
- package/lib/agent/prompt-history.js.map +1 -0
- package/lib/agent/status.d.ts +16 -0
- package/lib/agent/status.d.ts.map +1 -1
- package/lib/agent/status.js +3 -0
- package/lib/agent/status.js.map +1 -1
- package/lib/cards.d.ts +1 -1
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +4 -3
- package/lib/cards.js.map +1 -1
- 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/herdr/client.d.ts +57 -0
- package/lib/herdr/client.d.ts.map +1 -0
- package/lib/herdr/client.js +218 -0
- package/lib/herdr/client.js.map +1 -0
- package/lib/herdr/constants.d.ts +93 -0
- package/lib/herdr/constants.d.ts.map +1 -0
- package/lib/herdr/constants.js +79 -0
- package/lib/herdr/constants.js.map +1 -0
- package/lib/herdr/reporter.d.ts +60 -0
- package/lib/herdr/reporter.d.ts.map +1 -0
- package/lib/herdr/reporter.js +217 -0
- package/lib/herdr/reporter.js.map +1 -0
- package/lib/herdr/state.d.ts +57 -0
- package/lib/herdr/state.d.ts.map +1 -0
- package/lib/herdr/state.js +62 -0
- package/lib/herdr/state.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +631 -118
- 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 +743 -0
- package/lib/input/actions.js.map +1 -0
- package/lib/input/ghost.d.ts +46 -0
- package/lib/input/ghost.d.ts.map +1 -0
- package/lib/input/ghost.js +58 -0
- package/lib/input/ghost.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 +172 -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 +29 -1
- package/lib/input/submission.d.ts.map +1 -1
- package/lib/input/submission.js +33 -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/stash/lock.d.ts +72 -0
- package/lib/stash/lock.d.ts.map +1 -0
- package/lib/stash/lock.js +374 -0
- package/lib/stash/lock.js.map +1 -0
- package/lib/stash/paths.d.ts +22 -0
- package/lib/stash/paths.d.ts.map +1 -0
- package/lib/stash/paths.js +83 -0
- package/lib/stash/paths.js.map +1 -0
- package/lib/stash/private-fs.d.ts +61 -0
- package/lib/stash/private-fs.d.ts.map +1 -0
- package/lib/stash/private-fs.js +379 -0
- package/lib/stash/private-fs.js.map +1 -0
- package/lib/stash/schema.d.ts +57 -0
- package/lib/stash/schema.d.ts.map +1 -0
- package/lib/stash/schema.js +127 -0
- package/lib/stash/schema.js.map +1 -0
- package/lib/stash/store.d.ts +92 -0
- package/lib/stash/store.d.ts.map +1 -0
- package/lib/stash/store.js +262 -0
- package/lib/stash/store.js.map +1 -0
- package/lib/stash.d.ts +91 -0
- package/lib/stash.d.ts.map +1 -0
- package/lib/stash.js +296 -0
- package/lib/stash.js.map +1 -0
- package/lib/theme-settings.d.ts +72 -8
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +125 -5
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +4 -4
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +39 -5
- package/lib/theme-tokens.js.map +1 -1
- package/lib/todo-guard.d.ts +116 -0
- package/lib/todo-guard.d.ts.map +1 -0
- package/lib/todo-guard.js +259 -0
- package/lib/todo-guard.js.map +1 -0
- package/lib/ui/editor.d.ts +58 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +174 -19
- package/lib/ui/editor.js.map +1 -1
- 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/history-picker.d.ts +15 -0
- package/lib/ui/history-picker.d.ts.map +1 -0
- package/lib/ui/history-picker.js +26 -0
- package/lib/ui/history-picker.js.map +1 -0
- package/lib/ui/markdown.d.ts +11 -2
- package/lib/ui/markdown.d.ts.map +1 -1
- package/lib/ui/markdown.js +25 -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 +40 -8
- package/lib/ui/picker.d.ts.map +1 -1
- package/lib/ui/picker.js +79 -24
- package/lib/ui/picker.js.map +1 -1
- package/lib/ui/prompt.d.ts +32 -0
- package/lib/ui/prompt.d.ts.map +1 -0
- package/lib/ui/prompt.js +49 -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/stash-picker.d.ts +43 -0
- package/lib/ui/stash-picker.d.ts.map +1 -0
- package/lib/ui/stash-picker.js +78 -0
- package/lib/ui/stash-picker.js.map +1 -0
- package/lib/ui/status.d.ts +6 -0
- package/lib/ui/status.d.ts.map +1 -1
- package/lib/ui/status.js +15 -0
- package/lib/ui/status.js.map +1 -1
- package/lib/ui/view.d.ts +22 -2
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +84 -24
- package/lib/ui/view.js.map +1 -1
- package/lib/work.d.ts +51 -1
- package/lib/work.d.ts.map +1 -1
- package/lib/work.js +53 -1
- package/lib/work.js.map +1 -1
- package/package.json +7 -2
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.
|
|
@@ -8,6 +12,18 @@ import { describePreset } from "../agent/presets.js";
|
|
|
8
12
|
* window stays around the cursor instead, and the counts say what is hidden.
|
|
9
13
|
*/
|
|
10
14
|
export const PICKER_WINDOW = 12;
|
|
15
|
+
/** Runs of whitespace, including the newlines a seeded draft or a paste can carry. */
|
|
16
|
+
const WHITESPACE = /\s+/gu;
|
|
17
|
+
/**
|
|
18
|
+
* Fold a value onto one drawn row.
|
|
19
|
+
*
|
|
20
|
+
* A filter can be seeded from a multiline draft or typed through a paste, and a
|
|
21
|
+
* raw newline inside a row would push the frame's own accounting apart; the
|
|
22
|
+
* needle the list matches with stays untouched.
|
|
23
|
+
*/
|
|
24
|
+
export function singleLine(text) {
|
|
25
|
+
return text.replace(WHITESPACE, ' ').trim();
|
|
26
|
+
}
|
|
11
27
|
const MINUTE_MS = 60_000;
|
|
12
28
|
const HOUR_MS = 60 * MINUTE_MS;
|
|
13
29
|
const DAY_MS = 24 * HOUR_MS;
|
|
@@ -38,6 +54,7 @@ export class ListPicker {
|
|
|
38
54
|
describe;
|
|
39
55
|
haystackOf;
|
|
40
56
|
hints;
|
|
57
|
+
keys;
|
|
41
58
|
cursor = 0;
|
|
42
59
|
filter = '';
|
|
43
60
|
note;
|
|
@@ -45,20 +62,32 @@ export class ListPicker {
|
|
|
45
62
|
/** The value a pick settles on. */
|
|
46
63
|
idOf, describe,
|
|
47
64
|
/** Extra text the filter matches besides the row's own label. */
|
|
48
|
-
haystackOf, hints
|
|
65
|
+
haystackOf, hints,
|
|
66
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
67
|
+
keys,
|
|
68
|
+
/** A draft to open already filtered by, so a search can start where the reader is. */
|
|
69
|
+
initialFilter = '') {
|
|
49
70
|
this.source = source;
|
|
50
71
|
this.heading = heading;
|
|
51
72
|
this.idOf = idOf;
|
|
52
73
|
this.describe = describe;
|
|
53
74
|
this.haystackOf = haystackOf;
|
|
54
75
|
this.hints = hints;
|
|
76
|
+
this.keys = keys;
|
|
77
|
+
this.filter = initialFilter;
|
|
55
78
|
}
|
|
56
|
-
/** Rows matching the typed filter,
|
|
79
|
+
/** Rows matching the typed filter, best match first. */
|
|
57
80
|
visible() {
|
|
58
|
-
const needle = this.filter.trim()
|
|
81
|
+
const needle = this.filter.trim();
|
|
59
82
|
if (needle === '')
|
|
60
83
|
return this.source();
|
|
61
|
-
|
|
84
|
+
// Ties keep the order the caller listed them in, so rows do not shuffle
|
|
85
|
+
// under the cursor while the reader is still typing.
|
|
86
|
+
return this.source()
|
|
87
|
+
.map(row => ({ row, score: matchScore(needle, this.haystackOf(row)) }))
|
|
88
|
+
.filter((entry) => entry.score !== undefined)
|
|
89
|
+
.sort((left, right) => right.score - left.score)
|
|
90
|
+
.map(entry => entry.row);
|
|
62
91
|
}
|
|
63
92
|
/**
|
|
64
93
|
* Say why the row under the cursor cannot be taken.
|
|
@@ -74,17 +103,20 @@ export class ListPicker {
|
|
|
74
103
|
handleKey(data) {
|
|
75
104
|
this.note = undefined;
|
|
76
105
|
const rows = this.visible();
|
|
77
|
-
|
|
106
|
+
// A picker owns the keyboard while it is open, so the interrupt key has to
|
|
107
|
+
// mean "leave this list" here: swallowing it would strand the reader.
|
|
108
|
+
const keys = this.keys();
|
|
109
|
+
if (matchesAction(keys, 'picker.cancel', data))
|
|
78
110
|
return { kind: 'cancel' };
|
|
79
|
-
if (
|
|
111
|
+
if (matchesAction(keys, 'picker.confirm', data)) {
|
|
80
112
|
const chosen = rows[Math.min(this.cursor, Math.max(0, rows.length - 1))];
|
|
81
113
|
return chosen === undefined ? undefined : { kind: 'pick', id: this.idOf(chosen) };
|
|
82
114
|
}
|
|
83
|
-
if (
|
|
115
|
+
if (matchesAction(keys, 'picker.up', data)) {
|
|
84
116
|
this.cursor = Math.max(0, this.cursor - 1);
|
|
85
117
|
return undefined;
|
|
86
118
|
}
|
|
87
|
-
if (
|
|
119
|
+
if (matchesAction(keys, 'picker.down', data)) {
|
|
88
120
|
this.cursor = Math.min(Math.max(0, rows.length - 1), this.cursor + 1);
|
|
89
121
|
return undefined;
|
|
90
122
|
}
|
|
@@ -98,8 +130,9 @@ export class ListPicker {
|
|
|
98
130
|
this.cursor = 0;
|
|
99
131
|
return undefined;
|
|
100
132
|
}
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
const text = pastedText(data) ?? (data.length === 1 && data >= ' ' ? data : undefined);
|
|
134
|
+
if (text !== undefined) {
|
|
135
|
+
this.filter += text;
|
|
103
136
|
this.cursor = 0;
|
|
104
137
|
}
|
|
105
138
|
return undefined;
|
|
@@ -118,8 +151,8 @@ export class ListPicker {
|
|
|
118
151
|
})),
|
|
119
152
|
above: start,
|
|
120
153
|
below: Math.max(0, rows.length - start - window.length),
|
|
121
|
-
filter: this.filter,
|
|
122
|
-
hint: rows.length === 0 ? this.hints.empty : this.hints.listed,
|
|
154
|
+
filter: singleLine(this.filter),
|
|
155
|
+
hint: rows.length === 0 ? this.hints.empty() : this.hints.listed(),
|
|
123
156
|
};
|
|
124
157
|
}
|
|
125
158
|
}
|
|
@@ -131,7 +164,7 @@ export class ListPicker {
|
|
|
131
164
|
* first paint would make opening the picker as slow as the slowest session.
|
|
132
165
|
*/
|
|
133
166
|
export class SessionPicker extends ListPicker {
|
|
134
|
-
constructor(sessions, titles, now = () => Date.now()) {
|
|
167
|
+
constructor(sessions, titles, now = () => Date.now(), keys) {
|
|
135
168
|
const labelOf = (session) => titles().get(session.id) ?? session.id;
|
|
136
169
|
super(() => sessions, () => `resume a session · ${sessions.length} stored`, session => session.id, session => ({
|
|
137
170
|
label: labelOf(session),
|
|
@@ -143,9 +176,9 @@ export class SessionPicker extends ListPicker {
|
|
|
143
176
|
// The card marks the row under the cursor, which the list decides.
|
|
144
177
|
current: false,
|
|
145
178
|
}), session => [labelOf(session), session.id, session.cwd ?? ''].join(' '), {
|
|
146
|
-
empty:
|
|
147
|
-
listed: '
|
|
148
|
-
});
|
|
179
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
180
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} open · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
181
|
+
}, keys);
|
|
149
182
|
}
|
|
150
183
|
}
|
|
151
184
|
/**
|
|
@@ -155,11 +188,33 @@ export class SessionPicker extends ListPicker {
|
|
|
155
188
|
* the picker is open is present or gone without reopening it.
|
|
156
189
|
*/
|
|
157
190
|
export class PresetPicker extends ListPicker {
|
|
158
|
-
constructor(presets, currentId) {
|
|
191
|
+
constructor(presets, currentId, keys) {
|
|
159
192
|
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
|
-
});
|
|
193
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
194
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} switch · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
195
|
+
}, keys);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* One configured model route chosen by key press.
|
|
200
|
+
*
|
|
201
|
+
* Rows are the caller's and are re-read on every key and paint, so a provider
|
|
202
|
+
* whose model list arrives after the picker opened appears in it without
|
|
203
|
+
* reopening, and the filter the reader already typed applies to those late
|
|
204
|
+
* rows too.
|
|
205
|
+
*/
|
|
206
|
+
export class ModelPicker extends ListPicker {
|
|
207
|
+
constructor(routes, current, keys) {
|
|
208
|
+
super(routes, () => {
|
|
209
|
+
const chosen = current();
|
|
210
|
+
if (chosen === undefined)
|
|
211
|
+
return 'model · no route in use';
|
|
212
|
+
const effort = chosen.reasoningEffort === undefined ? '' : ` (${chosen.reasoningEffort})`;
|
|
213
|
+
return `model · current ${chosen.provider}/${chosen.model}${effort}`;
|
|
214
|
+
}, route => modelRouteKey(route), route => describeModelRoute(route, current()), route => [route.provider, route.model, route.name].join(' '), {
|
|
215
|
+
empty: () => `nothing matched · /model <provider>/<model> takes any id · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
216
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} switch · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
217
|
+
}, keys);
|
|
163
218
|
}
|
|
164
219
|
}
|
|
165
220
|
/**
|
|
@@ -200,7 +255,7 @@ export function effortChoices(efforts, effective) {
|
|
|
200
255
|
* cannot change while the list owns the keyboard.
|
|
201
256
|
*/
|
|
202
257
|
export class EffortPicker extends ListPicker {
|
|
203
|
-
constructor(choices, heading) {
|
|
258
|
+
constructor(choices, heading, keys) {
|
|
204
259
|
super(choices, () => heading, choice => choice.id, choice => ({
|
|
205
260
|
label: choice.name,
|
|
206
261
|
description: [
|
|
@@ -210,9 +265,9 @@ export class EffortPicker extends ListPicker {
|
|
|
210
265
|
].filter(part => part !== undefined && part !== '').join(' · ') || undefined,
|
|
211
266
|
current: choice.current,
|
|
212
267
|
}), choice => [choice.name, choice.id, choice.description ?? ''].join(' '), {
|
|
213
|
-
empty:
|
|
214
|
-
listed: '
|
|
215
|
-
});
|
|
268
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
269
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} apply · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
270
|
+
}, keys);
|
|
216
271
|
}
|
|
217
272
|
}
|
|
218
273
|
//# 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,32 @@
|
|
|
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
|
+
/** Whether the editor is collecting an answer rather than a prompt. */
|
|
25
|
+
isBorrowed(): boolean;
|
|
26
|
+
/** Give the editor back, with the prompt that was in it. */
|
|
27
|
+
giveBack(): void;
|
|
28
|
+
/** The rows the bar occupies, which a borrowing question leaves empty. */
|
|
29
|
+
render(width: number): string[];
|
|
30
|
+
invalidate(): void;
|
|
31
|
+
}
|
|
32
|
+
//# 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,uEAAuE;IACvE,UAAU,IAAI,OAAO;IAIrB,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,49 @@
|
|
|
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
|
+
/** Whether the editor is collecting an answer rather than a prompt. */
|
|
30
|
+
isBorrowed() {
|
|
31
|
+
return this.borrowed;
|
|
32
|
+
}
|
|
33
|
+
/** Give the editor back, with the prompt that was in it. */
|
|
34
|
+
giveBack() {
|
|
35
|
+
if (!this.borrowed)
|
|
36
|
+
return;
|
|
37
|
+
this.borrowed = false;
|
|
38
|
+
this.editor.setText(this.held);
|
|
39
|
+
this.held = '';
|
|
40
|
+
}
|
|
41
|
+
/** The rows the bar occupies, which a borrowing question leaves empty. */
|
|
42
|
+
render(width) {
|
|
43
|
+
return this.borrowed ? [] : this.editor.render(width);
|
|
44
|
+
}
|
|
45
|
+
invalidate() {
|
|
46
|
+
this.editor.invalidate();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# 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,uEAAuE;IACvE,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Component } from '@earendil-works/pi-tui';
|
|
2
|
+
import type { TuiTheme } from '../theme.ts';
|
|
3
|
+
/** Queued prompts the bar draws; everything older becomes one count above them. */
|
|
4
|
+
export declare const QUEUE_LIMIT = 3;
|
|
5
|
+
/** Text rows one queued prompt keeps before its own count takes over. */
|
|
6
|
+
export declare const QUEUE_TEXT_ROWS = 3;
|
|
7
|
+
/**
|
|
8
|
+
* The prompts the agent has not taken yet, drawn above the editor.
|
|
9
|
+
*
|
|
10
|
+
* The rows take the editor's own frame because that is what they are: input the
|
|
11
|
+
* reader already submitted, waiting for the agent to reach it. Only the face
|
|
12
|
+
* differs — faint and italic — so a reader can tell at a glance that the text is
|
|
13
|
+
* waiting rather than being typed.
|
|
14
|
+
*/
|
|
15
|
+
export declare class QueueBar implements Component {
|
|
16
|
+
private readonly prompts;
|
|
17
|
+
private readonly theme;
|
|
18
|
+
constructor(prompts: () => readonly string[], theme: TuiTheme);
|
|
19
|
+
invalidate(): void;
|
|
20
|
+
/** One queued prompt as the editor bar's own box, drawn in the queued face. */
|
|
21
|
+
private box;
|
|
22
|
+
render(width: number): string[];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/ui/queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,mFAAmF;AACnF,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,yEAAyE;AACzE,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC;;;;;;;GAOG;AACH,qBAAa,QAAS,YAAW,SAAS;IAEtC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,OAAO,EAAE,MAAM,SAAS,MAAM,EAAE,EAChC,KAAK,EAAE,QAAQ;IAGlC,UAAU,IAAI,IAAI;IAIlB,+EAA+E;IAC/E,OAAO,CAAC,GAAG;IAUX,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAkBhC"}
|
package/lib/ui/queue.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { canFrame, frameText } from "./frame.js";
|
|
2
|
+
/** Queued prompts the bar draws; everything older becomes one count above them. */
|
|
3
|
+
export const QUEUE_LIMIT = 3;
|
|
4
|
+
/** Text rows one queued prompt keeps before its own count takes over. */
|
|
5
|
+
export const QUEUE_TEXT_ROWS = 3;
|
|
6
|
+
/**
|
|
7
|
+
* The prompts the agent has not taken yet, drawn above the editor.
|
|
8
|
+
*
|
|
9
|
+
* The rows take the editor's own frame because that is what they are: input the
|
|
10
|
+
* reader already submitted, waiting for the agent to reach it. Only the face
|
|
11
|
+
* differs — faint and italic — so a reader can tell at a glance that the text is
|
|
12
|
+
* waiting rather than being typed.
|
|
13
|
+
*/
|
|
14
|
+
export class QueueBar {
|
|
15
|
+
prompts;
|
|
16
|
+
theme;
|
|
17
|
+
constructor(prompts, theme) {
|
|
18
|
+
this.prompts = prompts;
|
|
19
|
+
this.theme = theme;
|
|
20
|
+
}
|
|
21
|
+
invalidate() {
|
|
22
|
+
// Nothing is cached: the prompts are read fresh on every frame.
|
|
23
|
+
}
|
|
24
|
+
/** One queued prompt as the editor bar's own box, drawn in the queued face. */
|
|
25
|
+
box(text, width, framed) {
|
|
26
|
+
// A prompt can be longer than the screen; the reader needs to see that it is
|
|
27
|
+
// waiting, not to re-read all of it, so the first rows stand for the whole.
|
|
28
|
+
return frameText(text, width, {
|
|
29
|
+
text: line => this.theme.style('editor.queued', line),
|
|
30
|
+
border: rule => this.theme.editor.borderColor(rule),
|
|
31
|
+
framed,
|
|
32
|
+
}, QUEUE_TEXT_ROWS);
|
|
33
|
+
}
|
|
34
|
+
render(width) {
|
|
35
|
+
if (width <= 0)
|
|
36
|
+
return [];
|
|
37
|
+
const prompts = this.prompts();
|
|
38
|
+
if (prompts.length === 0)
|
|
39
|
+
return [];
|
|
40
|
+
// Hiding the face hides the rows: a frame around text the reader cannot read
|
|
41
|
+
// would look like an empty prompt waiting to be typed into.
|
|
42
|
+
if (!this.theme.visible('editor.queued'))
|
|
43
|
+
return [];
|
|
44
|
+
const framed = canFrame(width, this.theme.visible('editor.border'));
|
|
45
|
+
const shown = prompts.slice(-QUEUE_LIMIT);
|
|
46
|
+
const lines = [];
|
|
47
|
+
// The reader typed the newest prompt last, so that is the row that must stay
|
|
48
|
+
// on screen; the ones dropped here are the ones a claim is about to take.
|
|
49
|
+
if (shown.length < prompts.length) {
|
|
50
|
+
lines.push(this.theme.style('editor.queued.more', this.theme.cut(`… ${prompts.length - shown.length} queued earlier`, width, '…')));
|
|
51
|
+
}
|
|
52
|
+
for (const prompt of shown)
|
|
53
|
+
lines.push(...this.box(prompt, width, framed));
|
|
54
|
+
return lines;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/ui/queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEhD,mFAAmF;AACnF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAA;AAC5B,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA;AAEhC;;;;;;;GAOG;AACH,MAAM,OAAO,QAAQ;IAEA;IACA;IAFnB,YACmB,OAAgC,EAChC,KAAe;QADf,YAAO,GAAP,OAAO,CAAyB;QAChC,UAAK,GAAL,KAAK,CAAU;IAC/B,CAAC;IAEJ,UAAU;QACR,gEAAgE;IAClE,CAAC;IAED,+EAA+E;IACvE,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,MAAe;QACtD,6EAA6E;QAC7E,4EAA4E;QAC5E,OAAO,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE;YAC5B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC;YACrD,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;YACnD,MAAM;SACP,EAAE,eAAe,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,EAAE,CAAA;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACnC,6EAA6E;QAC7E,4DAA4D;QAC5D,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC;YAAE,OAAO,EAAE,CAAA;QACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAA;QACnE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAA;QACzC,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,iBAAiB,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;QACrI,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QAC1E,OAAO,KAAK,CAAA;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ResolvedEntry } from '../stash/schema.ts';
|
|
2
|
+
import { type Keymap } from '../input/actions.ts';
|
|
3
|
+
import { ListPicker } from './picker.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The first line of a draft, as one list row can show it.
|
|
6
|
+
*
|
|
7
|
+
* A picker row is a single line, so line feeds and runs of whitespace collapse;
|
|
8
|
+
* a draft whose only line is blank still has to name itself.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stashLabel(text: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* The drafts of one working directory, chosen by key press.
|
|
13
|
+
*
|
|
14
|
+
* The id a pick settles on is the entry id, so a pop survives the list being
|
|
15
|
+
* re-read while it is open and can never take the wrong draft after a concurrent
|
|
16
|
+
* drop shifted the indexes. The index is still shown, because it is the selector
|
|
17
|
+
* the same draft answers to on the command line, and filtering must not renumber
|
|
18
|
+
* it into something a reader could type and miss.
|
|
19
|
+
*/
|
|
20
|
+
export declare class StashPicker extends ListPicker<ResolvedEntry> {
|
|
21
|
+
constructor(entries: readonly ResolvedEntry[], cwdLabel: string, keys: () => Keymap, now?: () => number);
|
|
22
|
+
}
|
|
23
|
+
/** The choice that clears the bank, as opposed to leaving it alone. */
|
|
24
|
+
export declare const STASH_CLEAR_CHOICE = "clear";
|
|
25
|
+
interface ConfirmChoice {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly description: string;
|
|
29
|
+
}
|
|
30
|
+
/** Whether a settled confirm pick was the destructive one. */
|
|
31
|
+
export declare function confirmedClear(picked: string | undefined): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* A two-row confirmation.
|
|
34
|
+
*
|
|
35
|
+
* Clearing a bank is irreversible, so it is answered by picking a row rather
|
|
36
|
+
* than by a key that could be pressed by accident: leaving is the first row and
|
|
37
|
+
* the safe default.
|
|
38
|
+
*/
|
|
39
|
+
export declare class StashConfirmPicker extends ListPicker<ConfirmChoice> {
|
|
40
|
+
constructor(count: number, keys: () => Keymap);
|
|
41
|
+
}
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=stash-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stash-picker.d.ts","sourceRoot":"","sources":["../../src/ui/stash-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAsB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAe,UAAU,EAAoC,MAAM,aAAa,CAAA;AAqBvF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;;;;;GAQG;AACH,qBAAa,WAAY,SAAQ,UAAU,CAAC,aAAa,CAAC;gBAEtD,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,MAAM,EAClB,GAAG,GAAE,MAAM,MAAyB;CAiBvC;AAED,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,UAAU,CAAA;AAGzC,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAElE;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,UAAU,CAAC,aAAa,CAAC;gBACnD,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,MAAM;CAmB9C"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { hintKeys, moveHint } from "../input/actions.js";
|
|
2
|
+
import { describeAge, ListPicker } from "./picker.js";
|
|
3
|
+
/** Longest draft label a list row shows before it is cut. */
|
|
4
|
+
const LABEL_LENGTH = 50;
|
|
5
|
+
/** What a draft that contains only whitespace is called, so a row is never blank. */
|
|
6
|
+
const EMPTY_LABEL = '(empty draft)';
|
|
7
|
+
const ELLIPSIS = '…';
|
|
8
|
+
/**
|
|
9
|
+
* What the list says about its own keys.
|
|
10
|
+
*
|
|
11
|
+
* Read from the map on every paint, because a settings edit lands while the list
|
|
12
|
+
* is open and a hint that kept naming the shipped key would be wrong.
|
|
13
|
+
*/
|
|
14
|
+
function stashHints(keys, verb) {
|
|
15
|
+
return {
|
|
16
|
+
empty: () => `nothing matches · backspace to widen · ${hintKeys(keys(), 'picker.cancel')} cancel`,
|
|
17
|
+
listed: () => `${moveHint(keys(), 'picker.up', 'picker.down')} move · ${hintKeys(keys(), 'picker.confirm')} ${verb} · ${hintKeys(keys(), 'picker.cancel')} cancel · type to filter`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The first line of a draft, as one list row can show it.
|
|
22
|
+
*
|
|
23
|
+
* A picker row is a single line, so line feeds and runs of whitespace collapse;
|
|
24
|
+
* a draft whose only line is blank still has to name itself.
|
|
25
|
+
*/
|
|
26
|
+
export function stashLabel(text) {
|
|
27
|
+
const line = text.split('\n').find(candidate => candidate.trim() !== '')?.trim().replace(/\s+/gu, ' ');
|
|
28
|
+
if (line === undefined || line === '')
|
|
29
|
+
return EMPTY_LABEL;
|
|
30
|
+
return line.length <= LABEL_LENGTH ? line : `${line.slice(0, LABEL_LENGTH - 1)}${ELLIPSIS}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The drafts of one working directory, chosen by key press.
|
|
34
|
+
*
|
|
35
|
+
* The id a pick settles on is the entry id, so a pop survives the list being
|
|
36
|
+
* re-read while it is open and can never take the wrong draft after a concurrent
|
|
37
|
+
* drop shifted the indexes. The index is still shown, because it is the selector
|
|
38
|
+
* the same draft answers to on the command line, and filtering must not renumber
|
|
39
|
+
* it into something a reader could type and miss.
|
|
40
|
+
*/
|
|
41
|
+
export class StashPicker extends ListPicker {
|
|
42
|
+
constructor(entries, cwdLabel, keys, now = () => Date.now()) {
|
|
43
|
+
super(() => entries, () => `stash · ${cwdLabel} · ${entries.length} draft${entries.length === 1 ? '' : 's'}`, row => row.entry.id, (row) => ({
|
|
44
|
+
label: `[${row.index}] ${stashLabel(row.entry.text)}`,
|
|
45
|
+
description: describeAge(row.entry.createdAt, now()),
|
|
46
|
+
// The card marks the row under the cursor, which the list decides.
|
|
47
|
+
current: false,
|
|
48
|
+
}), row => row.entry.text, stashHints(keys, 'pop'), keys);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** The choice that clears the bank, as opposed to leaving it alone. */
|
|
52
|
+
export const STASH_CLEAR_CHOICE = 'clear';
|
|
53
|
+
const STASH_CANCEL_CHOICE = 'cancel';
|
|
54
|
+
/** Whether a settled confirm pick was the destructive one. */
|
|
55
|
+
export function confirmedClear(picked) {
|
|
56
|
+
return picked === STASH_CLEAR_CHOICE;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A two-row confirmation.
|
|
60
|
+
*
|
|
61
|
+
* Clearing a bank is irreversible, so it is answered by picking a row rather
|
|
62
|
+
* than by a key that could be pressed by accident: leaving is the first row and
|
|
63
|
+
* the safe default.
|
|
64
|
+
*/
|
|
65
|
+
export class StashConfirmPicker extends ListPicker {
|
|
66
|
+
constructor(count, keys) {
|
|
67
|
+
const choices = [
|
|
68
|
+
{ id: STASH_CANCEL_CHOICE, label: 'cancel', description: 'keep every draft' },
|
|
69
|
+
{
|
|
70
|
+
id: STASH_CLEAR_CHOICE,
|
|
71
|
+
label: `delete ${count} draft${count === 1 ? '' : 's'}`,
|
|
72
|
+
description: 'remove them permanently',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
super(() => choices, () => `clear stash · ${count} draft${count === 1 ? '' : 's'} in this directory`, choice => choice.id, (choice) => ({ label: choice.label, description: choice.description, current: false }), choice => choice.label, stashHints(keys, 'confirm'), keys);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=stash-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stash-picker.js","sourceRoot":"","sources":["../../src/ui/stash-picker.ts"],"names":[],"mappings":"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"}
|
package/lib/ui/status.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { type Component } from '@earendil-works/pi-tui';
|
|
|
2
2
|
import type { TuiTheme } from '../theme.ts';
|
|
3
3
|
/** Everything the footer states, gathered by the surface around it. */
|
|
4
4
|
export interface StatusFacts {
|
|
5
|
+
/** The chord waiting for its second key, when one is armed. */
|
|
6
|
+
readonly chord: string | undefined;
|
|
7
|
+
/** How the reader returns to the session this terminal drives, when another is on screen. */
|
|
8
|
+
readonly back: string | undefined;
|
|
5
9
|
readonly activity: 'idle' | 'working';
|
|
6
10
|
/** How long the running turn has been running, when one is. */
|
|
7
11
|
readonly elapsedMs: number | undefined;
|
|
@@ -20,6 +24,8 @@ export interface StatusFacts {
|
|
|
20
24
|
readonly uncachedInputTokens: number | undefined;
|
|
21
25
|
/** Tokens this session has generated, when the provider reported any. */
|
|
22
26
|
readonly outputTokens: number | undefined;
|
|
27
|
+
/** Drafts parked for this working directory; omitted when none are known. */
|
|
28
|
+
readonly stashed?: number | undefined;
|
|
23
29
|
readonly cwd: string;
|
|
24
30
|
readonly home: string | undefined;
|
|
25
31
|
}
|
package/lib/ui/status.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,wBAAwB,CAAA;AAIrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAA;IAChD,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,wBAAwB,CAAA;AAIrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAA;IAChD,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;AAwBD,wFAAwF;AAExF;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQxE;AAOD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAgDvF;AAsCD,yDAAyD;AACzD,qBAAa,SAAU,YAAW,SAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,KAAK,EAAE,MAAM,WAAW,EACxB,KAAK,EAAE,QAAQ;IAGlC,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAGhC"}
|
package/lib/ui/status.js
CHANGED
|
@@ -12,6 +12,8 @@ const ELLIPSIS = '…';
|
|
|
12
12
|
/** The mark that says which of the two activities the session is in. */
|
|
13
13
|
const WORKING_MARK = '▶';
|
|
14
14
|
const READY_MARK = '●';
|
|
15
|
+
/** What the parked-draft count is labelled, so the number is not mistaken for tokens. */
|
|
16
|
+
const STASH_LABEL = 'stash';
|
|
15
17
|
/** Compact a token count, because the exact number changes nothing a reader decides. */
|
|
16
18
|
/**
|
|
17
19
|
* Shorten an absolute path for the footer: the reader's own home becomes `~`,
|
|
@@ -55,6 +57,14 @@ export function formatStatus(facts, width, theme) {
|
|
|
55
57
|
return;
|
|
56
58
|
segments.push({ token, text: displayText(text), join });
|
|
57
59
|
};
|
|
60
|
+
// An armed chord is transient and needs the reader's eye now, so it leads the
|
|
61
|
+
// row: a row cut to width loses its tail, never what is about to happen.
|
|
62
|
+
if (facts.chord !== undefined && facts.chord !== '')
|
|
63
|
+
push('status.prefix', facts.chord);
|
|
64
|
+
// The way back is the other thing the reader may need at once: a transcript of
|
|
65
|
+
// a session they are not driving is exactly when they need it.
|
|
66
|
+
if (facts.back !== undefined && facts.back !== '')
|
|
67
|
+
push('status.back', facts.back);
|
|
58
68
|
if (facts.activity === 'working') {
|
|
59
69
|
push('status.activity.working', `${WORKING_MARK} working`);
|
|
60
70
|
// Elapsed carries its own token so it can be toned apart from the activity,
|
|
@@ -78,6 +88,11 @@ export function formatStatus(facts, width, theme) {
|
|
|
78
88
|
}
|
|
79
89
|
if (facts.preset !== undefined && facts.preset !== '')
|
|
80
90
|
push('status.permission', facts.preset);
|
|
91
|
+
// Parked drafts come before the running numbers: a row cut to width loses its
|
|
92
|
+
// tail, and a reader who cannot see the count cannot know the directory is
|
|
93
|
+
// holding work they meant to come back to.
|
|
94
|
+
if (facts.stashed !== undefined && facts.stashed > 0)
|
|
95
|
+
push('status.stash', `${STASH_LABEL} ${facts.stashed}`);
|
|
81
96
|
if (facts.contextTokens !== undefined) {
|
|
82
97
|
push('status.context', facts.contextWindow === undefined
|
|
83
98
|
? `ctx ${formatTokens(facts.contextTokens)}`
|