arc402-cli 0.8.0 → 0.9.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/INK6-UX-SPEC.md +446 -0
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +43 -3
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Header.d.ts +1 -1
- package/dist/tui/Header.d.ts.map +1 -1
- package/dist/tui/Header.js +6 -5
- package/dist/tui/Header.js.map +1 -1
- package/dist/tui/InputLine.d.ts +1 -2
- package/dist/tui/InputLine.d.ts.map +1 -1
- package/dist/tui/InputLine.js +76 -24
- package/dist/tui/InputLine.js.map +1 -1
- package/dist/tui/components/Button.d.ts +7 -0
- package/dist/tui/components/Button.d.ts.map +1 -0
- package/dist/tui/components/Button.js +18 -0
- package/dist/tui/components/Button.js.map +1 -0
- package/dist/tui/components/CeremonyView.d.ts +13 -0
- package/dist/tui/components/CeremonyView.d.ts.map +1 -0
- package/dist/tui/components/CeremonyView.js +7 -0
- package/dist/tui/components/CeremonyView.js.map +1 -0
- package/dist/tui/components/CompletionDropdown.d.ts +7 -0
- package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
- package/dist/tui/components/CompletionDropdown.js +20 -0
- package/dist/tui/components/CompletionDropdown.js.map +1 -0
- package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
- package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
- package/dist/tui/components/ConfirmPrompt.js +7 -0
- package/dist/tui/components/ConfirmPrompt.js.map +1 -0
- package/dist/tui/components/InteractiveTable.d.ts +14 -0
- package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
- package/dist/tui/components/InteractiveTable.js +58 -0
- package/dist/tui/components/InteractiveTable.js.map +1 -0
- package/dist/tui/components/StepSpinner.d.ts +11 -0
- package/dist/tui/components/StepSpinner.d.ts.map +1 -0
- package/dist/tui/components/StepSpinner.js +29 -0
- package/dist/tui/components/StepSpinner.js.map +1 -0
- package/dist/tui/components/Toast.d.ts +18 -0
- package/dist/tui/components/Toast.d.ts.map +1 -0
- package/dist/tui/components/Toast.js +25 -0
- package/dist/tui/components/Toast.js.map +1 -0
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +15 -1
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/useNotifications.d.ts +9 -0
- package/dist/tui/useNotifications.d.ts.map +1 -0
- package/dist/tui/useNotifications.js +14 -0
- package/dist/tui/useNotifications.js.map +1 -0
- package/dist/ui/banner.d.ts +12 -0
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +23 -0
- package/dist/ui/banner.js.map +1 -1
- package/package.json +1 -1
- package/src/tui/App.tsx +53 -9
- package/src/tui/Header.tsx +25 -4
- package/src/tui/InputLine.tsx +107 -32
- package/src/tui/components/Button.tsx +38 -0
- package/src/tui/components/CeremonyView.tsx +39 -0
- package/src/tui/components/CompletionDropdown.tsx +59 -0
- package/src/tui/components/ConfirmPrompt.tsx +36 -0
- package/src/tui/components/InteractiveTable.tsx +112 -0
- package/src/tui/components/StepSpinner.tsx +84 -0
- package/src/tui/components/Toast.tsx +59 -0
- package/src/tui/index.tsx +20 -1
- package/src/tui/useNotifications.ts +28 -0
- package/src/ui/banner.ts +27 -0
package/INK6-UX-SPEC.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# Ink 6 UX Enhancement Spec
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
CLI is now on Ink 6 + React 19 + ESM. The WalletConnect native component exists.
|
|
5
|
+
This spec covers ALL remaining Ink 6 UX capabilities to build before the article demo.
|
|
6
|
+
|
|
7
|
+
## Current TUI Architecture
|
|
8
|
+
```
|
|
9
|
+
src/tui/
|
|
10
|
+
├── App.tsx — Root component, layout, command dispatch
|
|
11
|
+
├── Header.tsx — ASCII banner + network/wallet/balance
|
|
12
|
+
├── Viewport.tsx — Scrollable output buffer
|
|
13
|
+
├── InputLine.tsx — Text input with history + tab completion
|
|
14
|
+
├── Footer.tsx — Footer wrapper
|
|
15
|
+
├── WalletConnectPairing.tsx — Native WC QR + status (new from Phase 3)
|
|
16
|
+
├── index.tsx — TUI launcher
|
|
17
|
+
├── useCommand.ts — Command dispatch (in-process + child process)
|
|
18
|
+
├── useChat.ts — Chat gateway integration
|
|
19
|
+
└── useScroll.ts — Viewport scroll state
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Feature 1: Full-Screen Mode
|
|
25
|
+
|
|
26
|
+
### What
|
|
27
|
+
Use Ink 6's `fullScreen` option on `render()` to use the alternate screen buffer.
|
|
28
|
+
|
|
29
|
+
### Why
|
|
30
|
+
- Clean entry: terminal history preserved, TUI gets a blank canvas
|
|
31
|
+
- Clean exit: original terminal content restored
|
|
32
|
+
- Proper resize: Ink reflows on SIGWINCH in full-screen mode
|
|
33
|
+
- No visual artifacts from previous commands bleeding into the TUI
|
|
34
|
+
|
|
35
|
+
### Implementation
|
|
36
|
+
In `src/tui/index.tsx`, change the render call:
|
|
37
|
+
```tsx
|
|
38
|
+
const { waitUntilExit } = render(<App ... />, {
|
|
39
|
+
exitOnCtrlC: true,
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
Ink 6's `render()` supports a second options argument. Check if `fullScreen` is a boolean option or if it's handled via `<Box height="100%">` with the alternate buffer.
|
|
43
|
+
|
|
44
|
+
If Ink 6 doesn't have a built-in fullScreen option, implement manually:
|
|
45
|
+
```tsx
|
|
46
|
+
// Enter alternate buffer
|
|
47
|
+
process.stdout.write('\x1b[?1049h');
|
|
48
|
+
// ... render ...
|
|
49
|
+
// On exit, restore
|
|
50
|
+
process.stdout.write('\x1b[?1049l');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Files to change
|
|
54
|
+
- `src/tui/index.tsx` — add alternate screen buffer enter/exit
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Feature 2: Static Banner with `<Static>`
|
|
59
|
+
|
|
60
|
+
### What
|
|
61
|
+
Wrap the ASCII art banner in Ink's `<Static>` component so it renders once and never re-renders.
|
|
62
|
+
|
|
63
|
+
### Why
|
|
64
|
+
- The banner is ~12 lines of ASCII art that NEVER changes after launch
|
|
65
|
+
- Currently re-renders on every state change (output buffer update, scroll, input change)
|
|
66
|
+
- `<Static>` renders items once above the dynamic area — perfect for the banner
|
|
67
|
+
|
|
68
|
+
### Implementation
|
|
69
|
+
In `App.tsx`, replace the `<Header>` component with a `<Static>` block:
|
|
70
|
+
```tsx
|
|
71
|
+
import { Static } from "ink";
|
|
72
|
+
|
|
73
|
+
// Banner lines computed once
|
|
74
|
+
const [bannerItems] = useState(() => getBannerLines({ network, wallet, balance }));
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Box flexDirection="column" height="100%">
|
|
78
|
+
<Static items={bannerItems}>
|
|
79
|
+
{(line, i) => <Text key={i}>{line}</Text>}
|
|
80
|
+
</Static>
|
|
81
|
+
<Text>{separator}</Text>
|
|
82
|
+
<Viewport ... />
|
|
83
|
+
<Text>{separator}</Text>
|
|
84
|
+
<InputLine ... />
|
|
85
|
+
</Box>
|
|
86
|
+
);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Files to change
|
|
90
|
+
- `src/tui/App.tsx` — use `<Static>` for banner
|
|
91
|
+
- `src/tui/Header.tsx` — may become unnecessary (inline into App)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Feature 3: Spinner Components for Deploy Ceremony
|
|
96
|
+
|
|
97
|
+
### What
|
|
98
|
+
Create reusable `<StepSpinner>` and `<StepComplete>` components for multi-step flows.
|
|
99
|
+
|
|
100
|
+
### Why
|
|
101
|
+
The deploy + onboarding ceremony has 8+ sequential steps. Each should show:
|
|
102
|
+
- `◈ Step 3/8 — Setting guardian...` (spinning) while in progress
|
|
103
|
+
- `✓ Step 3/8 — Guardian set` (static) when done
|
|
104
|
+
- `✗ Step 3/8 — Failed: reason` (static) on error
|
|
105
|
+
|
|
106
|
+
### Implementation
|
|
107
|
+
Create `src/tui/components/StepSpinner.tsx`:
|
|
108
|
+
```tsx
|
|
109
|
+
interface StepSpinnerProps {
|
|
110
|
+
step: number;
|
|
111
|
+
total: number;
|
|
112
|
+
label: string;
|
|
113
|
+
status: "pending" | "running" | "done" | "error";
|
|
114
|
+
detail?: string; // e.g. tx hash, address
|
|
115
|
+
error?: string;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Uses Ink's built-in spinner frames (or a simple `◈ ◇ ◆ ◈` cycle):
|
|
120
|
+
```
|
|
121
|
+
◈ Step 1/8 — Deploying wallet...
|
|
122
|
+
✓ Step 1/8 — Wallet deployed
|
|
123
|
+
└ 0xA34B...a5dc
|
|
124
|
+
◈ Step 2/8 — Authorizing machine key...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Create `src/tui/components/CeremonyView.tsx`:
|
|
128
|
+
A container that manages the step list and renders each StepSpinner.
|
|
129
|
+
```tsx
|
|
130
|
+
interface CeremonyStep {
|
|
131
|
+
label: string;
|
|
132
|
+
status: "pending" | "running" | "done" | "error";
|
|
133
|
+
detail?: string;
|
|
134
|
+
error?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface CeremonyViewProps {
|
|
138
|
+
title: string;
|
|
139
|
+
steps: CeremonyStep[];
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Files to create
|
|
144
|
+
- `src/tui/components/StepSpinner.tsx`
|
|
145
|
+
- `src/tui/components/CeremonyView.tsx`
|
|
146
|
+
|
|
147
|
+
### Integration
|
|
148
|
+
Wire into `useCommand.ts` — when `wallet deploy` runs, instead of spawning a child process, render `<CeremonyView>` in the viewport with steps updating via React state.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Feature 4: Focus Management (`useFocus` / `useFocusManager`)
|
|
153
|
+
|
|
154
|
+
### What
|
|
155
|
+
Tab-navigable interactive elements in the TUI.
|
|
156
|
+
|
|
157
|
+
### Why
|
|
158
|
+
- Deploy wizard: Tab between "Confirm" / "Cancel" / "Change settings"
|
|
159
|
+
- WalletConnect: Tab between QR display and wallet link list
|
|
160
|
+
- Any confirmation prompt: focus on Yes/No buttons
|
|
161
|
+
|
|
162
|
+
### Implementation
|
|
163
|
+
Create `src/tui/components/Button.tsx`:
|
|
164
|
+
```tsx
|
|
165
|
+
interface ButtonProps {
|
|
166
|
+
label: string;
|
|
167
|
+
onPress: () => void;
|
|
168
|
+
variant?: "primary" | "danger" | "dim";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function Button({ label, onPress, variant = "primary" }: ButtonProps) {
|
|
172
|
+
const { isFocused } = useFocus();
|
|
173
|
+
return (
|
|
174
|
+
<Box>
|
|
175
|
+
<Text
|
|
176
|
+
color={isFocused ? "cyan" : "white"}
|
|
177
|
+
bold={isFocused}
|
|
178
|
+
>
|
|
179
|
+
{isFocused ? "▸ " : " "}{label}
|
|
180
|
+
</Text>
|
|
181
|
+
</Box>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Create `src/tui/components/ConfirmPrompt.tsx`:
|
|
187
|
+
```tsx
|
|
188
|
+
interface ConfirmPromptProps {
|
|
189
|
+
message: string;
|
|
190
|
+
onConfirm: () => void;
|
|
191
|
+
onCancel: () => void;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
Renders two focusable buttons. Enter on focused button triggers action.
|
|
195
|
+
|
|
196
|
+
### Files to create
|
|
197
|
+
- `src/tui/components/Button.tsx`
|
|
198
|
+
- `src/tui/components/ConfirmPrompt.tsx`
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Feature 5: Enhanced Input (useInput)
|
|
203
|
+
|
|
204
|
+
### What
|
|
205
|
+
Better keyboard handling in the TUI.
|
|
206
|
+
|
|
207
|
+
### Why
|
|
208
|
+
- Ctrl+C: graceful shutdown (cleanup WC sessions, save state)
|
|
209
|
+
- Ctrl+L: clear viewport (like terminal clear)
|
|
210
|
+
- Page Up/Down: fast viewport scrolling
|
|
211
|
+
- Escape: cancel current operation / close prompts
|
|
212
|
+
|
|
213
|
+
### Implementation
|
|
214
|
+
In `App.tsx`, add a top-level `useInput` handler:
|
|
215
|
+
```tsx
|
|
216
|
+
useInput((input, key) => {
|
|
217
|
+
if (key.ctrl && input === 'l') {
|
|
218
|
+
setOutputBuffer([]);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (key.pageUp) {
|
|
222
|
+
scrollUp(viewportHeight);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (key.pageDown) {
|
|
226
|
+
scrollDown(viewportHeight);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (key.escape) {
|
|
230
|
+
// Cancel current operation if any
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Files to change
|
|
237
|
+
- `src/tui/App.tsx` — add useInput handler
|
|
238
|
+
- `src/tui/useScroll.ts` — expose page-size scroll functions
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Feature 6: FlexWrap for Status Bar
|
|
243
|
+
|
|
244
|
+
### What
|
|
245
|
+
Use `flexWrap="wrap"` on the header status info so it wraps on narrow terminals.
|
|
246
|
+
|
|
247
|
+
### Why
|
|
248
|
+
`Network Base Mainnet Wallet 0xa9e0...83bE Balance 0.0042 ETH`
|
|
249
|
+
On a narrow terminal this truncates. With flexWrap it becomes:
|
|
250
|
+
```
|
|
251
|
+
Network Base Mainnet
|
|
252
|
+
Wallet 0xa9e0...83bE
|
|
253
|
+
Balance 0.0042 ETH
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Implementation
|
|
257
|
+
In the banner/header, wrap status items in a `<Box flexWrap="wrap">`:
|
|
258
|
+
```tsx
|
|
259
|
+
<Box flexWrap="wrap" columnGap={2}>
|
|
260
|
+
<Box><Text dimColor>Network</Text><Text> {network}</Text></Box>
|
|
261
|
+
<Box><Text dimColor>Wallet</Text><Text> {wallet}</Text></Box>
|
|
262
|
+
<Box><Text dimColor>Balance</Text><Text> {balance}</Text></Box>
|
|
263
|
+
</Box>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Files to change
|
|
267
|
+
- `src/ui/banner.ts` — return structured data instead of pre-formatted strings
|
|
268
|
+
- `src/tui/Header.tsx` — use flexWrap Box layout
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Feature 7: Notification Toasts
|
|
273
|
+
|
|
274
|
+
### What
|
|
275
|
+
Non-blocking notifications that appear briefly in the TUI when background events occur.
|
|
276
|
+
|
|
277
|
+
### Why
|
|
278
|
+
When the daemon is running and receives a hire request, dispute, or payment — show it.
|
|
279
|
+
|
|
280
|
+
### Implementation
|
|
281
|
+
Create `src/tui/components/Toast.tsx`:
|
|
282
|
+
```tsx
|
|
283
|
+
interface ToastProps {
|
|
284
|
+
message: string;
|
|
285
|
+
variant: "info" | "success" | "warning" | "error";
|
|
286
|
+
duration?: number; // ms, default 5000
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Create `src/tui/useNotifications.ts`:
|
|
291
|
+
```tsx
|
|
292
|
+
function useNotifications() {
|
|
293
|
+
const [toasts, setToasts] = useState<Toast[]>([]);
|
|
294
|
+
const push = (toast: Omit<Toast, "id">) => { ... };
|
|
295
|
+
const dismiss = (id: string) => { ... };
|
|
296
|
+
return { toasts, push, dismiss };
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Toasts render in a fixed position above the input line, auto-dismiss after duration.
|
|
301
|
+
|
|
302
|
+
### Files to create
|
|
303
|
+
- `src/tui/components/Toast.tsx`
|
|
304
|
+
- `src/tui/useNotifications.ts`
|
|
305
|
+
|
|
306
|
+
### Integration
|
|
307
|
+
The daemon WebSocket connection (if running) emits events → push toast.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Feature 8: Tab-Completion Dropdown
|
|
312
|
+
|
|
313
|
+
### What
|
|
314
|
+
Show a dropdown list of completion candidates when Tab is pressed.
|
|
315
|
+
|
|
316
|
+
### Why
|
|
317
|
+
Current tab completion silently completes in the input. Users don't know what's available.
|
|
318
|
+
|
|
319
|
+
### Implementation
|
|
320
|
+
Create `src/tui/components/CompletionDropdown.tsx`:
|
|
321
|
+
```tsx
|
|
322
|
+
interface CompletionDropdownProps {
|
|
323
|
+
candidates: string[];
|
|
324
|
+
selectedIndex: number;
|
|
325
|
+
visible: boolean;
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Renders a floating box above the input line showing matching commands:
|
|
330
|
+
```
|
|
331
|
+
wallet deploy
|
|
332
|
+
wallet status
|
|
333
|
+
wallet balance
|
|
334
|
+
wallet freeze
|
|
335
|
+
◈ arc402 > wallet d_
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Arrow keys navigate, Tab/Enter selects, Escape dismisses.
|
|
339
|
+
|
|
340
|
+
### Files to create
|
|
341
|
+
- `src/tui/components/CompletionDropdown.tsx`
|
|
342
|
+
|
|
343
|
+
### Files to change
|
|
344
|
+
- `src/tui/InputLine.tsx` — manage dropdown state, render above input
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Feature 9: Interactive Tables
|
|
349
|
+
|
|
350
|
+
### What
|
|
351
|
+
Scrollable, selectable table component for list views.
|
|
352
|
+
|
|
353
|
+
### Why
|
|
354
|
+
`discover`, `agreements list`, `wallet list`, `list-machine-keys` all return tabular data.
|
|
355
|
+
Currently rendered as plain text. Should be interactive: arrow keys to navigate rows, Enter to drill in.
|
|
356
|
+
|
|
357
|
+
### Implementation
|
|
358
|
+
Create `src/tui/components/InteractiveTable.tsx`:
|
|
359
|
+
```tsx
|
|
360
|
+
interface Column {
|
|
361
|
+
header: string;
|
|
362
|
+
key: string;
|
|
363
|
+
width?: number;
|
|
364
|
+
align?: "left" | "right";
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
interface InteractiveTableProps {
|
|
368
|
+
columns: Column[];
|
|
369
|
+
rows: Record<string, string>[];
|
|
370
|
+
onSelect?: (row: Record<string, string>, index: number) => void;
|
|
371
|
+
selectedIndex?: number;
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Renders with box-drawing borders for the header row:
|
|
376
|
+
```
|
|
377
|
+
Agent Service Trust Endpoint
|
|
378
|
+
─────────────────────────────────────────────────
|
|
379
|
+
▸ GigaBrain intelligence 850 gigabrain.arc402.xyz
|
|
380
|
+
CodeReviewer code.review 720 reviewer.arc402.xyz
|
|
381
|
+
DataOracle data.feed 690 oracle.arc402.xyz
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Files to create
|
|
385
|
+
- `src/tui/components/InteractiveTable.tsx`
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Feature 10: Split Pane (Future — Post-Launch)
|
|
390
|
+
|
|
391
|
+
### What
|
|
392
|
+
Side-by-side panes: command output left, daemon logs right.
|
|
393
|
+
|
|
394
|
+
### Why
|
|
395
|
+
Power users running the daemon want to see live events while issuing commands.
|
|
396
|
+
|
|
397
|
+
### Implementation (design only — build post-launch)
|
|
398
|
+
Create `src/tui/components/SplitPane.tsx`:
|
|
399
|
+
```tsx
|
|
400
|
+
interface SplitPaneProps {
|
|
401
|
+
left: React.ReactNode;
|
|
402
|
+
right: React.ReactNode;
|
|
403
|
+
ratio?: number; // 0.0-1.0, default 0.6
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Uses Ink 6's `<Box width="60%">` + `<Box width="40%">` for the split.
|
|
408
|
+
|
|
409
|
+
### Files to create (post-launch)
|
|
410
|
+
- `src/tui/components/SplitPane.tsx`
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Build Order
|
|
415
|
+
|
|
416
|
+
1. Full-screen mode (Feature 1) — foundational
|
|
417
|
+
2. Static banner (Feature 2) — performance
|
|
418
|
+
3. Enhanced input / keyboard (Feature 5) — UX basics
|
|
419
|
+
4. Spinner components (Feature 3) — deploy ceremony visual
|
|
420
|
+
5. Focus management + buttons (Feature 4) — interactive deploy wizard
|
|
421
|
+
6. FlexWrap status bar (Feature 6) — responsive layout
|
|
422
|
+
7. Tab-completion dropdown (Feature 8) — discoverability
|
|
423
|
+
8. Interactive tables (Feature 9) — list views
|
|
424
|
+
9. Notification toasts (Feature 7) — daemon integration
|
|
425
|
+
10. Split pane (Feature 10) — post-launch
|
|
426
|
+
|
|
427
|
+
Features 1-8 are for the article demo. Feature 9 is nice-to-have. Feature 10 is post-launch.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Testing Checklist
|
|
432
|
+
|
|
433
|
+
After build:
|
|
434
|
+
- [ ] `arc402` launches in full-screen mode, clean entry
|
|
435
|
+
- [ ] Ctrl+C exits cleanly, original terminal restored
|
|
436
|
+
- [ ] Ctrl+L clears viewport
|
|
437
|
+
- [ ] Page Up/Down scrolls viewport
|
|
438
|
+
- [ ] Tab shows completion dropdown
|
|
439
|
+
- [ ] `wallet deploy` shows QR inside viewport
|
|
440
|
+
- [ ] Deploy ceremony shows step spinners
|
|
441
|
+
- [ ] Confirmation prompts are focusable (Tab between buttons)
|
|
442
|
+
- [ ] `discover` renders interactive table
|
|
443
|
+
- [ ] Narrow terminal: status bar wraps correctly
|
|
444
|
+
- [ ] `exit` / `quit` restores terminal cleanly
|
|
445
|
+
- [ ] `arc402 wallet status` (one-shot mode) still works outside TUI
|
|
446
|
+
- [ ] `arc402 --help` still works
|
package/dist/tui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAmBA,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,2CAyOlE"}
|
package/dist/tui/App.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useCallback } from "react";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import { Box, Text, useApp } from "ink";
|
|
5
|
-
import { Header } from "./Header.js";
|
|
4
|
+
import { Box, Text, Static, useApp, useInput } from "ink";
|
|
6
5
|
import { Viewport } from "./Viewport.js";
|
|
7
6
|
import { Footer } from "./Footer.js";
|
|
8
7
|
import { InputLine } from "./InputLine.js";
|
|
9
8
|
import { useCommand } from "./useCommand.js";
|
|
10
9
|
import { useChat } from "./useChat.js";
|
|
11
10
|
import { useScroll } from "./useScroll.js";
|
|
11
|
+
import { useNotifications } from "./useNotifications.js";
|
|
12
|
+
import { ToastContainer } from "./components/Toast.js";
|
|
12
13
|
import { createProgram } from "../program.js";
|
|
14
|
+
import { getBannerArt, getStatusItems } from "../ui/banner.js";
|
|
13
15
|
import chalk from "chalk";
|
|
14
16
|
const pkg = createRequire(import.meta.url)("../../package.json");
|
|
15
17
|
const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
|
|
@@ -18,6 +20,30 @@ const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
|
|
|
18
20
|
*/
|
|
19
21
|
export function App({ version, network, wallet, balance }) {
|
|
20
22
|
const { exit } = useApp();
|
|
23
|
+
// Banner computed once — rendered via <Static> so it never re-renders
|
|
24
|
+
const [bannerData] = useState(() => {
|
|
25
|
+
const { artLines, subtitle, separator } = getBannerArt();
|
|
26
|
+
const statusItems = getStatusItems({ network, wallet, balance });
|
|
27
|
+
// Build static items: art lines + subtitle + separator + status + help hint
|
|
28
|
+
const items = [];
|
|
29
|
+
artLines.forEach((line, i) => items.push({ id: `art-${i}`, text: line }));
|
|
30
|
+
items.push({ id: "blank-1", text: "" });
|
|
31
|
+
items.push({ id: "subtitle", text: subtitle });
|
|
32
|
+
items.push({ id: "separator", text: separator });
|
|
33
|
+
if (statusItems.length > 0) {
|
|
34
|
+
items.push({ id: "blank-2", text: "" });
|
|
35
|
+
// Status items as a single formatted line for <Static>
|
|
36
|
+
// (FlexWrap rendering happens in the Header component for non-Static contexts)
|
|
37
|
+
const statusLine = statusItems
|
|
38
|
+
.map((s) => `\x1b[2m${s.label}\x1b[22m ${s.value}`)
|
|
39
|
+
.join(" ");
|
|
40
|
+
items.push({ id: "status", text: ` ${statusLine}` });
|
|
41
|
+
}
|
|
42
|
+
items.push({ id: "blank-3", text: "" });
|
|
43
|
+
items.push({ id: "hint", text: " \x1b[2mType 'help' to get started\x1b[22m" });
|
|
44
|
+
items.push({ id: "blank-4", text: "" });
|
|
45
|
+
return items;
|
|
46
|
+
});
|
|
21
47
|
const [outputBuffer, setOutputBuffer] = useState([
|
|
22
48
|
chalk.dim(" Type 'help' to see available commands"),
|
|
23
49
|
"",
|
|
@@ -31,6 +57,7 @@ export function App({ version, network, wallet, balance }) {
|
|
|
31
57
|
const rows = process.stdout.rows ?? 24;
|
|
32
58
|
const viewportHeight = Math.max(1, rows - HEADER_ROWS - FOOTER_ROWS);
|
|
33
59
|
const { scrollOffset, isAutoScroll, scrollUp, scrollDown, snapToBottom } = useScroll(viewportHeight);
|
|
60
|
+
const { toasts, dismiss: dismissToast } = useNotifications();
|
|
34
61
|
// Get top-level command names for dispatch detection
|
|
35
62
|
const [topCmds] = useState(() => {
|
|
36
63
|
try {
|
|
@@ -41,6 +68,19 @@ export function App({ version, network, wallet, balance }) {
|
|
|
41
68
|
return [];
|
|
42
69
|
}
|
|
43
70
|
});
|
|
71
|
+
// ── Enhanced keyboard shortcuts ────────────────────────────────────────
|
|
72
|
+
useInput((input, key) => {
|
|
73
|
+
// Ctrl+L — clear viewport
|
|
74
|
+
if (key.ctrl && input === "l") {
|
|
75
|
+
setOutputBuffer([]);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Escape — cancel / clear (snap to bottom if scrolled)
|
|
79
|
+
if (key.escape) {
|
|
80
|
+
snapToBottom();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
44
84
|
const appendLine = useCallback((line) => {
|
|
45
85
|
setOutputBuffer((prev) => [...prev, line]);
|
|
46
86
|
}, []);
|
|
@@ -143,6 +183,6 @@ export function App({ version, network, wallet, balance }) {
|
|
|
143
183
|
setIsProcessing(false);
|
|
144
184
|
}, [appendLine, execute, send, snapToBottom, topCmds, network, wallet, balance, exit]);
|
|
145
185
|
const isDisabled = isProcessing || isRunning || isSending;
|
|
146
|
-
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(
|
|
186
|
+
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(Static, { items: bannerData, children: (item) => _jsx(Text, { children: item.text }, item.id) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "─".repeat(60) }) }), _jsx(Viewport, { lines: outputBuffer, scrollOffset: scrollOffset, isAutoScroll: isAutoScroll }), _jsx(ToastContainer, { toasts: toasts, onDismiss: dismissToast }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "─".repeat(60) }) }), _jsx(Footer, { children: _jsx(InputLine, { onSubmit: handleCommand, isDisabled: isDisabled }) })] }));
|
|
147
187
|
}
|
|
148
188
|
//# sourceMappingURL=App.js.map
|
package/dist/tui/App.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,WAAW,EAAa,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,WAAW,EAAa,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAwB,CAAC;AAExF,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AASjE;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAY;IACjE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;IAE1B,sEAAsE;IACtE,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;QACjC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;QACzD,MAAM,WAAW,GAAG,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,4EAA4E;QAC5E,MAAM,KAAK,GAAmC,EAAE,CAAC;QACjD,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACjD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACxC,uDAAuD;YACvD,+EAA+E;YAC/E,MAAM,UAAU,GAAG,WAAW;iBAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC;iBACnD,IAAI,CAAC,MAAM,CAAC,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,UAAU,EAAE,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,4CAA4C,EAAE,CAAC,CAAC;QAC/E,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAW;QACzD,KAAK,CAAC,GAAG,CAAC,yCAAyC,CAAC;QACpD,EAAE;KACH,CAAC,CAAC;IACH,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;IAC5C,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtC,oDAAoD;IACpD,MAAM,WAAW,GAAG,EAAE,CAAC;IACvB,MAAM,WAAW,GAAG,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IACvC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC;IAErE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,GACtE,SAAS,CAAC,cAAc,CAAC,CAAC;IAE5B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAE7D,qDAAqD;IACrD,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAW,GAAG,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,0EAA0E;IAC1E,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,0BAA0B;QAC1B,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAC9B,eAAe,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QACD,uDAAuD;QACvD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,IAAY,EAAE,EAAE;QAC9C,eAAe,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,WAAW,CAC/B,KAAK,EAAE,KAAa,EAAiB,EAAE;QACrC,2BAA2B;QAC3B,UAAU,CACR,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YACnB,GAAG;YACH,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;YACnB,GAAG;YACH,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;YAChB,GAAG;YACH,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CACrB,CAAC;QAEF,gCAAgC;QAChC,YAAY,EAAE,CAAC;QACf,eAAe,CAAC,IAAI,CAAC,CAAC;QAEtB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC,CAAC;QAE/C,0EAA0E;QAC1E,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACzC,UAAU,CACR,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CACpD,CAAC;YACF,eAAe,CAAC,KAAK,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,eAAe,CAAC,EAAE,CAAC,CAAC;YACpB,eAAe,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;gBAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM,QAAQ,GAAa,EAAE,CAAC;gBAC9B,IAAI,CAAC,eAAe,CAAC;oBACnB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;oBACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;iBACtC,CAAC,CAAC;gBACH,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;gBACtD,CAAC;gBAAC,MAAM,CAAC;oBACP,0CAA0C;gBAC5C,CAAC;gBACD,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;oBAC7B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;wBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC/C,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YACrC,KAAK,CAAC,IAAI,CACR,IAAI;gBACF,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;gBACxB,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAC1D,CAAC;YACF,KAAK,CAAC,IAAI,CACR,IAAI;gBACF,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC;gBAC9B,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAC3C,CAAC;YACF,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,GAAG,CACP,6DAA6D,CAC9D,CACF,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,MAAM,CAAC,IAAI,KAAK;gBAAE,UAAU,CAAC,CAAC,CAAC,CAAC;YACrC,eAAe,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,IAAI,OAAO;gBACT,UAAU,CACR,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CACrD,CAAC;YACJ,IAAI,MAAM;gBACR,UAAU,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClE,IAAI,OAAO;gBACT,UAAU,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO;gBACjC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC,CAAC;YAChF,UAAU,CAAC,EAAE,CAAC,CAAC;YACf,eAAe,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,WAAW,GACf,cAAc,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,EAAE,CAAC,CAAC;QAExE,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YAC3D,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAC9B,CAAC;YACD,UAAU,CAAC,EAAE,CAAC,CAAC;YACf,eAAe,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,MAAM,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACjC,UAAU,CAAC,EAAE,CAAC,CAAC;QACf,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC,EACD,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CACnF,CAAC;IAEF,MAAM,UAAU,GAAG,YAAY,IAAI,SAAS,IAAI,SAAS,CAAC;IAE1D,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,MAAM,EAAC,MAAM,aAEvC,KAAC,MAAM,IAAC,KAAK,EAAE,UAAU,YACtB,CAAC,IAAI,EAAE,EAAE,CAAC,KAAC,IAAI,cAAgB,IAAI,CAAC,IAAI,IAAnB,IAAI,CAAC,EAAE,CAAoB,GAC1C,EAGT,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,GAClC,EAGN,KAAC,QAAQ,IACP,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,YAAY,GAC1B,EAGF,KAAC,cAAc,IAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAI,EAG3D,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,GAClC,EAGN,KAAC,MAAM,cACL,KAAC,SAAS,IAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,GAAI,GACvD,IACL,CACP,CAAC;AACJ,CAAC"}
|
package/dist/tui/Header.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ interface HeaderProps {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Fixed header showing the ASCII art banner + status info.
|
|
10
|
-
*
|
|
10
|
+
* Status items use flexWrap to adapt to narrow terminals.
|
|
11
11
|
*/
|
|
12
12
|
export declare const Header: React.NamedExoticComponent<HeaderProps>;
|
|
13
13
|
export {};
|
package/dist/tui/Header.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/tui/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/tui/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM,yCAkCjB,CAAC"}
|
package/dist/tui/Header.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Box, Text } from "ink";
|
|
4
|
-
import {
|
|
4
|
+
import { getBannerArt, getStatusItems } from "../ui/banner.js";
|
|
5
5
|
/**
|
|
6
6
|
* Fixed header showing the ASCII art banner + status info.
|
|
7
|
-
*
|
|
7
|
+
* Status items use flexWrap to adapt to narrow terminals.
|
|
8
8
|
*/
|
|
9
9
|
export const Header = React.memo(function Header({ network, wallet, balance, }) {
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const { artLines, subtitle, separator } = getBannerArt();
|
|
11
|
+
const statusItems = getStatusItems({ network, wallet, balance });
|
|
12
|
+
return (_jsxs(Box, { flexDirection: "column", children: [artLines.map((line, i) => (_jsx(Text, { children: line }, i))), _jsx(Text, { children: "" }), _jsx(Text, { children: subtitle }), _jsx(Text, { children: separator }), statusItems.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { children: "" }), _jsx(Box, { flexWrap: "wrap", columnGap: 2, children: statusItems.map((item) => (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: item.label }), _jsxs(Text, { children: [" ", item.value] })] }, item.label))) })] })), _jsx(Text, { children: "" }), _jsx(Text, { dimColor: true, children: " Type 'help' to get started" }), _jsx(Text, { children: "" })] }));
|
|
12
13
|
});
|
|
13
14
|
//# sourceMappingURL=Header.js.map
|
package/dist/tui/Header.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/tui/Header.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/tui/Header.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAU/D;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,EAC/C,OAAO,EACP,MAAM,EACN,OAAO,GACK;IACZ,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;IACzD,MAAM,WAAW,GAAG,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAEjE,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,IAAI,cAAU,IAAI,IAAR,CAAC,CAAe,CAC5B,CAAC,EACF,KAAC,IAAI,cAAE,EAAE,GAAQ,EACjB,KAAC,IAAI,cAAE,QAAQ,GAAQ,EACvB,KAAC,IAAI,cAAE,SAAS,GAAQ,EACvB,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,CACzB,8BACE,KAAC,IAAI,cAAE,EAAE,GAAQ,EACjB,KAAC,GAAG,IAAC,QAAQ,EAAC,MAAM,EAAC,SAAS,EAAE,CAAC,YAC9B,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACzB,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,QAAQ,kBAAE,IAAI,CAAC,KAAK,GAAQ,EAClC,MAAC,IAAI,qBAAI,IAAI,CAAC,KAAK,IAAQ,KAFnB,IAAI,CAAC,KAAK,CAGd,CACP,CAAC,GACE,IACL,CACJ,EACD,KAAC,IAAI,cAAE,EAAE,GAAQ,EACjB,KAAC,IAAI,IAAC,QAAQ,kBAAE,6BAA6B,GAAQ,EACrD,KAAC,IAAI,cAAE,EAAE,GAAQ,IACb,CACP,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/tui/InputLine.d.ts
CHANGED
|
@@ -3,8 +3,7 @@ interface InputLineProps {
|
|
|
3
3
|
isDisabled?: boolean;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* Input line with command history navigation
|
|
7
|
-
* Uses ink-text-input for text input with cursor.
|
|
6
|
+
* Input line with command history navigation, tab completion, and dropdown.
|
|
8
7
|
*/
|
|
9
8
|
export declare function InputLine({ onSubmit, isDisabled }: InputLineProps): import("react/jsx-runtime").JSX.Element;
|
|
10
9
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputLine.d.ts","sourceRoot":"","sources":["../../src/tui/InputLine.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InputLine.d.ts","sourceRoot":"","sources":["../../src/tui/InputLine.tsx"],"names":[],"mappings":"AAQA,UAAU,cAAc;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,UAAkB,EAAE,EAAE,cAAc,2CA8NzE"}
|