@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
package/lib/export.js
CHANGED
|
@@ -1,19 +1,45 @@
|
|
|
1
|
+
import { rowText } from "./cards.js";
|
|
1
2
|
import { displayText } from "./text.js";
|
|
2
3
|
/** Directory-relative default the reader can find without being told. */
|
|
3
4
|
export const DEFAULT_EXPORT_PREFIX = 'dsh-session';
|
|
5
|
+
/** How the dump marks a nested call that returned an error, which the screen carried as colour. */
|
|
6
|
+
const SUBCALL_FAILED_SUFFIX = ' (failed)';
|
|
4
7
|
/** Id characters kept in a file name, so a session id cannot escape the directory. */
|
|
5
8
|
const UNSAFE_NAME = /[^A-Za-z0-9._-]/gu;
|
|
9
|
+
/** The shortest code fence; a longer backtick run in the body needs a longer one. */
|
|
10
|
+
const MIN_FENCE = 3;
|
|
11
|
+
const BACKTICK_RUN = /`+/gu;
|
|
12
|
+
/** A comment body must not close the comment that carries it. */
|
|
13
|
+
const COMMENT_CLOSE = '-->';
|
|
14
|
+
const COMMENT_CLOSE_DEFUSED = '-->';
|
|
6
15
|
/** Default file for a dump: the session's own name, in the working directory. */
|
|
7
16
|
export function defaultExportFile(sessionId) {
|
|
8
17
|
return `${DEFAULT_EXPORT_PREFIX}-${sessionId.replace(UNSAFE_NAME, '_')}.md`;
|
|
9
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* A fence the body cannot close early.
|
|
21
|
+
*
|
|
22
|
+
* Tool output and thinking are arbitrary text, and a run of three backticks in
|
|
23
|
+
* either would end the block and spill the rest into the document as prose.
|
|
24
|
+
*/
|
|
25
|
+
function fenceFor(text) {
|
|
26
|
+
let longest = 0;
|
|
27
|
+
for (const run of text.match(BACKTICK_RUN) ?? [])
|
|
28
|
+
longest = Math.max(longest, run.length);
|
|
29
|
+
return '`'.repeat(Math.max(MIN_FENCE, longest + 1));
|
|
30
|
+
}
|
|
31
|
+
/** Comment text with any closing marker defused, so the comment stays one. */
|
|
32
|
+
function commentBody(text) {
|
|
33
|
+
return displayText(text).replaceAll(COMMENT_CLOSE, COMMENT_CLOSE_DEFUSED);
|
|
34
|
+
}
|
|
10
35
|
/**
|
|
11
36
|
* Render the visible transcript as markdown.
|
|
12
37
|
*
|
|
13
|
-
* The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
38
|
+
* The dump outlives the screen it came from, so each row is given the markdown
|
|
39
|
+
* construct that carries its meaning rather than whichever mark the surface
|
|
40
|
+
* happened to draw, and every fragment is escaped for display for the same
|
|
41
|
+
* reason a rendered row is: the file may be opened in a terminal, and it is
|
|
42
|
+
* full of model and tool output.
|
|
17
43
|
*/
|
|
18
44
|
export function transcriptToText(entries) {
|
|
19
45
|
const lines = [];
|
|
@@ -26,23 +52,46 @@ export function transcriptToText(entries) {
|
|
|
26
52
|
lines.push('', displayText(entry.text));
|
|
27
53
|
break;
|
|
28
54
|
case 'notice':
|
|
29
|
-
lines.push('', `<!-- ${
|
|
55
|
+
lines.push('', `<!-- ${commentBody(entry.text)} -->`);
|
|
30
56
|
break;
|
|
31
57
|
case 'marker':
|
|
32
58
|
lines.push('', `--- ${displayText(entry.text)} ---`);
|
|
33
59
|
break;
|
|
34
|
-
case 'reasoning':
|
|
35
|
-
|
|
60
|
+
case 'reasoning': {
|
|
61
|
+
// The thought is on screen now, so it belongs in the dump; only the
|
|
62
|
+
// count is metadata, and the body is the part a reader came for.
|
|
63
|
+
const body = entry.body.split('\n').map(displayText);
|
|
64
|
+
const fence = fenceFor(body.join('\n'));
|
|
65
|
+
lines.push('', `<!-- ${commentBody(entry.summary)} -->`, `${fence}reasoning`);
|
|
66
|
+
lines.push(...body);
|
|
67
|
+
lines.push(fence);
|
|
36
68
|
break;
|
|
69
|
+
}
|
|
37
70
|
case 'tool': {
|
|
38
71
|
const mark = entry.card.failed ? 'ERROR' : 'tool';
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
72
|
+
// The dump is the words, not the screen: row classes exist so the
|
|
73
|
+
// surface can style a line, and a file has no use for them.
|
|
74
|
+
const rows = entry.card.detail.map(row => displayText(rowText(row)));
|
|
75
|
+
const more = entry.card.totalLines > entry.card.detail.length
|
|
76
|
+
? `… ${entry.card.totalLines - entry.card.detail.length} more lines`
|
|
77
|
+
: undefined;
|
|
78
|
+
const fence = fenceFor([displayText(entry.card.title), ...rows, more ?? ''].join('\n'));
|
|
79
|
+
lines.push('', `### ${mark}: ${displayText(entry.card.title)}`);
|
|
80
|
+
// The calls are what the reader saw under the card, so a dump that
|
|
81
|
+
// dropped them would lose the only record of what the program reached.
|
|
82
|
+
const subCalls = entry.card.subCalls ?? [];
|
|
83
|
+
for (const call of subCalls) {
|
|
84
|
+
const text = call.argument === undefined ? call.title : `${call.title} ${call.argument}`;
|
|
85
|
+
lines.push(`- ${displayText(text)}${call.failed ? SUBCALL_FAILED_SUFFIX : ''}`);
|
|
44
86
|
}
|
|
45
|
-
|
|
87
|
+
const dropped = (entry.card.subCallsTotal ?? subCalls.length) - subCalls.length;
|
|
88
|
+
if (dropped > 0)
|
|
89
|
+
lines.push(`- … ${dropped} more calls`);
|
|
90
|
+
lines.push('', fence);
|
|
91
|
+
lines.push(...rows);
|
|
92
|
+
if (more !== undefined)
|
|
93
|
+
lines.push(more);
|
|
94
|
+
lines.push(fence);
|
|
46
95
|
break;
|
|
47
96
|
}
|
|
48
97
|
}
|
package/lib/export.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAGvC,yEAAyE;AACzE,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAA;AAElD,sFAAsF;AACtF,MAAM,WAAW,GAAG,mBAAmB,CAAA;AAEvC,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,GAAG,qBAAqB,IAAI,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,CAAA;AAC7E,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ForkEvent } from './agent/fork.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The fold's place in a session's durable event sequence.
|
|
4
|
+
*
|
|
5
|
+
* A resumed session is folded while its agent's loop is already live, so the
|
|
6
|
+
* same event reaches the surface twice: once on the stream, once from the log
|
|
7
|
+
* the fold is reading. Every durable event carries a monotonic sequence number,
|
|
8
|
+
* which is what tells a row that has already been drawn from one that has not.
|
|
9
|
+
*/
|
|
10
|
+
/** Consumes durable events in sequence order, each exactly once. */
|
|
11
|
+
export declare class FoldCursor {
|
|
12
|
+
private through;
|
|
13
|
+
/**
|
|
14
|
+
* Start a fresh transcript.
|
|
15
|
+
*
|
|
16
|
+
* Sequence numbers are per session, so a fold that begins a new transcript
|
|
17
|
+
* must not measure its events against the previous session's numbering.
|
|
18
|
+
*/
|
|
19
|
+
reset(): void;
|
|
20
|
+
/** Whether an event still has to be folded, and record it when it does. */
|
|
21
|
+
accept(event: ForkEvent): boolean;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=fold-cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-cursor.d.ts","sourceRoot":"","sources":["../src/fold-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD;;;;;;;GAOG;AAEH,oEAAoE;AACpE,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAoB;IAEnC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAIb,2EAA2E;IAC3E,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;CAOlC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fold's place in a session's durable event sequence.
|
|
3
|
+
*
|
|
4
|
+
* A resumed session is folded while its agent's loop is already live, so the
|
|
5
|
+
* same event reaches the surface twice: once on the stream, once from the log
|
|
6
|
+
* the fold is reading. Every durable event carries a monotonic sequence number,
|
|
7
|
+
* which is what tells a row that has already been drawn from one that has not.
|
|
8
|
+
*/
|
|
9
|
+
/** Consumes durable events in sequence order, each exactly once. */
|
|
10
|
+
export class FoldCursor {
|
|
11
|
+
through;
|
|
12
|
+
/**
|
|
13
|
+
* Start a fresh transcript.
|
|
14
|
+
*
|
|
15
|
+
* Sequence numbers are per session, so a fold that begins a new transcript
|
|
16
|
+
* must not measure its events against the previous session's numbering.
|
|
17
|
+
*/
|
|
18
|
+
reset() {
|
|
19
|
+
this.through = undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Whether an event still has to be folded, and record it when it does. */
|
|
22
|
+
accept(event) {
|
|
23
|
+
if (typeof event.seq === 'number') {
|
|
24
|
+
if (this.through !== undefined && event.seq <= this.through)
|
|
25
|
+
return false;
|
|
26
|
+
this.through = event.seq;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=fold-cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-cursor.js","sourceRoot":"","sources":["../src/fold-cursor.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,oEAAoE;AACpE,MAAM,OAAO,UAAU;IACb,OAAO,CAAoB;IAEnC;;;;;OAKG;IACH,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;IAC1B,CAAC;IAED,2EAA2E;IAC3E,MAAM,CAAC,KAAgB;QACrB,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAA;YACzE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,CAAA;QAC1B,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
|
package/lib/gates.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Keymap } from './input/actions.ts';
|
|
1
2
|
/** The outcome vocabulary the approval seam accepts from an answerer. */
|
|
2
3
|
export type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled';
|
|
3
4
|
/** How a pending gate presents itself, independent of how it is drawn. */
|
|
@@ -5,9 +6,54 @@ export interface GateCard {
|
|
|
5
6
|
readonly kind: 'approval' | 'question';
|
|
6
7
|
readonly title: string;
|
|
7
8
|
readonly detail: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The number the first drawn option answers for. A list longer than the
|
|
11
|
+
* screen shows a window of itself, and a window that restarts at one every
|
|
12
|
+
* scroll hides where the reader is and contradicts the digits that pick by
|
|
13
|
+
* that same number.
|
|
14
|
+
*/
|
|
15
|
+
readonly optionOffset: number;
|
|
8
16
|
readonly options: readonly GateOption[];
|
|
17
|
+
/**
|
|
18
|
+
* The row that answers with typed text. A question with no options is answered
|
|
19
|
+
* by typing anyway, so it has no such row to draw.
|
|
20
|
+
*/
|
|
21
|
+
readonly custom: GateCustomRow | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The editor the answer is written in, drawn under the row that fills it.
|
|
24
|
+
*
|
|
25
|
+
* A question says nothing about its answer until someone writes one, so the
|
|
26
|
+
* rows come from the surface's own editor rather than from text composed
|
|
27
|
+
* here: the reader gets the cursor movement, deletion, undo, and paste the
|
|
28
|
+
* prompt bar already has.
|
|
29
|
+
*/
|
|
30
|
+
readonly answerInput: GateInput | undefined;
|
|
9
31
|
readonly hint: string;
|
|
10
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* The editor a question collects typed text with.
|
|
35
|
+
*
|
|
36
|
+
* These are the editor's own members rather than a vocabulary invented here, so
|
|
37
|
+
* the surface hands in the component the prompt bar already uses and nothing
|
|
38
|
+
* has to adapt it. Every key the gate does not claim — movement, deletion,
|
|
39
|
+
* undo, a pasted block — reaches the answer through this.
|
|
40
|
+
*/
|
|
41
|
+
export type GateInputMode = 'answer' | 'secret';
|
|
42
|
+
export interface GateInput {
|
|
43
|
+
/** The answer as written, with a pasted block expanded back to its text. */
|
|
44
|
+
getExpandedText(): string;
|
|
45
|
+
/** Replace the answer, so the next question of a batch does not inherit one. */
|
|
46
|
+
setText(text: string): void;
|
|
47
|
+
/** Lay the answer out for this width; its rows are drawn under the free-text row. */
|
|
48
|
+
render(width: number): string[];
|
|
49
|
+
/** Take a key the gate itself did not claim. */
|
|
50
|
+
handleInput(data: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* How the surface shows the answer it is collecting, absent on an editor
|
|
53
|
+
* that has no way to hide one.
|
|
54
|
+
*/
|
|
55
|
+
setMode?(mode: GateInputMode): void;
|
|
56
|
+
}
|
|
11
57
|
/** One selectable row of a question gate. */
|
|
12
58
|
export interface GateOption {
|
|
13
59
|
readonly label: string;
|
|
@@ -15,6 +61,15 @@ export interface GateOption {
|
|
|
15
61
|
readonly current: boolean;
|
|
16
62
|
readonly selected: boolean;
|
|
17
63
|
}
|
|
64
|
+
/** The row that answers with typed text instead of a listed label. */
|
|
65
|
+
export interface GateCustomRow {
|
|
66
|
+
readonly label: string;
|
|
67
|
+
readonly description: string | undefined;
|
|
68
|
+
/** Whether the cursor is on this row, which is what makes typing the answer. */
|
|
69
|
+
readonly current: boolean;
|
|
70
|
+
/** Whether a custom answer is being formed or already holds text. */
|
|
71
|
+
readonly selected: boolean;
|
|
72
|
+
}
|
|
18
73
|
/**
|
|
19
74
|
* One pending approval.
|
|
20
75
|
*
|
|
@@ -25,8 +80,12 @@ export interface GateOption {
|
|
|
25
80
|
export declare class ApprovalGate {
|
|
26
81
|
private readonly toolName;
|
|
27
82
|
private readonly reason;
|
|
83
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
84
|
+
private readonly keys;
|
|
28
85
|
private outcome;
|
|
29
|
-
constructor(toolName: string, reason: string | undefined
|
|
86
|
+
constructor(toolName: string, reason: string | undefined,
|
|
87
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
88
|
+
keys: () => Keymap);
|
|
30
89
|
get resolved(): boolean;
|
|
31
90
|
/** Apply one key press; returns the outcome the first time it settles. */
|
|
32
91
|
handleKey(data: string): ApprovalOutcome | undefined;
|
|
@@ -37,6 +96,7 @@ export declare class ApprovalGate {
|
|
|
37
96
|
export interface GateQuestion {
|
|
38
97
|
readonly id: string;
|
|
39
98
|
readonly question: string;
|
|
99
|
+
readonly header: string | undefined;
|
|
40
100
|
readonly detail: string | undefined;
|
|
41
101
|
readonly options: readonly {
|
|
42
102
|
readonly label: string;
|
|
@@ -57,6 +117,8 @@ export interface GateAnswer {
|
|
|
57
117
|
* option-less gate rather than a rejected request: the model asked for text.
|
|
58
118
|
*/
|
|
59
119
|
export declare function toGateQuestions(request: unknown): GateQuestion[];
|
|
120
|
+
/** The number the free-text row answers for. It sits below the window, so drawn numbering runs 1..n then 0. */
|
|
121
|
+
export declare const CUSTOM_ROW_NUMBER = 0;
|
|
60
122
|
/**
|
|
61
123
|
* A pending batch of questions.
|
|
62
124
|
*
|
|
@@ -67,18 +129,99 @@ export declare function toGateQuestions(request: unknown): GateQuestion[];
|
|
|
67
129
|
*/
|
|
68
130
|
export declare class QuestionGate {
|
|
69
131
|
private readonly questions;
|
|
132
|
+
/** The editor every typed answer is written in, whichever row asks for it. */
|
|
133
|
+
private readonly input;
|
|
134
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
135
|
+
private readonly keys;
|
|
70
136
|
private index;
|
|
71
137
|
private cursor;
|
|
72
138
|
private typed;
|
|
139
|
+
/** Whether the cursor is on the free-text row. */
|
|
140
|
+
private atCustom;
|
|
141
|
+
/**
|
|
142
|
+
* The row an escape from the free-text row returns to.
|
|
143
|
+
*
|
|
144
|
+
* It is the row the reader last acted on — walked to, picked by its number, or
|
|
145
|
+
* toggled — because that is the option they were looking at when they decided
|
|
146
|
+
* to answer freely, and it is not always the row the cursor still stands on: a
|
|
147
|
+
* digit picks by number without walking anywhere.
|
|
148
|
+
*/
|
|
149
|
+
private customFrom;
|
|
73
150
|
private readonly chosen;
|
|
74
151
|
private readonly custom;
|
|
75
152
|
private finished;
|
|
76
|
-
constructor(questions: readonly GateQuestion[]
|
|
153
|
+
constructor(questions: readonly GateQuestion[],
|
|
154
|
+
/** The editor every typed answer is written in, whichever row asks for it. */
|
|
155
|
+
input: GateInput,
|
|
156
|
+
/** The keys in force, read per press so a settings edit lands on the next key. */
|
|
157
|
+
keys: () => Keymap);
|
|
158
|
+
/**
|
|
159
|
+
* Empty the editor for the question now under the cursor.
|
|
160
|
+
*
|
|
161
|
+
* The editor belongs to the surface and outlives one question, so an answer
|
|
162
|
+
* must never cross from the last question into the next — or from a gate that
|
|
163
|
+
* was abandoned into the one that follows it. Its mode follows the question
|
|
164
|
+
* for the same reason: a credential must not be shown because the last
|
|
165
|
+
* question was not one.
|
|
166
|
+
*/
|
|
167
|
+
private resetInput;
|
|
77
168
|
get resolved(): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Stop a question whose caller is gone.
|
|
171
|
+
*
|
|
172
|
+
* WHY: an aborted call has no reader for the answer, and a live gate would
|
|
173
|
+
* otherwise keep the keyboard — and the borrowed editor — until someone
|
|
174
|
+
* typed into a call that had already ended.
|
|
175
|
+
*/
|
|
176
|
+
cancel(): void;
|
|
78
177
|
private get current();
|
|
178
|
+
/**
|
|
179
|
+
* Options the typed filter leaves, in the order they were listed.
|
|
180
|
+
*
|
|
181
|
+
* The order is not the score order a picker uses: a digit answers by
|
|
182
|
+
* position, and re-ranking rows would move the number the reader just read.
|
|
183
|
+
*/
|
|
184
|
+
private matched;
|
|
185
|
+
/**
|
|
186
|
+
* The rows the keys and the card agree on: the filter, then a window around
|
|
187
|
+
* the cursor, because a list as long as a provider catalog would otherwise
|
|
188
|
+
* push the editor off the screen.
|
|
189
|
+
*/
|
|
190
|
+
private windowed;
|
|
191
|
+
/** The row under the cursor, as the filter leaves it. */
|
|
192
|
+
private currentRow;
|
|
193
|
+
/** Take or drop one source option, by single-select replacement or multi-select toggle. */
|
|
194
|
+
private pick;
|
|
195
|
+
/**
|
|
196
|
+
* Whether a keystroke is answer text rather than a filter.
|
|
197
|
+
*
|
|
198
|
+
* A question without options has no list to filter, and the free-text row is
|
|
199
|
+
* where a question with options collects an answer the model did not list.
|
|
200
|
+
*/
|
|
201
|
+
private typingAnswer;
|
|
202
|
+
/** Add text to the filter, or to the answer the current row collects. */
|
|
203
|
+
private absorb;
|
|
79
204
|
/** Apply one key press; returns the batch answer the first time it completes. */
|
|
80
205
|
handleKey(data: string): GateAnswer[] | undefined;
|
|
206
|
+
/**
|
|
207
|
+
* One key press while the free-text row holds the cursor.
|
|
208
|
+
*
|
|
209
|
+
* Walking back to the list keeps whatever was typed, so a reader who changes
|
|
210
|
+
* their mind about answering freely has not lost the text yet. An escape
|
|
211
|
+
* leaves the row the same way, because a question skipped by accident is a
|
|
212
|
+
* question the reader has to answer again: from the list, where every other
|
|
213
|
+
* question is skipped, an escape skips this one too.
|
|
214
|
+
*/
|
|
215
|
+
private handleCustomKey;
|
|
216
|
+
/** Take the answer the reader confirmed, then leave the question. */
|
|
81
217
|
private confirm;
|
|
218
|
+
/**
|
|
219
|
+
* Leave the current question for the next one.
|
|
220
|
+
*
|
|
221
|
+
* Typed text belongs to the question being left, so it never crosses into the
|
|
222
|
+
* next one — which is why a skipped question reports no typed answer at all.
|
|
223
|
+
*/
|
|
224
|
+
private advance;
|
|
82
225
|
private result;
|
|
83
226
|
card(): GateCard;
|
|
84
227
|
}
|
package/lib/gates.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"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"}
|