@multiclawcli/dashboard 0.4.0 → 0.5.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.
- package/dist/tui/App.d.ts +10 -0
- package/dist/tui/commands.d.ts +122 -0
- package/dist/tui/components/chrome.d.ts +58 -0
- package/dist/tui/components/overlays.d.ts +64 -0
- package/dist/tui/components/panels.d.ts +72 -0
- package/dist/tui/components/prompt.d.ts +36 -0
- package/dist/tui/format.d.ts +65 -0
- package/dist/tui/history.d.ts +34 -0
- package/dist/tui/index.d.ts +17 -0
- package/dist/tui/layout.d.ts +87 -0
- package/dist/tui/state.d.ts +292 -0
- package/dist/tui/theme.d.ts +66 -0
- package/dist/tui.js +642 -114
- package/package.json +9 -8
- package/dist/tui.d.ts +0 -299
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiclawcli/dashboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./tui": {
|
|
7
|
-
"types": "./dist/tui.d.ts",
|
|
7
|
+
"types": "./dist/tui/index.d.ts",
|
|
8
8
|
"default": "./dist/tui.js"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
@@ -25,18 +25,19 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@multiclawcli/core": "0.
|
|
28
|
+
"@multiclawcli/core": "0.5.1",
|
|
29
29
|
"ink": "^8.0.0",
|
|
30
|
-
"react": "^19.3.
|
|
30
|
+
"react": "^19.3.1",
|
|
31
|
+
"string-width": "^8.3.0"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
|
-
"@types/node": "^26.6.
|
|
34
|
+
"@types/node": "^26.6.5",
|
|
34
35
|
"@types/react": "^19.3.0",
|
|
35
|
-
"typescript": "^
|
|
36
|
-
"vitest": "^
|
|
36
|
+
"typescript": "^7.0.2",
|
|
37
|
+
"vitest": "^5.0.4"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
40
|
+
"build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
|
|
40
41
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
42
|
"test": "vitest run",
|
|
42
43
|
"test:coverage": "vitest run --coverage"
|
package/dist/tui.d.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { MultiClawConfig, EventBus, AgentStatus, MultiClawEvent, StageInfo, LeaderMessage, TurnRecord, AgentDefinition } from '@multiclawcli/core';
|
|
2
|
-
|
|
3
|
-
interface AppProps {
|
|
4
|
-
config: MultiClawConfig;
|
|
5
|
-
/**
|
|
6
|
-
* Called once per turn, after that turn's orchestrator exists. The CLI uses it
|
|
7
|
-
* to attach a file log writer without the TUI depending on the CLI package.
|
|
8
|
-
*/
|
|
9
|
-
onTurnStart?: (eventBus: EventBus, logDir: string) => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Terminal geometry.
|
|
14
|
-
*
|
|
15
|
-
* Kept pure and separate from the components because responsive rules are the
|
|
16
|
-
* part of a TUI that is easiest to get subtly wrong and hardest to eyeball. Every
|
|
17
|
-
* row the console spends is budgeted here, so the arithmetic is testable rather
|
|
18
|
-
* than buried in JSX.
|
|
19
|
-
*/
|
|
20
|
-
declare const MIN_COLUMNS = 40;
|
|
21
|
-
declare const MIN_ROWS = 10;
|
|
22
|
-
/** Below this the roster is dropped so the stream keeps a usable width. */
|
|
23
|
-
declare const COMPACT_COLUMNS = 72;
|
|
24
|
-
/** The rail costs a row; it only earns one when there is vertical room. */
|
|
25
|
-
declare const RAIL_MIN_ROWS = 16;
|
|
26
|
-
/**
|
|
27
|
-
* The most rows the pipeline rail is ever allowed to occupy.
|
|
28
|
-
*
|
|
29
|
-
* The rail wraps, so its height depends on how many agents the turn has and how
|
|
30
|
-
* wide the terminal is. Without a cap it could eat the whole screen; with one,
|
|
31
|
-
* the budget stays honest and anything past it is clipped rather than silently
|
|
32
|
-
* swallowed by the body.
|
|
33
|
-
*/
|
|
34
|
-
declare const MAX_RAIL_ROWS = 2;
|
|
35
|
-
/** Enough to see the palette is a list; more would push the stream off screen. */
|
|
36
|
-
declare const MAX_MENU_ROWS = 7;
|
|
37
|
-
/** Queued follow-ups sit above the prompt; more than a few would crowd the stream. */
|
|
38
|
-
declare const MAX_QUEUE_ROWS = 3;
|
|
39
|
-
interface LayoutInput {
|
|
40
|
-
columns: number;
|
|
41
|
-
rows: number;
|
|
42
|
-
/** Zero means no turn has run yet, which swaps the body for the welcome screen. */
|
|
43
|
-
turn: number;
|
|
44
|
-
/** A modal owns the body — help or the history list. */
|
|
45
|
-
overlay: boolean;
|
|
46
|
-
/** Rows the command palette is asking for. */
|
|
47
|
-
menuRows: number;
|
|
48
|
-
/** Rows the queued follow-ups are asking for. */
|
|
49
|
-
queueRows?: number;
|
|
50
|
-
/** Whether a command result is waiting to be shown. */
|
|
51
|
-
notice: boolean;
|
|
52
|
-
/** A past turn is open for reading, which costs a banner row. */
|
|
53
|
-
viewing?: boolean;
|
|
54
|
-
/** Whether there is a leader or any stage to draw. */
|
|
55
|
-
hasRail: boolean;
|
|
56
|
-
/**
|
|
57
|
-
* Rendered widths of the rail's cells, widest first is not required — order
|
|
58
|
-
* is what the rail draws. Needed because the rail wraps: its height is a
|
|
59
|
-
* function of the content, so a flat "one row" charge under-budgets it.
|
|
60
|
-
*/
|
|
61
|
-
railCells?: number[];
|
|
62
|
-
}
|
|
63
|
-
interface Layout {
|
|
64
|
-
columns: number;
|
|
65
|
-
rows: number;
|
|
66
|
-
compact: boolean;
|
|
67
|
-
showTeam: boolean;
|
|
68
|
-
showRail: boolean;
|
|
69
|
-
/** How many rows the rail will actually occupy once it wraps. */
|
|
70
|
-
railRows: number;
|
|
71
|
-
welcome: boolean;
|
|
72
|
-
bodyHeight: number;
|
|
73
|
-
logViewport: number;
|
|
74
|
-
teamWidth: number;
|
|
75
|
-
menuRows: number;
|
|
76
|
-
queueRows: number;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* How many rows the rail occupies given the widths of the cells it draws.
|
|
80
|
-
*
|
|
81
|
-
* Approximate on purpose: Yoga's own wrapping depends on margins and on how the
|
|
82
|
-
* terminal renders wide glyphs, and chasing exactness here is not worth it. The
|
|
83
|
-
* number is capped and the rail is clipped, so an under-count costs the last
|
|
84
|
-
* chip rather than collapsing the layout.
|
|
85
|
-
*/
|
|
86
|
-
declare function measureRailRows(cells: number[] | undefined, columns: number): number;
|
|
87
|
-
declare function computeLayout(input: LayoutInput): Layout;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Per-agent log buffer cap, in characters.
|
|
91
|
-
*
|
|
92
|
-
* The previous web store appended output forever (`logs: a.logs + chunk`). A
|
|
93
|
-
* chatty agent running for hours would grow that string without bound. The TUI
|
|
94
|
-
* renders a tail window, so only the tail is worth keeping.
|
|
95
|
-
*/
|
|
96
|
-
declare const MAX_LOG_CHARS = 8000;
|
|
97
|
-
interface AgentView {
|
|
98
|
-
id: string;
|
|
99
|
-
name: string;
|
|
100
|
-
icon?: string;
|
|
101
|
-
model?: string;
|
|
102
|
-
/** Static role, from the config. Always available, even before turn one. */
|
|
103
|
-
description?: string;
|
|
104
|
-
/** Per-turn title assigned by the leader's task plan; absent until it plans. */
|
|
105
|
-
taskTitle?: string;
|
|
106
|
-
status: AgentStatus;
|
|
107
|
-
/** Wall clock at which the agent started, so its timer can tick while it runs. */
|
|
108
|
-
startedAt?: number;
|
|
109
|
-
/** Final duration, present once the agent has finished. */
|
|
110
|
-
duration?: number;
|
|
111
|
-
attempts?: number;
|
|
112
|
-
/** In-flight retry counter, present only while the agent is between attempts. */
|
|
113
|
-
retry?: {
|
|
114
|
-
attempt: number;
|
|
115
|
-
max: number;
|
|
116
|
-
};
|
|
117
|
-
error?: string;
|
|
118
|
-
logs: string;
|
|
119
|
-
}
|
|
120
|
-
type TuiPhase = "idle" | "running" | "complete";
|
|
121
|
-
/**
|
|
122
|
-
* One turn, as the panes need to see it.
|
|
123
|
-
*
|
|
124
|
-
* Everything that describes *a turn* lives here, and everything that describes
|
|
125
|
-
* *the console* lives on {@link TuiState}. The split is what makes history
|
|
126
|
-
* possible: a finished turn is just a `TurnView` kept around, and the panes take
|
|
127
|
-
* a `TurnView` so they can render one without knowing which it is.
|
|
128
|
-
*/
|
|
129
|
-
interface TurnView {
|
|
130
|
-
turn: number;
|
|
131
|
-
requirement?: string;
|
|
132
|
-
phase: TuiPhase;
|
|
133
|
-
/** Wall clock at which the turn started. */
|
|
134
|
-
startedAt?: number;
|
|
135
|
-
/** Wall clock at which the turn finished. */
|
|
136
|
-
endedAt?: number;
|
|
137
|
-
stages: StageInfo[];
|
|
138
|
-
agents: Record<string, AgentView>;
|
|
139
|
-
/**
|
|
140
|
-
* Agents that run *before* the pipeline exists (the leader), so the pipeline
|
|
141
|
-
* bar can label them without guessing. Derived from the config, not from
|
|
142
|
-
* "every agent that is not in a stage" — a configured agent that has not been
|
|
143
|
-
* scheduled yet is not a leader.
|
|
144
|
-
*/
|
|
145
|
-
leaderIds: string[];
|
|
146
|
-
focusId?: string;
|
|
147
|
-
/**
|
|
148
|
-
* While true the focus pane follows whichever agent starts next. Cycling the
|
|
149
|
-
* focus by hand clears it, so the user's choice is not yanked away.
|
|
150
|
-
*/
|
|
151
|
-
autoFollow: boolean;
|
|
152
|
-
/**
|
|
153
|
-
* How many lines the stream is scrolled back from the tail. Zero means the
|
|
154
|
-
* stream is live. Kept as an offset rather than an absolute index so new
|
|
155
|
-
* output arriving underneath does not shift what the user is reading.
|
|
156
|
-
*/
|
|
157
|
-
scroll: number;
|
|
158
|
-
success?: boolean;
|
|
159
|
-
totalDuration?: number;
|
|
160
|
-
warning?: string;
|
|
161
|
-
/**
|
|
162
|
-
* Set when the turn ended in words rather than a pipeline: the leader answered
|
|
163
|
-
* or asked a question, so no agent ran. Distinct from `success`, because both
|
|
164
|
-
* a finished pipeline and a one-line answer are successful turns — and the
|
|
165
|
-
* console has to be able to say which one happened.
|
|
166
|
-
*/
|
|
167
|
-
reply?: LeaderMessage;
|
|
168
|
-
}
|
|
169
|
-
/** How many finished turns the console keeps around to browse. */
|
|
170
|
-
declare const MAX_HISTORY = 20;
|
|
171
|
-
interface TuiState extends TurnView {
|
|
172
|
-
name: string;
|
|
173
|
-
/** Finished turns, oldest first. The live turn is `state` itself. */
|
|
174
|
-
history: TurnView[];
|
|
175
|
-
/**
|
|
176
|
-
* A finished turn opened for reading.
|
|
177
|
-
*
|
|
178
|
-
* Kept as a detached copy so scrolling and tabbing through it cannot disturb
|
|
179
|
-
* the turn that is actually running. While it is set the panes render it, and
|
|
180
|
-
* `focusId` / `scroll` edits land on it rather than on the live turn.
|
|
181
|
-
*/
|
|
182
|
-
view?: TurnView;
|
|
183
|
-
}
|
|
184
|
-
declare const initialState: TuiState;
|
|
185
|
-
type TuiAction = {
|
|
186
|
-
type: "turn:start";
|
|
187
|
-
requirement: string;
|
|
188
|
-
agents: Record<string, AgentView>;
|
|
189
|
-
leaderIds: string[];
|
|
190
|
-
startedAt: number;
|
|
191
|
-
} | {
|
|
192
|
-
type: "event";
|
|
193
|
-
event: MultiClawEvent;
|
|
194
|
-
} | {
|
|
195
|
-
type: "focus:cycle";
|
|
196
|
-
delta: number;
|
|
197
|
-
} | {
|
|
198
|
-
type: "focus:set";
|
|
199
|
-
agentId: string;
|
|
200
|
-
}
|
|
201
|
-
/** Scroll the focused stream. `viewport` is needed to clamp at the tail. */
|
|
202
|
-
| {
|
|
203
|
-
type: "stream:scroll";
|
|
204
|
-
delta: number;
|
|
205
|
-
viewport: number;
|
|
206
|
-
}
|
|
207
|
-
/** Drop the focused agent's buffered output without touching its status. */
|
|
208
|
-
| {
|
|
209
|
-
type: "stream:clear";
|
|
210
|
-
}
|
|
211
|
-
/** Open a finished turn for reading, by its turn number. */
|
|
212
|
-
| {
|
|
213
|
-
type: "view:open";
|
|
214
|
-
turn: number;
|
|
215
|
-
}
|
|
216
|
-
/** Go back to the live turn. */
|
|
217
|
-
| {
|
|
218
|
-
type: "view:close";
|
|
219
|
-
};
|
|
220
|
-
declare function stripAnsi(text: string): string;
|
|
221
|
-
/** Append a chunk, keeping only the last {@link MAX_LOG_CHARS} characters. */
|
|
222
|
-
declare function appendLog(previous: string, chunk: string): string;
|
|
223
|
-
/** Every agent that takes part in a run, in declaration order: leader first. */
|
|
224
|
-
declare function plannedAgents(config: MultiClawConfig): AgentDefinition[];
|
|
225
|
-
declare function leaderAgentIds(config: MultiClawConfig): string[];
|
|
226
|
-
/**
|
|
227
|
-
* Build the roster shown before (and between) runs.
|
|
228
|
-
*
|
|
229
|
-
* The orchestrator only reveals the team through `orchestration:start`, which it
|
|
230
|
-
* emits *after* the leader has already run — so a console that learned its
|
|
231
|
-
* agents purely from events would show an empty list until the first turn was
|
|
232
|
-
* well under way. Seeding from the config makes the idle screen show the team
|
|
233
|
-
* you are about to run, and gives every turn a known baseline to reset to.
|
|
234
|
-
*/
|
|
235
|
-
declare function seedAgents(config: MultiClawConfig): Record<string, AgentView>;
|
|
236
|
-
declare function createInitialState(config: MultiClawConfig): TuiState;
|
|
237
|
-
declare function reduceEvent(state: TuiState, event: MultiClawEvent): TuiState;
|
|
238
|
-
/**
|
|
239
|
-
* The turns behind this one, as dialogue the leader can read back.
|
|
240
|
-
*
|
|
241
|
-
* Core has no notion of a session — an orchestrator is built per turn — so the
|
|
242
|
-
* console is what carries earlier turns into the next run. Without them a bare
|
|
243
|
-
* answer arrives at the leader as a requirement with nothing to answer: turn one
|
|
244
|
-
* asks "which database?", turn two's requirement is the word "Postgres".
|
|
245
|
-
*
|
|
246
|
-
* Derived rather than tracked separately: `history` plus the turn on screen
|
|
247
|
-
* *are* the finished turns, and a second copy is one more thing that could
|
|
248
|
-
* disagree with what the panes show.
|
|
249
|
-
*
|
|
250
|
-
* Only turns that ended are carried, which makes the call site's timing
|
|
251
|
-
* irrelevant: whether this is read before or after `turn:start` moves the turn
|
|
252
|
-
* on screen into `history`, the set is the same.
|
|
253
|
-
*/
|
|
254
|
-
declare function conversationTurns(state: TuiState): TurnRecord[];
|
|
255
|
-
declare function tuiReducer(state: TuiState, action: TuiAction): TuiState;
|
|
256
|
-
/** Roll a stage's member statuses up into one status for the pipeline bar. */
|
|
257
|
-
declare function stageStatus(stage: StageInfo, agents: Record<string, AgentView>): AgentStatus;
|
|
258
|
-
/** How many agents have finished, out of how many the turn will run. */
|
|
259
|
-
declare function progress(turn: TurnView): {
|
|
260
|
-
done: number;
|
|
261
|
-
total: number;
|
|
262
|
-
};
|
|
263
|
-
/**
|
|
264
|
-
* An agent's time: the live clock while it runs, the recorded duration once it
|
|
265
|
-
* has stopped. Returning the *same* number after completion is what stops the
|
|
266
|
-
* column from jittering when a stage ends.
|
|
267
|
-
*/
|
|
268
|
-
declare function agentElapsed(agent: AgentView, now: number): number | undefined;
|
|
269
|
-
/** The turn's time, live while running and frozen once the orchestrator reports back. */
|
|
270
|
-
declare function turnElapsed(turn: TurnView, now: number): number | undefined;
|
|
271
|
-
interface LogWindow {
|
|
272
|
-
lines: string[];
|
|
273
|
-
/** How many lines sit below the window. Zero means the stream is live. */
|
|
274
|
-
scrolledBack: number;
|
|
275
|
-
following: boolean;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* The slice of the focused agent's output that fits the pane.
|
|
279
|
-
*
|
|
280
|
-
* Clamping here as well as in the reducer keeps the window correct even when
|
|
281
|
-
* the pane is resized between two scroll actions.
|
|
282
|
-
*/
|
|
283
|
-
declare function visibleLog(turn: TurnView, viewport: number): LogWindow;
|
|
284
|
-
|
|
285
|
-
interface TuiOptions {
|
|
286
|
-
config: MultiClawConfig;
|
|
287
|
-
/** Attach per-turn reporters (e.g. a file log writer) here. */
|
|
288
|
-
onTurnStart?: (eventBus: EventBus, logDir: string) => void;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Render the interactive team console.
|
|
292
|
-
*
|
|
293
|
-
* Runs on the alternate screen buffer so the app owns the viewport and the
|
|
294
|
-
* user's scrollback survives. The buffer is always restored — including when
|
|
295
|
-
* rendering throws — otherwise the terminal is left unusable.
|
|
296
|
-
*/
|
|
297
|
-
declare function startTui(options: TuiOptions): Promise<void>;
|
|
298
|
-
|
|
299
|
-
export { type AgentView, type AppProps, COMPACT_COLUMNS, type Layout, type LayoutInput, type LogWindow, MAX_HISTORY, MAX_LOG_CHARS, MAX_MENU_ROWS, MAX_QUEUE_ROWS, MAX_RAIL_ROWS, MIN_COLUMNS, MIN_ROWS, RAIL_MIN_ROWS, type TuiAction, type TuiOptions, type TuiPhase, type TuiState, type TurnView, agentElapsed, appendLog, computeLayout, conversationTurns, createInitialState, initialState, leaderAgentIds, measureRailRows, plannedAgents, progress, reduceEvent, seedAgents, stageStatus, startTui, stripAnsi, tuiReducer, turnElapsed, visibleLog };
|