@sigrun/tui 0.1.1 → 0.2.1

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +2 -2
  3. package/dist/actions.d.ts +0 -119
  4. package/dist/actions.js +0 -12
  5. package/dist/api.d.ts +0 -152
  6. package/dist/api.js +0 -189
  7. package/dist/blocks/braille.d.ts +0 -41
  8. package/dist/blocks/braille.js +0 -131
  9. package/dist/blocks/chart.d.ts +0 -20
  10. package/dist/blocks/chart.js +0 -397
  11. package/dist/blocks/collection/calendar.d.ts +0 -28
  12. package/dist/blocks/collection/calendar.js +0 -232
  13. package/dist/blocks/collection/card.d.ts +0 -36
  14. package/dist/blocks/collection/card.js +0 -128
  15. package/dist/blocks/collection/collection.d.ts +0 -9
  16. package/dist/blocks/collection/collection.js +0 -26
  17. package/dist/blocks/collection/grid.d.ts +0 -18
  18. package/dist/blocks/collection/grid.js +0 -72
  19. package/dist/blocks/collection/lanes.d.ts +0 -32
  20. package/dist/blocks/collection/lanes.js +0 -320
  21. package/dist/blocks/collection/list.d.ts +0 -30
  22. package/dist/blocks/collection/list.js +0 -273
  23. package/dist/blocks/collection/move.d.ts +0 -67
  24. package/dist/blocks/collection/move.js +0 -96
  25. package/dist/blocks/collection/shared.d.ts +0 -87
  26. package/dist/blocks/collection/shared.js +0 -177
  27. package/dist/blocks/collection/table.d.ts +0 -26
  28. package/dist/blocks/collection/table.js +0 -221
  29. package/dist/blocks/content.d.ts +0 -48
  30. package/dist/blocks/content.js +0 -253
  31. package/dist/blocks/context.d.ts +0 -96
  32. package/dist/blocks/context.js +0 -65
  33. package/dist/blocks/diff.d.ts +0 -21
  34. package/dist/blocks/diff.js +0 -25
  35. package/dist/blocks/ext-transport.d.ts +0 -70
  36. package/dist/blocks/ext-transport.js +0 -165
  37. package/dist/blocks/form/choice.d.ts +0 -54
  38. package/dist/blocks/form/choice.js +0 -175
  39. package/dist/blocks/form/fields.d.ts +0 -56
  40. package/dist/blocks/form/fields.js +0 -136
  41. package/dist/blocks/form/file.d.ts +0 -61
  42. package/dist/blocks/form/file.js +0 -121
  43. package/dist/blocks/form/form.d.ts +0 -53
  44. package/dist/blocks/form/form.js +0 -703
  45. package/dist/blocks/form/list.d.ts +0 -37
  46. package/dist/blocks/form/list.js +0 -70
  47. package/dist/blocks/form/values.d.ts +0 -20
  48. package/dist/blocks/form/values.js +0 -104
  49. package/dist/blocks/icons.d.ts +0 -14
  50. package/dist/blocks/icons.js +0 -74
  51. package/dist/blocks/image.d.ts +0 -39
  52. package/dist/blocks/image.js +0 -82
  53. package/dist/blocks/layout.d.ts +0 -31
  54. package/dist/blocks/layout.js +0 -155
  55. package/dist/blocks/log.d.ts +0 -24
  56. package/dist/blocks/log.js +0 -111
  57. package/dist/blocks/meter.d.ts +0 -16
  58. package/dist/blocks/meter.js +0 -50
  59. package/dist/blocks/page.d.ts +0 -54
  60. package/dist/blocks/page.js +0 -355
  61. package/dist/blocks/render.d.ts +0 -31
  62. package/dist/blocks/render.js +0 -145
  63. package/dist/blocks/surface-view.d.ts +0 -33
  64. package/dist/blocks/surface-view.js +0 -86
  65. package/dist/blocks/surface.d.ts +0 -75
  66. package/dist/blocks/surface.js +0 -468
  67. package/dist/blocks/tones.d.ts +0 -23
  68. package/dist/blocks/tones.js +0 -63
  69. package/dist/blocks/treeview.d.ts +0 -22
  70. package/dist/blocks/treeview.js +0 -121
  71. package/dist/blocks/width.d.ts +0 -32
  72. package/dist/blocks/width.js +0 -70
  73. package/dist/clipboard.d.ts +0 -20
  74. package/dist/clipboard.js +0 -19
  75. package/dist/editor-launch.d.ts +0 -34
  76. package/dist/editor-launch.js +0 -70
  77. package/dist/keymaps/emacs.d.ts +0 -18
  78. package/dist/keymaps/emacs.js +0 -172
  79. package/dist/keymaps/standard.d.ts +0 -17
  80. package/dist/keymaps/standard.js +0 -175
  81. package/dist/keymaps/types.d.ts +0 -43
  82. package/dist/keymaps/types.js +0 -28
  83. package/dist/keymaps/vim.d.ts +0 -48
  84. package/dist/keymaps/vim.js +0 -291
  85. package/dist/launch.d.ts +0 -149
  86. package/dist/launch.js +0 -446
  87. package/dist/sse.d.ts +0 -109
  88. package/dist/sse.js +0 -401
  89. package/dist/theme.d.ts +0 -51
  90. package/dist/theme.js +0 -119
  91. package/dist/ui/ambient.d.ts +0 -81
  92. package/dist/ui/ambient.js +0 -301
  93. package/dist/ui/app.d.ts +0 -245
  94. package/dist/ui/app.js +0 -1325
  95. package/dist/ui/composer.d.ts +0 -66
  96. package/dist/ui/composer.js +0 -125
  97. package/dist/ui/conversation-pane.d.ts +0 -123
  98. package/dist/ui/conversation-pane.js +0 -463
  99. package/dist/ui/help.d.ts +0 -15
  100. package/dist/ui/help.js +0 -80
  101. package/dist/ui/interactions.d.ts +0 -90
  102. package/dist/ui/interactions.js +0 -330
  103. package/dist/ui/picker.d.ts +0 -26
  104. package/dist/ui/picker.js +0 -130
  105. package/dist/ui/sidebar.d.ts +0 -99
  106. package/dist/ui/sidebar.js +0 -269
  107. package/dist/ui/status-bar.d.ts +0 -77
  108. package/dist/ui/status-bar.js +0 -146
@@ -1,43 +0,0 @@
1
- /**
2
- * The keymap contract (Task C3, UI refresh): a keymap maps raw terminal
3
- * input to an {@link Action}, `"pass"` (the focused component — usually
4
- * the composer — gets the key), or `"consume"` (swallow silently). The
5
- * launcher's single input listener asks the keymap first, then dispatches
6
- * / consumes / passes.
7
- *
8
- * RESERVED_KEYS are the composer's line-editing chords (readline-style)
9
- * and the tmux prefix: a keymap must NEVER bind them — it returns "pass"
10
- * for every one in every focus so the editor (or tmux) always sees them.
11
- * Ctrl+B in particular is the user's hard rule.
12
- */
13
- import type { Action, Focus } from "../actions.js";
14
- /** The state a keymap decision depends on. */
15
- export interface KeyContext {
16
- readonly focus: Focus;
17
- /** A live run is in flight (Esc aborts it). */
18
- readonly busy: boolean;
19
- /** The composer's autocomplete dropdown is open (Esc/Tab pass to it). */
20
- readonly autocompleteOpen: boolean;
21
- /** A modal overlay (picker/search/answer) owns the keys. */
22
- readonly overlayOpen: boolean;
23
- }
24
- /** What the launcher does with the key: run the action, swallow, or pass. */
25
- export type KeyResult = Action | "pass" | "consume";
26
- export interface Keymap {
27
- readonly name: "standard" | "vim" | "emacs";
28
- /** The status-bar mode chip text; undefined = no chip (standard). */
29
- modeLabel(): string | undefined;
30
- handle(data: string, ctx: KeyContext): KeyResult;
31
- /** The one-line hint cluster for the status bar. */
32
- hints(ctx: KeyContext): readonly string[];
33
- /** The help listing: every binding with a human description. */
34
- describe(): readonly {
35
- keys: string;
36
- action: string;
37
- }[];
38
- }
39
- /**
40
- * Keys no keymap may bind: the composer's readline chords plus the tmux
41
- * prefix (ctrl+b). Keymaps return "pass" for all of them in every focus.
42
- */
43
- export declare const RESERVED_KEYS: readonly string[];
@@ -1,28 +0,0 @@
1
- /**
2
- * The keymap contract (Task C3, UI refresh): a keymap maps raw terminal
3
- * input to an {@link Action}, `"pass"` (the focused component — usually
4
- * the composer — gets the key), or `"consume"` (swallow silently). The
5
- * launcher's single input listener asks the keymap first, then dispatches
6
- * / consumes / passes.
7
- *
8
- * RESERVED_KEYS are the composer's line-editing chords (readline-style)
9
- * and the tmux prefix: a keymap must NEVER bind them — it returns "pass"
10
- * for every one in every focus so the editor (or tmux) always sees them.
11
- * Ctrl+B in particular is the user's hard rule.
12
- */
13
- /**
14
- * Keys no keymap may bind: the composer's readline chords plus the tmux
15
- * prefix (ctrl+b). Keymaps return "pass" for all of them in every focus.
16
- */
17
- export const RESERVED_KEYS = [
18
- "ctrl+b",
19
- "ctrl+a",
20
- "ctrl+e",
21
- "ctrl+f",
22
- "ctrl+k",
23
- "ctrl+u",
24
- "ctrl+w",
25
- "ctrl+y",
26
- "ctrl+d",
27
- "ctrl+j",
28
- ];
@@ -1,48 +0,0 @@
1
- /**
2
- * The vim keymap (Task C4, UI refresh): real insert/normal/command modes
3
- * over the C3 action layer. Starts in INSERT with the composer focused —
4
- * every key types through except Esc (→ NORMAL, focus transcript),
5
- * Ctrl+C (abort a live run; otherwise consumed — quitting is ZZ or :q),
6
- * and Ctrl+O (answer an interaction). Every {@link RESERVED_KEYS} chord
7
- * passes in INSERT (the composer's readline chords and the tmux prefix
8
- * are never shadowed; ctrl+b is NEVER bound anywhere).
9
- *
10
- * NORMAL owns the transcript/list: j/k move, h/l focus list/transcript,
11
- * ctrl+d/ctrl+u half-page (bound here — RESERVED exists to protect the
12
- * composer's editing, and in NORMAL the composer is not focused),
13
- * gg/G edges, {/} prompt jumps, Enter/za fold, o open, y/yy copy,
14
- * f fork, e edit, v edit-in-vim, //?/n/N search, i/a back to INSERT,
15
- * `:` the command line, ctrl+p picker, ctrl+l redraw, ZZ quit. UNBOUND
16
- * PRINTABLE KEYS ARE CONSUMED — they must never leak into the composer.
17
- *
18
- * COMMAND accumulates a line after `:` (the app renders ":"+buffer in
19
- * the status bar via {@link VimKeymap.getCommandLine}); Enter dispatches
20
- * run-command, Esc cancels, Tab completes the command name.
21
- *
22
- * The two-key chords (gg, yy, za, ZZ) share one pending-key window of
23
- * 500 ms; a timed-out or mismatched prefix is consumed silently.
24
- */
25
- import { type Keymap } from "./types.js";
26
- export type VimMode = "insert" | "normal" | "command";
27
- /** The keymap plus the mode/command-line seam the app polls after each key. */
28
- export interface VimKeymap extends Keymap {
29
- readonly mode: VimMode;
30
- /** The ":" line while in command mode; undefined otherwise. */
31
- getCommandLine(): string | undefined;
32
- /**
33
- * Drop to INSERT (the app calls this after an external edit-in-vim so
34
- * the mode agrees with the restored composer focus).
35
- */
36
- enterInsertMode(): void;
37
- }
38
- /** Options for {@link createVimKeymap}. */
39
- export interface VimKeymapOptions {
40
- /**
41
- * The slash-command catalog's names (C3's picker source); they join
42
- * COMMAND_NAMES in the Tab completion table as `"/"`-prefixed
43
- * entries. Defaults to none (the launcher fills a shared array once
44
- * the catalog fetch lands).
45
- */
46
- readonly catalogNames?: readonly string[];
47
- }
48
- export declare function createVimKeymap(options?: VimKeymapOptions): VimKeymap;
@@ -1,291 +0,0 @@
1
- /**
2
- * The vim keymap (Task C4, UI refresh): real insert/normal/command modes
3
- * over the C3 action layer. Starts in INSERT with the composer focused —
4
- * every key types through except Esc (→ NORMAL, focus transcript),
5
- * Ctrl+C (abort a live run; otherwise consumed — quitting is ZZ or :q),
6
- * and Ctrl+O (answer an interaction). Every {@link RESERVED_KEYS} chord
7
- * passes in INSERT (the composer's readline chords and the tmux prefix
8
- * are never shadowed; ctrl+b is NEVER bound anywhere).
9
- *
10
- * NORMAL owns the transcript/list: j/k move, h/l focus list/transcript,
11
- * ctrl+d/ctrl+u half-page (bound here — RESERVED exists to protect the
12
- * composer's editing, and in NORMAL the composer is not focused),
13
- * gg/G edges, {/} prompt jumps, Enter/za fold, o open, y/yy copy,
14
- * f fork, e edit, v edit-in-vim, //?/n/N search, i/a back to INSERT,
15
- * `:` the command line, ctrl+p picker, ctrl+l redraw, ZZ quit. UNBOUND
16
- * PRINTABLE KEYS ARE CONSUMED — they must never leak into the composer.
17
- *
18
- * COMMAND accumulates a line after `:` (the app renders ":"+buffer in
19
- * the status bar via {@link VimKeymap.getCommandLine}); Enter dispatches
20
- * run-command, Esc cancels, Tab completes the command name.
21
- *
22
- * The two-key chords (gg, yy, za, ZZ) share one pending-key window of
23
- * 500 ms; a timed-out or mismatched prefix is consumed silently.
24
- */
25
- import { Key, matchesKey } from "@earendil-works/pi-tui";
26
- import { RESERVED_KEYS } from "./types.js";
27
- /** The two-key chord window (gg, yy, za, ZZ). */
28
- const CHORD_MS = 500;
29
- /** The command-mode completion table (Tab completes the command name). */
30
- const COMMAND_NAMES = ["new", "fork", "model", "set", "b", "ls", "q", "quit"];
31
- const BINDINGS = [
32
- { keys: "esc (insert)", action: "normal mode" },
33
- { keys: "i / a", action: "insert mode" },
34
- { keys: "j / k", action: "move down / up" },
35
- { keys: "h / l", action: "focus list / transcript" },
36
- { keys: "ctrl+d / ctrl+u", action: "half page down / up" },
37
- { keys: "gg / G", action: "top / bottom" },
38
- { keys: "{ / }", action: "previous / next prompt" },
39
- { keys: "enter / za", action: "toggle fold" },
40
- { keys: "o", action: "open" },
41
- { keys: "y / yy", action: "copy turn" },
42
- { keys: "f", action: "fork here" },
43
- { keys: "e", action: "edit here" },
44
- { keys: "v", action: "edit in vim" },
45
- { keys: "/ / ?", action: "search forward / backward" },
46
- { keys: "n / N", action: "next / previous match" },
47
- { keys: ":", action: "command line" },
48
- { keys: "ctrl+p", action: "conversation picker" },
49
- { keys: "ctrl+o", action: "answer interaction" },
50
- { keys: "ctrl+l", action: "redraw" },
51
- { keys: "ctrl+c", action: "abort run (busy)" },
52
- { keys: "g?", action: "key reference" },
53
- { keys: "ZZ / :q", action: "quit" },
54
- { keys: "m", action: "pick up (block surface)" },
55
- { keys: "enter", action: "drop (block surface)" },
56
- { keys: "esc", action: "cancel move (block surface)" },
57
- { keys: "space", action: "select (block surface)" },
58
- { keys: ".", action: "action menu (block surface)" },
59
- { keys: "x", action: "check (block surface)" },
60
- { keys: "[ / ]", action: "previous / next range (calendar)" },
61
- { keys: "t", action: "today (calendar)" },
62
- ];
63
- function isReserved(data) {
64
- return RESERVED_KEYS.some((id) => matchesKey(data, id));
65
- }
66
- /** A printable single character (space through ~, plus unicode text). */
67
- function isPrintable(data) {
68
- return data.length === 1 && data >= " ";
69
- }
70
- export function createVimKeymap(options) {
71
- const catalogNames = options?.catalogNames ?? [];
72
- /** Tab completion table: the vim-native commands plus `/`-catalog names. */
73
- const completionNames = () => [
74
- ...COMMAND_NAMES,
75
- ...catalogNames.map((name) => `/${name}`),
76
- ];
77
- let mode = "insert";
78
- let commandLine = "";
79
- /** The pending chord prefix ("g" | "y" | "z" | "Z") and its timestamp. */
80
- let pending;
81
- /**
82
- * Resolve the pending two-key chord (gg → top, ZZ → quit, za → fold)
83
- * against `data`. Returns the chord's action, "consume" when `data`
84
- * STARTS a chord, or undefined to process `data` fresh (a mismatched
85
- * or timed-out follow-up).
86
- */
87
- const chord = (data) => {
88
- const now = Date.now();
89
- if (pending !== undefined) {
90
- const prefix = pending;
91
- pending = undefined;
92
- if (now - prefix.at <= CHORD_MS) {
93
- if (prefix.key === "g" && data === "g")
94
- return { type: "edge", to: "top" };
95
- // g? is vim normal's help key — "?" stays search-backward.
96
- if (prefix.key === "g" && data === "?")
97
- return { type: "help" };
98
- if (prefix.key === "Z" && data === "Z")
99
- return { type: "quit" };
100
- if (prefix.key === "z" && data === "a")
101
- return { type: "toggle-fold" };
102
- }
103
- // Mismatch/timeout: `data` is processed fresh below.
104
- }
105
- if (data === "g" || data === "Z" || data === "z") {
106
- pending = { key: data, at: now };
107
- return "consume";
108
- }
109
- return undefined;
110
- };
111
- const insert = (data, ctx) => {
112
- // The composer's readline chords + the tmux prefix: NEVER bound.
113
- if (isReserved(data))
114
- return "pass";
115
- if (matchesKey(data, Key.escape)) {
116
- if (ctx.autocompleteOpen)
117
- return "pass";
118
- mode = "normal";
119
- return { type: "focus", target: "transcript" };
120
- }
121
- if (matchesKey(data, Key.ctrl("c"))) {
122
- return ctx.busy ? { type: "cancel-run" } : "consume";
123
- }
124
- if (matchesKey(data, Key.ctrl("o")))
125
- return { type: "answer-interaction" };
126
- return "pass";
127
- };
128
- /** Block-surface keys (spec §12.4): NORMAL mode over a `surface`
129
- * focus. The surface wins over transcript/list bindings for the
130
- * shared keys (o/x/etc). */
131
- const surfaceNormal = (data) => {
132
- if (data === "m")
133
- return { type: "blocks.pickUp" };
134
- if (matchesKey(data, Key.enter))
135
- return { type: "blocks.drop" };
136
- if (matchesKey(data, Key.escape))
137
- return { type: "blocks.cancelMove" };
138
- if (data === " ")
139
- return { type: "blocks.select" };
140
- if (data === ".")
141
- return { type: "blocks.actionMenu" };
142
- if (data === "x")
143
- return { type: "blocks.check" };
144
- if (data === "[")
145
- return { type: "blocks.rangePrev" };
146
- if (data === "]")
147
- return { type: "blocks.rangeNext" };
148
- if (data === "t")
149
- return { type: "blocks.today" };
150
- return undefined;
151
- };
152
- const normal = (data, ctx) => {
153
- // ctrl+b / ctrl+f are NOT bound in vim normal — reserved chords pass.
154
- const chorded = chord(data);
155
- if (chorded !== undefined)
156
- return chorded;
157
- if (ctx.focus === "surface") {
158
- const surfaceResult = surfaceNormal(data);
159
- if (surfaceResult !== undefined)
160
- return surfaceResult;
161
- }
162
- if (data === "y")
163
- return { type: "copy" }; // yy is two copies — same action
164
- if (data === "j")
165
- return { type: "move", delta: 1 };
166
- if (data === "k")
167
- return { type: "move", delta: -1 };
168
- if (data === "h")
169
- return { type: "focus", target: "list" };
170
- if (data === "l")
171
- return { type: "focus", target: "transcript" };
172
- if (matchesKey(data, Key.ctrl("d")))
173
- return { type: "page", direction: 1, half: true };
174
- if (matchesKey(data, Key.ctrl("u")))
175
- return { type: "page", direction: -1, half: true };
176
- if (data === "G")
177
- return { type: "edge", to: "bottom" };
178
- if (data === "{")
179
- return { type: "prompt-jump", delta: -1 };
180
- if (data === "}")
181
- return { type: "prompt-jump", delta: 1 };
182
- if (matchesKey(data, Key.enter))
183
- return { type: "toggle-fold" };
184
- if (data === "o")
185
- return { type: "open" };
186
- if (data === "f")
187
- return { type: "fork-here" };
188
- if (data === "e")
189
- return { type: "edit-here" };
190
- if (data === "v")
191
- return { type: "edit-in-vim" };
192
- if (data === "/")
193
- return { type: "search", direction: "forward" };
194
- if (data === "?")
195
- return { type: "search", direction: "backward" };
196
- if (data === "n")
197
- return { type: "search-next", reverse: false };
198
- if (data === "N")
199
- return { type: "search-next", reverse: true };
200
- if (data === "i" || data === "a") {
201
- mode = "insert";
202
- return { type: "focus", target: "composer" };
203
- }
204
- if (data === ":") {
205
- mode = "command";
206
- commandLine = "";
207
- return "consume";
208
- }
209
- if (matchesKey(data, Key.ctrl("p")))
210
- return { type: "picker", kind: "conversation" };
211
- if (matchesKey(data, Key.ctrl("l")))
212
- return { type: "redraw" };
213
- if (matchesKey(data, Key.ctrl("c"))) {
214
- return ctx.busy ? { type: "cancel-run" } : "consume";
215
- }
216
- // Reserved chords the composer owns pass even here (they are no-ops
217
- // in a non-composer focus, but the invariant is one rule).
218
- if (isReserved(data))
219
- return "pass";
220
- // UNBOUND PRINTABLE KEYS ARE CONSUMED: never typed into the composer.
221
- if (isPrintable(data))
222
- return "consume";
223
- return "consume";
224
- };
225
- const command = (data) => {
226
- if (matchesKey(data, Key.escape)) {
227
- mode = "normal";
228
- commandLine = "";
229
- return "consume";
230
- }
231
- if (matchesKey(data, Key.enter) || data === "\r") {
232
- const line = commandLine;
233
- mode = "normal";
234
- commandLine = "";
235
- if (line.trim() === "")
236
- return "consume";
237
- return { type: "run-command", line };
238
- }
239
- if (matchesKey(data, Key.backspace) || data === "\x7f" || data === "\b") {
240
- commandLine = commandLine.slice(0, -1);
241
- return "consume";
242
- }
243
- if (matchesKey(data, Key.tab) || data === "\t") {
244
- const match = completionNames().find((name) => name.startsWith(commandLine) && name !== commandLine);
245
- if (match !== undefined)
246
- commandLine = match;
247
- return "consume";
248
- }
249
- if (isPrintable(data)) {
250
- commandLine += data;
251
- return "consume";
252
- }
253
- return "consume";
254
- };
255
- return {
256
- name: "vim",
257
- get mode() {
258
- return mode;
259
- },
260
- getCommandLine: () => (mode === "command" ? `:${commandLine}` : undefined),
261
- enterInsertMode: () => {
262
- mode = "insert";
263
- },
264
- modeLabel: () => {
265
- if (mode === "insert")
266
- return "-- INSERT --";
267
- if (mode === "normal")
268
- return "-- NORMAL --";
269
- return undefined; // the status bar shows the ":" line instead
270
- },
271
- handle(data, ctx) {
272
- // A modal overlay owns the keys; only its cancel key is held back.
273
- if (ctx.overlayOpen) {
274
- return matchesKey(data, Key.escape) ? "consume" : "pass";
275
- }
276
- if (mode === "insert")
277
- return insert(data, ctx);
278
- if (mode === "normal")
279
- return normal(data, ctx);
280
- return command(data);
281
- },
282
- hints(ctx) {
283
- if (mode === "command")
284
- return ["enter run", "esc cancel", "tab complete"];
285
- if (mode === "insert" || ctx.focus === "composer")
286
- return ["Esc normal"];
287
- return ["i insert", ": command", "g? keys"];
288
- },
289
- describe: () => BINDINGS,
290
- };
291
- }
package/dist/launch.d.ts DELETED
@@ -1,149 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * The TUI entry the CLI's default `launchTui` runs (Task 6): boot the
4
- * pi-tui fullscreen alt-screen renderer (task C1b — the terminal scrollback
5
- * is gone for the session; the app owns the viewport), mount the layout
6
- * root, and resolve when the user exits (ctrl+c). The CLI's `run`
7
- * lifecycle owns the shutdown from there — this promise resolving IS the
8
- * exit signal. There is no main-screen fallback.
9
- *
10
- * As of build-and-webui Task 2 this file is ALSO the package's bin
11
- * (`sigrun-tui` → `dist/launch.js`): the CLI no longer imports
12
- * `launchTuiShell` in-process — it spawns this bin as a child process
13
- * (`node <resolved dist/launch.js>`), passing the resolved server URL,
14
- * user, and tui.json UI fields as `--flags`. Run standalone, the bin
15
- * resolves them itself: `--server`/`SIGRUN_SERVER` (default
16
- * `http://localhost:$SIGRUN_PORT` or 3000) and `--user`/`SIGRUN_USER`.
17
- *
18
- * Layout (task C1b): `tui.setLayoutRoot(new VStack([...]))` — the body row
19
- * (`HStack`: the sidebar at basis 28, visible only at width ≥ 80, and the
20
- * pane wrapped in the follow-end PRIMARY ScrollView growing to fill), then
21
- * the interaction + ambient seam strips (basis "auto" — zero height when
22
- * empty), the composer Editor (basis "auto"), and the status bar pinned to
23
- * one line at the bottom (basis 1).
24
- *
25
- * Keybindings: BEFORE the screen is constructed, the alt-screen built-ins
26
- * the action layer will own are disabled (search, search next/previous,
27
- * previous/next prompt — the built-ins search raw lines and jump OSC 133
28
- * marks sigrun never emits); pageUp/pageDown/ctrl+home/ctrl+end scrolling
29
- * and the wheel stay. The shell's global input listener keeps ctrl+c
30
- * (exit), ctrl+o (answer mode), and Esc (abort a live run); task C3's
31
- * action layer reintroduces navigation — until then the composer is the
32
- * focus and the mouse drives the sidebar.
33
- *
34
- * Test seams (the shell itself needs a real terminal): `screen` injects
35
- * the screen constructor (tests assert TuiAltScreen's arguments), and
36
- * `terminal`/`fetchFn` inject the terminal and boot fetch. Production
37
- * callers pass none of them.
38
- */
39
- import { type Component, type Terminal, type TuiAltScreenOptions } from "@earendil-works/pi-tui";
40
- import { type AccentName, type ModeName, type PaletteName } from "@sigrun/shared/themes";
41
- import { type FetchLike } from "./api.js";
42
- /** The input-listener signature pi-tui's TUI uses. */
43
- export type TuiInputListenerFn = (data: string) => {
44
- consume: boolean;
45
- } | undefined;
46
- /** The screen surface the launcher drives (a TuiAltScreen satisfies it). */
47
- export interface TuiScreen extends Component {
48
- setLayoutRoot(component: Component | undefined): void;
49
- setFocus(component: Component | null): void;
50
- start(): void;
51
- stop(options?: {
52
- preserveScreen?: boolean;
53
- }): void;
54
- requestRender(force?: boolean): void;
55
- addInputListener(listener: TuiInputListenerFn): () => void;
56
- }
57
- /**
58
- * The screen-constructor seam (task C1b): matches TuiAltScreen's
59
- * constructor signature so tests can record the arguments without a real
60
- * terminal. Production uses `TuiAltScreen` itself.
61
- */
62
- export type TuiScreenFactory = (terminal: Terminal, showHardwareCursor?: boolean, logDirectory?: string, options?: TuiAltScreenOptions) => TuiScreen;
63
- export interface LaunchTuiShellOptions {
64
- /** The server's base URL (`SigrunClient`'s `baseUrl`). */
65
- readonly baseUrl: string;
66
- /** The `X-Sigrun-User` identity; absent = the server's naive mode. */
67
- readonly user?: string;
68
- /**
69
- * The bearer token (Task 7): `authorization: Bearer` on every client
70
- * request and the stream connect. The launcher sources it from env
71
- * `SIGRUN_TOKEN` — a credential never rides argv.
72
- */
73
- readonly token?: string;
74
- /** The UI refresh's tui.json fields (C1a threads them in from the CLI). */
75
- readonly palette?: PaletteName;
76
- readonly accent?: AccentName;
77
- readonly mode?: ModeName;
78
- /** The keymap (C3); defaults to the standard one. */
79
- readonly keymap?: "standard" | "vim" | "emacs";
80
- /** The tui.json `editor` field (C1); a vim-family value feeds edit-in-vim. */
81
- readonly editor?: string;
82
- /** TEST SEAM: the screen constructor (defaults to TuiAltScreen). */
83
- readonly screen?: TuiScreenFactory;
84
- /** TEST SEAM: the terminal (defaults to ProcessTerminal). */
85
- readonly terminal?: Terminal;
86
- /** TEST SEAM: the boot fetch (defaults to the ambient fetch). */
87
- readonly fetchFn?: FetchLike;
88
- }
89
- /**
90
- * The stream-health transition notices (fix wave F5): state-deduped, so a
91
- * reconnect storm shows ONE "disconnected" and ONE "reconnected", never a
92
- * pane full of retries. Exported for the unit test (the shell itself needs
93
- * a real terminal).
94
- */
95
- export declare function createStreamHealthNotices(notify: (message: string) => void): {
96
- onError(): void;
97
- onOpen(): void;
98
- };
99
- /**
100
- * Run the shell against `baseUrl` until the user exits. Boot failures
101
- * (the initial refresh rejecting) propagate — the CLI prints and exits 1.
102
- */
103
- export declare function launchTuiShell(options: LaunchTuiShellOptions): Promise<void>;
104
- /**
105
- * The flags {@link tuiMain} accepts. The CLI passes the fields it
106
- * resolved (tui.json + its own flags) through these; a standalone
107
- * invocation may pass any subset.
108
- */
109
- export interface TuiLaunchArgs {
110
- readonly server?: string;
111
- readonly user?: string;
112
- readonly palette?: PaletteName;
113
- readonly accent?: AccentName;
114
- readonly mode?: ModeName;
115
- readonly keymap?: "standard" | "vim" | "emacs";
116
- readonly editor?: string;
117
- }
118
- /**
119
- * Parse the bin's argv (post-`node` slices): every entry must be a known
120
- * flag followed by a value. A validator returning `undefined` means the
121
- * VALUE was malformed for that flag (not a parse-usage error) — it is
122
- * reported naming the flag's expected form.
123
- */
124
- export declare function parseTuiLaunchArgs(argv: readonly string[]): TuiLaunchArgs;
125
- /**
126
- * Resolve the bin's launch options from its parsed flags + environment
127
- * (Task 7): server (`--server` > `SIGRUN_SERVER` > the localhost default),
128
- * user (`--user` > `SIGRUN_USER`), token (`SIGRUN_TOKEN` ONLY — there is
129
- * deliberately no `--token` flag; a credential never rides argv), and
130
- * the tui.json UI fields the CLI threads through as flags.
131
- */
132
- export declare function launchOptionsFrom(args: TuiLaunchArgs, env: NodeJS.ProcessEnv): LaunchTuiShellOptions;
133
- /**
134
- * The dedicated startup-failure message for a server still in its
135
- * unclaimed state (Task 7): a standalone `sigrun-tui` that hits the
136
- * setup gate exits with the `sigrun attach` onboarding hint instead of
137
- * a bare 403. Any other failure maps to `undefined` (the generic path).
138
- */
139
- export declare function tuiStartupMessage(error: unknown): string | undefined;
140
- /**
141
- * The bin's `main`: resolve the launch options (flags + env, see
142
- * {@link launchOptionsFrom}) and run {@link launchTuiShell}. Returns the
143
- * process exit code (0 clean; 1 on a usage error or a boot failure,
144
- * with the message printed — the setup-gate failure carries its own
145
- * `sigrun attach` onboarding hint).
146
- */
147
- export declare function tuiMain(argv?: readonly string[], env?: NodeJS.ProcessEnv, io?: {
148
- error(text: string): void;
149
- }): Promise<number>;