recomposable 1.1.7 → 1.2.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 +23 -8
- package/dist/components/App.d.ts +10 -0
- package/dist/components/App.js +149 -0
- package/dist/components/App.js.map +1 -0
- package/dist/components/BottomPanel.d.ts +9 -0
- package/dist/components/BottomPanel.js +205 -0
- package/dist/components/BottomPanel.js.map +1 -0
- package/dist/components/ExecScreen.d.ts +9 -0
- package/dist/components/ExecScreen.js +21 -0
- package/dist/components/ExecScreen.js.map +1 -0
- package/dist/components/Legend.d.ts +3 -0
- package/dist/components/Legend.js +86 -0
- package/dist/components/Legend.js.map +1 -0
- package/dist/components/ListScreen.d.ts +9 -0
- package/dist/components/ListScreen.js +85 -0
- package/dist/components/ListScreen.js.map +1 -0
- package/dist/components/LogScreen.d.ts +9 -0
- package/dist/components/LogScreen.js +130 -0
- package/dist/components/LogScreen.js.map +1 -0
- package/dist/components/Logo.d.ts +2 -0
- package/dist/components/Logo.js +8 -0
- package/dist/components/Logo.js.map +1 -0
- package/dist/components/Separator.d.ts +6 -0
- package/dist/components/Separator.js +8 -0
- package/dist/components/Separator.js.map +1 -0
- package/dist/components/ServiceRow.d.ts +11 -0
- package/dist/components/ServiceRow.js +159 -0
- package/dist/components/ServiceRow.js.map +1 -0
- package/dist/index.d.ts +26 -1
- package/dist/index.js +715 -293
- package/dist/index.js.map +1 -1
- package/dist/lib/docker.d.ts +12 -10
- package/dist/lib/docker.js +190 -103
- package/dist/lib/docker.js.map +1 -1
- package/dist/lib/inkTheme.d.ts +18 -0
- package/dist/lib/inkTheme.js +33 -0
- package/dist/lib/inkTheme.js.map +1 -0
- package/dist/lib/renderer.d.ts +1 -1
- package/dist/lib/renderer.js +118 -75
- package/dist/lib/renderer.js.map +1 -1
- package/dist/lib/state.d.ts +12 -1
- package/dist/lib/state.js +30 -21
- package/dist/lib/state.js.map +1 -1
- package/dist/lib/theme.js +13 -23
- package/dist/lib/theme.js.map +1 -1
- package/dist/lib/types.d.ts +14 -0
- package/dist/lib/types.js +1 -4
- package/dist/lib/types.js.map +1 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A lightweight Docker Compose TUI manager with vim keybindings. Monitor service s
|
|
|
4
4
|
|
|
5
5
|
Eliminate switching between countless terminal tabs or windows to rebuild you docker compose containers.
|
|
6
6
|
|
|
7
|
-
Zero dependencies
|
|
7
|
+
Built on [Ink](https://github.com/vadimdemedes/ink) (React for the terminal) for fast, flicker-free rendering. Zero runtime dependencies beyond Ink.
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
@@ -47,8 +47,9 @@ recomposable
|
|
|
47
47
|
- **No cache mode** — toggle to force a full clean rebuild (`--no-cache` + `--force-recreate`), off by default
|
|
48
48
|
- **Docker Compose Watch** — toggle `docker compose watch` per service, with live output in the log panel
|
|
49
49
|
- **Dependency-aware rebuild** — rebuild a service then automatically restart all its transitive dependents in topological order
|
|
50
|
-
- **Container exec** — run commands inside any container, inline in the bottom panel (`e`) or full-screen (`
|
|
50
|
+
- **Container exec** — run commands inside any container, inline in the bottom panel (`e`) or full-screen (`Ctrl+F`), with `cd` support and command history
|
|
51
51
|
- **Worktree switching** — switch any service to run from a different git worktree (`t`), automatically rebuilds and starts in the target branch
|
|
52
|
+
- **Multi-select** — select multiple services with `v`, then rebuild, restart, stop or switch worktree in batch
|
|
52
53
|
- **Vim keybindings** — navigate with `j`/`k`, `G`/`gg`, and more
|
|
53
54
|
|
|
54
55
|
## Full Log View
|
|
@@ -57,7 +58,7 @@ recomposable
|
|
|
57
58
|
|
|
58
59
|
## Exec Mode
|
|
59
60
|
|
|
60
|
-
Run commands inside any running container without leaving the TUI. Press `e` for inline exec in the bottom panel, or `
|
|
61
|
+
Run commands inside any running container without leaving the TUI. Press `e` for inline exec in the bottom panel, or `Ctrl+F` to expand to full-screen. `cd` works — the working directory is tracked across commands.
|
|
61
62
|
|
|
62
63
|

|
|
63
64
|
|
|
@@ -120,7 +121,7 @@ recomposable -f docker-compose.yml -f docker-compose.prod.yml
|
|
|
120
121
|
| `logScanPatterns` | `["WRN]", "ERR]"]` | Patterns to count in container logs |
|
|
121
122
|
| `logScanLines` | `1000` | Number of log lines to scan for pattern counts |
|
|
122
123
|
| `logScanInterval` | `10000` | Pattern scanning interval in milliseconds |
|
|
123
|
-
| `bottomLogCount` | `10` |
|
|
124
|
+
| `bottomLogCount` | `10` | Minimum log lines in the inline log panel (panel expands to fill available space) |
|
|
124
125
|
| `statsInterval` | `5000` | CPU/memory polling interval in milliseconds |
|
|
125
126
|
| `statsBufferSize` | `6` | Number of samples for rolling average (e.g. 6 x 5s = 30s window) |
|
|
126
127
|
| `cpuWarnThreshold` | `50` | CPU % above which the column turns yellow |
|
|
@@ -136,13 +137,13 @@ recomposable -f docker-compose.yml -f docker-compose.prod.yml
|
|
|
136
137
|
|---|---|
|
|
137
138
|
| `j` / `Down` | Move cursor down |
|
|
138
139
|
| `k` / `Up` | Move cursor up |
|
|
139
|
-
| `s` |
|
|
140
|
+
| `s` | Restart selected service |
|
|
140
141
|
| `p` | Stop selected service |
|
|
142
|
+
| `v` | Toggle multi-select on current service |
|
|
141
143
|
| `b` | Rebuild selected service (`up -d --build`) |
|
|
142
144
|
| `d` | Dependency-aware rebuild (rebuild + restart all dependents) |
|
|
143
145
|
| `w` | Toggle Docker Compose Watch for selected service |
|
|
144
146
|
| `e` | Inline exec in bottom panel |
|
|
145
|
-
| `x` | Full-screen exec mode |
|
|
146
147
|
| `n` | Toggle no-cache mode (rebuild with `--no-cache` + `--force-recreate`) |
|
|
147
148
|
| `f` / `Enter` | Full-screen log view for selected service |
|
|
148
149
|
| `t` | Switch service to a different git worktree |
|
|
@@ -168,6 +169,19 @@ recomposable -f docker-compose.yml -f docker-compose.prod.yml
|
|
|
168
169
|
| `Esc` / `f` | Exit log view |
|
|
169
170
|
| `q` | Quit |
|
|
170
171
|
|
|
172
|
+
### Multi-select mode
|
|
173
|
+
|
|
174
|
+
Press `v` on services to select them, then perform batch actions.
|
|
175
|
+
|
|
176
|
+
| Key | Action |
|
|
177
|
+
|---|---|
|
|
178
|
+
| `v` | Toggle selection on current service |
|
|
179
|
+
| `b` | Rebuild all selected services |
|
|
180
|
+
| `s` | Restart all selected services |
|
|
181
|
+
| `p` | Stop all selected services |
|
|
182
|
+
| `t` | Switch all selected services to a different worktree |
|
|
183
|
+
| `Esc` | Discard selection |
|
|
184
|
+
|
|
171
185
|
### Exec mode (inline & full-screen)
|
|
172
186
|
|
|
173
187
|
| Key | Action |
|
|
@@ -175,8 +189,9 @@ recomposable -f docker-compose.yml -f docker-compose.prod.yml
|
|
|
175
189
|
| Type | Enter commands |
|
|
176
190
|
| `Enter` | Execute command |
|
|
177
191
|
| `Up` / `Down` | Navigate command history |
|
|
178
|
-
| `
|
|
179
|
-
| `Ctrl+C` | Kill running command
|
|
192
|
+
| `Ctrl+F` | Expand inline exec to full screen |
|
|
193
|
+
| `Ctrl+C` | Kill running command |
|
|
194
|
+
| `Ctrl+Q` | Quit |
|
|
180
195
|
| `Esc` | Exit exec mode |
|
|
181
196
|
|
|
182
197
|
## Status Icons
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppState } from '../lib/types.js';
|
|
3
|
+
import type { ThemeMode } from '../lib/theme.js';
|
|
4
|
+
interface AppProps {
|
|
5
|
+
state: AppState;
|
|
6
|
+
themeMode: ThemeMode;
|
|
7
|
+
onKeypress: (key: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function App({ state, themeMode, onKeypress }: AppProps): React.ReactElement;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
3
|
+
import { Box, useInput, useStdout, useApp } from 'ink';
|
|
4
|
+
import { ThemeContext, getInkPalette } from '../lib/inkTheme.js';
|
|
5
|
+
import { MODE } from '../lib/state.js';
|
|
6
|
+
import { ListScreen } from './ListScreen.js';
|
|
7
|
+
import { LogScreen } from './LogScreen.js';
|
|
8
|
+
import { ExecScreen } from './ExecScreen.js';
|
|
9
|
+
export function App({ state, themeMode, onKeypress }) {
|
|
10
|
+
const { stdout } = useStdout();
|
|
11
|
+
const { exit } = useApp();
|
|
12
|
+
const palette = getInkPalette(themeMode);
|
|
13
|
+
const columns = stdout?.columns ?? 80;
|
|
14
|
+
const rows = stdout?.rows ?? 24;
|
|
15
|
+
// Re-render on state changes via a tick counter
|
|
16
|
+
const [tick, setTick] = useState(0);
|
|
17
|
+
const tickRef = useRef(tick);
|
|
18
|
+
tickRef.current = tick;
|
|
19
|
+
// Expose a re-render trigger on the state object for imperative code
|
|
20
|
+
const stateRef = useRef(state);
|
|
21
|
+
stateRef.current = state;
|
|
22
|
+
// The forceRender function is attached to state as _inkRender
|
|
23
|
+
// Batched: multiple calls within the same microtask only trigger one re-render
|
|
24
|
+
const pendingRef = useRef(false);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
state._inkRender = () => {
|
|
27
|
+
if (!pendingRef.current) {
|
|
28
|
+
pendingRef.current = true;
|
|
29
|
+
queueMicrotask(() => {
|
|
30
|
+
pendingRef.current = false;
|
|
31
|
+
setTick(t => t + 1);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
return () => { delete state._inkRender; };
|
|
36
|
+
}, [state]);
|
|
37
|
+
// gg detection
|
|
38
|
+
const gPendingRef = useRef(false);
|
|
39
|
+
const gTimerRef = useRef(null);
|
|
40
|
+
const handleInput = useCallback((input, key) => {
|
|
41
|
+
const st = stateRef.current;
|
|
42
|
+
// In text input modes, pass raw characters
|
|
43
|
+
if (st.logSearchActive || st.bottomSearchActive || st.mode === MODE.EXEC || st.execActive) {
|
|
44
|
+
if (key.escape) {
|
|
45
|
+
onKeypress('\x1b');
|
|
46
|
+
}
|
|
47
|
+
else if (key.return) {
|
|
48
|
+
onKeypress('\r');
|
|
49
|
+
}
|
|
50
|
+
else if (key.backspace || key.delete) {
|
|
51
|
+
onKeypress('\x7f');
|
|
52
|
+
}
|
|
53
|
+
else if (key.upArrow) {
|
|
54
|
+
onKeypress('\x1b[A');
|
|
55
|
+
}
|
|
56
|
+
else if (key.downArrow) {
|
|
57
|
+
onKeypress('\x1b[B');
|
|
58
|
+
}
|
|
59
|
+
else if (key.ctrl && input === 'c') {
|
|
60
|
+
onKeypress('\x03');
|
|
61
|
+
}
|
|
62
|
+
else if (input && input.length === 1 && input >= ' ') {
|
|
63
|
+
onKeypress(input);
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Worktree picker
|
|
68
|
+
if (st.worktreePickerActive) {
|
|
69
|
+
if (key.escape)
|
|
70
|
+
onKeypress('\x1b');
|
|
71
|
+
else if (key.return)
|
|
72
|
+
onKeypress('\r');
|
|
73
|
+
else if (input === 'j' || key.downArrow)
|
|
74
|
+
onKeypress('j');
|
|
75
|
+
else if (input === 'k' || key.upArrow)
|
|
76
|
+
onKeypress('k');
|
|
77
|
+
else if (input === 'G')
|
|
78
|
+
onKeypress('G');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Normal navigation modes
|
|
82
|
+
if (key.escape) {
|
|
83
|
+
onKeypress('\x1b');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (key.return) {
|
|
87
|
+
onKeypress('\r');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (key.upArrow) {
|
|
91
|
+
onKeypress('k');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (key.downArrow) {
|
|
95
|
+
onKeypress('j');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (key.ctrl && input === 'c') {
|
|
99
|
+
onKeypress('\x03');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (key.ctrl && input === 'u') {
|
|
103
|
+
onKeypress('\x15');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (key.ctrl && input === 'd') {
|
|
107
|
+
onKeypress('\x04');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Handle 'g' -> 'gg' sequence
|
|
111
|
+
if (input === 'g') {
|
|
112
|
+
if (gPendingRef.current) {
|
|
113
|
+
gPendingRef.current = false;
|
|
114
|
+
if (gTimerRef.current) {
|
|
115
|
+
clearTimeout(gTimerRef.current);
|
|
116
|
+
gTimerRef.current = null;
|
|
117
|
+
}
|
|
118
|
+
// gg action
|
|
119
|
+
if (st.mode === MODE.LIST) {
|
|
120
|
+
onKeypress('gg');
|
|
121
|
+
}
|
|
122
|
+
else if (st.mode === MODE.LOGS) {
|
|
123
|
+
onKeypress('gg');
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
gPendingRef.current = true;
|
|
128
|
+
gTimerRef.current = setTimeout(() => {
|
|
129
|
+
gPendingRef.current = false;
|
|
130
|
+
gTimerRef.current = null;
|
|
131
|
+
}, 300);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Any other key cancels pending g
|
|
135
|
+
if (gPendingRef.current) {
|
|
136
|
+
gPendingRef.current = false;
|
|
137
|
+
if (gTimerRef.current) {
|
|
138
|
+
clearTimeout(gTimerRef.current);
|
|
139
|
+
gTimerRef.current = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (input) {
|
|
143
|
+
onKeypress(input);
|
|
144
|
+
}
|
|
145
|
+
}, [onKeypress]);
|
|
146
|
+
useInput(handleInput);
|
|
147
|
+
return (_jsx(ThemeContext.Provider, { value: palette, children: _jsxs(Box, { flexDirection: "column", height: rows - 1, children: [state.mode === MODE.LIST && (_jsx(ListScreen, { state: state, columns: columns, rows: rows })), state.mode === MODE.LOGS && (_jsx(LogScreen, { state: state, columns: columns, rows: rows })), state.mode === MODE.EXEC && (_jsx(ExecScreen, { state: state, columns: columns, rows: rows }))] }) }));
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=App.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppState } from '../lib/types.js';
|
|
3
|
+
interface BottomPanelProps {
|
|
4
|
+
state: AppState;
|
|
5
|
+
columns: number;
|
|
6
|
+
availableRows?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function BottomPanel({ state, columns, availableRows }: BottomPanelProps): React.ReactElement | null;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Text, Box } from 'ink';
|
|
4
|
+
import { useTheme } from '../lib/inkTheme.js';
|
|
5
|
+
import { statusKey } from '../lib/state.js';
|
|
6
|
+
import { Separator } from './Separator.js';
|
|
7
|
+
function logLineColor(line, patterns, patternColors) {
|
|
8
|
+
let color = null;
|
|
9
|
+
for (let pi = 0; pi < patterns.length; pi++) {
|
|
10
|
+
const group = Array.isArray(patterns[pi]) ? patterns[pi] : [patterns[pi]];
|
|
11
|
+
if (group.some(p => line.includes(p))) {
|
|
12
|
+
color = patternColors[pi % patternColors.length];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return color;
|
|
16
|
+
}
|
|
17
|
+
export function BottomPanel({ state, columns, availableRows }) {
|
|
18
|
+
const theme = useTheme();
|
|
19
|
+
const patterns = state.config.logScanPatterns || [];
|
|
20
|
+
const patternColors = [theme.yellow, theme.red, theme.cyan, theme.magenta];
|
|
21
|
+
// Multi-select panel
|
|
22
|
+
if (state.multiSelected.size > 0) {
|
|
23
|
+
const selectionPanel = (_jsxs(React.Fragment, { children: [_jsx(Separator, { columns: columns }), _jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' Selection' }), _jsx(Text, { color: theme.dim, children: ' - press Esc to discard' })] }), [...state.multiSelected].map((sk, i) => {
|
|
24
|
+
const entry = state.flatList.find(e => statusKey(e.file, e.service) === sk);
|
|
25
|
+
if (!entry)
|
|
26
|
+
return null;
|
|
27
|
+
const st = state.statuses.get(sk);
|
|
28
|
+
const isRebuilding = state.rebuilding.has(sk);
|
|
29
|
+
const isRestarting = state.restarting.has(sk);
|
|
30
|
+
const isStopping = state.stopping.has(sk);
|
|
31
|
+
const isStarting = state.starting.has(sk);
|
|
32
|
+
const dots = '.'.repeat(state.animDots + 1);
|
|
33
|
+
let statusStr = '';
|
|
34
|
+
if (isRebuilding)
|
|
35
|
+
statusStr = ` REBUILDING${dots}`;
|
|
36
|
+
else if (isRestarting)
|
|
37
|
+
statusStr = ` RESTARTING${dots}`;
|
|
38
|
+
else if (isStopping)
|
|
39
|
+
statusStr = ` STOPPING${dots}`;
|
|
40
|
+
else if (isStarting)
|
|
41
|
+
statusStr = ` STARTING${dots}`;
|
|
42
|
+
else if (st)
|
|
43
|
+
statusStr = ` ${st.state}`;
|
|
44
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' \u2713 ' }), _jsx(Text, { bold: true, children: entry.service }), statusStr && _jsx(Text, { color: isRebuilding || isRestarting || isStopping || isStarting ? theme.yellow : theme.dim, children: statusStr })] }, i));
|
|
45
|
+
})] }, "sel"));
|
|
46
|
+
// If worktree picker is also active, show both panels
|
|
47
|
+
if (state.worktreePickerActive) {
|
|
48
|
+
return (_jsxs(Box, { flexDirection: "column", children: [selectionPanel, _jsx(Separator, { columns: columns }), _jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' switch worktree ' }), _jsx(Text, { bold: true, color: theme.cyan, children: 'selected services' })] }), _jsx(Text, { color: theme.dim, children: ' j/k navigate Enter confirm Esc cancel' }), state.worktreePickerEntries.map((wt, wi) => {
|
|
49
|
+
const isSelected = wi === state.worktreePickerCursor;
|
|
50
|
+
const isCurrent = state.worktreePickerCurrentPath !== null && state.worktreePickerCurrentPath === wt.path;
|
|
51
|
+
return (_jsxs(Text, { inverse: isSelected, children: [' ', wt.branch, ' ', _jsx(Text, { color: theme.dim, children: wt.path }), isCurrent && _jsx(Text, { color: theme.dim, children: ' (current)' })] }, wi));
|
|
52
|
+
})] }));
|
|
53
|
+
}
|
|
54
|
+
return _jsx(Box, { flexDirection: "column", children: selectionPanel });
|
|
55
|
+
}
|
|
56
|
+
// Worktree picker (single service)
|
|
57
|
+
if (state.worktreePickerActive) {
|
|
58
|
+
const selEntry = state.flatList[state.cursor];
|
|
59
|
+
if (!selEntry)
|
|
60
|
+
return null;
|
|
61
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Separator, { columns: columns }), _jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' switch worktree ' }), _jsx(Text, { bold: true, color: theme.cyan, children: selEntry.service })] }), _jsx(Text, { color: theme.dim, children: ' j/k navigate Enter confirm Esc cancel' }), state.worktreePickerEntries.map((wt, wi) => {
|
|
62
|
+
const isSelected = wi === state.worktreePickerCursor;
|
|
63
|
+
const isCurrent = state.worktreePickerCurrentPath !== null && state.worktreePickerCurrentPath === wt.path;
|
|
64
|
+
return (_jsxs(Text, { inverse: isSelected, children: [' ', wt.branch, ' ', _jsx(Text, { color: theme.dim, children: wt.path }), isCurrent && _jsx(Text, { color: theme.dim, children: ' (current)' })] }, wi));
|
|
65
|
+
})] }));
|
|
66
|
+
}
|
|
67
|
+
// Exec inline
|
|
68
|
+
if (state.execActive && state.execService) {
|
|
69
|
+
const runningIndicator = state.execChild ? 'running' : 'ready';
|
|
70
|
+
const runningColor = state.execChild ? theme.yellow : theme.green;
|
|
71
|
+
const execChrome = 3; // separator + header + input prompt
|
|
72
|
+
const maxOutputLines = availableRows ? Math.max(1, availableRows - execChrome) : Math.max(1, (state.config.bottomLogCount || 10) - 1);
|
|
73
|
+
const outputStart = Math.max(0, state.execOutputLines.length - maxOutputLines);
|
|
74
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Separator, { columns: columns }), _jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' exec ' }), _jsx(Text, { bold: true, color: theme.cyan, children: state.execService }), _jsx(Text, { children: ' ' }), _jsx(Text, { color: runningColor, children: runningIndicator }), state.execCwd && _jsx(Text, { color: theme.dim, children: ' ' + state.execCwd })] }), state.execOutputLines.slice(outputStart).map((line, i) => (_jsx(Text, { children: ' ' + line.substring(0, columns - 4) }, i))), _jsxs(Text, { children: [_jsx(Text, { color: theme.green, children: '$ ' }), _jsx(Text, { children: state.execInput }), _jsx(Text, { bold: true, children: '_' })] })] }));
|
|
75
|
+
}
|
|
76
|
+
// Bottom logs
|
|
77
|
+
if (!state.showBottomLogs)
|
|
78
|
+
return null;
|
|
79
|
+
const selEntry = state.flatList[state.cursor];
|
|
80
|
+
if (!selEntry)
|
|
81
|
+
return null;
|
|
82
|
+
const sk = statusKey(selEntry.file, selEntry.service);
|
|
83
|
+
const parts = [];
|
|
84
|
+
// Cascade progress
|
|
85
|
+
const cascade = state.cascading.get(sk);
|
|
86
|
+
if (cascade) {
|
|
87
|
+
parts.push(_jsx(Separator, { columns: columns }, "cas-sep"), _jsxs(Text, { children: [_jsx(Text, { color: theme.yellow, children: ' cascading ' }), _jsx(Text, { bold: true, color: theme.yellow, children: selEntry.service })] }, "cas-hdr"));
|
|
88
|
+
cascade.steps.forEach((step, si) => {
|
|
89
|
+
let marker;
|
|
90
|
+
let markerColor;
|
|
91
|
+
switch (step.status) {
|
|
92
|
+
case 'completed':
|
|
93
|
+
marker = '[done]';
|
|
94
|
+
markerColor = theme.green;
|
|
95
|
+
break;
|
|
96
|
+
case 'in_progress':
|
|
97
|
+
marker = '[>>> ]';
|
|
98
|
+
markerColor = theme.yellow;
|
|
99
|
+
break;
|
|
100
|
+
case 'failed':
|
|
101
|
+
marker = '[FAIL]';
|
|
102
|
+
markerColor = theme.red;
|
|
103
|
+
break;
|
|
104
|
+
default:
|
|
105
|
+
marker = '[ ]';
|
|
106
|
+
markerColor = theme.dim;
|
|
107
|
+
}
|
|
108
|
+
parts.push(_jsxs(Text, { children: [' ', _jsx(Text, { color: markerColor, children: marker }), ' ' + step.action + ' ', _jsx(Text, { bold: true, children: step.service })] }, `cas-${si}`));
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const info = state.bottomLogLines.get(sk);
|
|
112
|
+
// Show animated "loading logs" while debouncing (before tail starts)
|
|
113
|
+
if (!info && !cascade && state.bottomLogLoading) {
|
|
114
|
+
const dots = '.'.repeat(state.animDots + 1);
|
|
115
|
+
parts.push(_jsx(Separator, { columns: columns }, "log-sep"), _jsx(Text, { color: theme.dim, children: ' loading logs' + dots }, "loading"));
|
|
116
|
+
}
|
|
117
|
+
if (info) {
|
|
118
|
+
if (!cascade) {
|
|
119
|
+
parts.push(_jsx(Separator, { columns: columns }, "log-sep"));
|
|
120
|
+
}
|
|
121
|
+
const isFailed = info.action === 'build_failed' || info.action === 'restart_failed' || info.action === 'stop_failed' || info.action === 'start_failed' || info.action === 'switch_failed';
|
|
122
|
+
const isInProgress = info.action === 'rebuilding' || info.action === 'restarting' || info.action === 'stopping' || info.action === 'starting' || info.action === 'cascading' || info.action === 'switching';
|
|
123
|
+
const actionColor = isFailed ? theme.red
|
|
124
|
+
: isInProgress ? theme.yellow
|
|
125
|
+
: info.action === 'watching' ? theme.cyan : theme.green;
|
|
126
|
+
// Human-friendly labels
|
|
127
|
+
let actionLabel;
|
|
128
|
+
if (isFailed) {
|
|
129
|
+
actionLabel = info.action.replace('_', ' ').toUpperCase();
|
|
130
|
+
}
|
|
131
|
+
else if (info.action === 'rebuilding') {
|
|
132
|
+
actionLabel = 'Build logs';
|
|
133
|
+
}
|
|
134
|
+
else if (info.action === 'restarting') {
|
|
135
|
+
actionLabel = 'Restarting';
|
|
136
|
+
}
|
|
137
|
+
else if (info.action === 'switching') {
|
|
138
|
+
actionLabel = 'Switching';
|
|
139
|
+
}
|
|
140
|
+
else if (info.action === 'logs' || info.action === 'started') {
|
|
141
|
+
actionLabel = 'Run logs';
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
actionLabel = info.action;
|
|
145
|
+
}
|
|
146
|
+
// For switching, extract worktree target from first log line
|
|
147
|
+
let switchTarget = '';
|
|
148
|
+
if (info.action === 'switching' && info.lines.length > 0) {
|
|
149
|
+
const m = info.lines[0].match(/"([^"]+)"/);
|
|
150
|
+
if (m)
|
|
151
|
+
switchTarget = m[1];
|
|
152
|
+
}
|
|
153
|
+
const bq = state.bottomSearchQuery || '';
|
|
154
|
+
parts.push(_jsxs(Text, { children: [_jsx(Text, { color: actionColor, children: ' ' + actionLabel + ' ' }), _jsx(Text, { bold: true, color: actionColor, children: info.service }), switchTarget && _jsxs(Text, { color: actionColor, children: [' to ', _jsx(Text, { bold: true, children: switchTarget })] }), bq && !state.bottomSearchActive && state.bottomSearchLoading && (_jsx(Text, { color: theme.yellow, children: ' searching "' + bq + '"...' })), bq && !state.bottomSearchActive && !state.bottomSearchLoading && state.bottomSearchTotalMatches > 0 && (_jsx(Text, { color: theme.dim, children: ' search: "' + bq + '" (' + state.bottomSearchTotalMatches + ' match' + (state.bottomSearchTotalMatches !== 1 ? 'es' : '') + ' in full log)' })), bq && !state.bottomSearchActive && !state.bottomSearchLoading && state.bottomSearchTotalMatches === 0 && (_jsx(Text, { color: theme.red, children: ' search: "' + bq + '" (no matches)' }))] }, "log-hdr"));
|
|
155
|
+
if (info.lines.length === 0 && (info.action === 'logs' || info.action === 'started')) {
|
|
156
|
+
const dots = '.'.repeat(state.animDots + 1);
|
|
157
|
+
parts.push(_jsx(Text, { color: theme.dim, children: ' loading' + dots }, "loading"));
|
|
158
|
+
}
|
|
159
|
+
// Chrome: separator (1) + header (1) + optional search prompt (1) + optional cascade lines
|
|
160
|
+
let chromeLines = 2;
|
|
161
|
+
if (cascade)
|
|
162
|
+
chromeLines += 2 + cascade.steps.length;
|
|
163
|
+
if (state.bottomSearchActive)
|
|
164
|
+
chromeLines += 1;
|
|
165
|
+
const maxBottomLines = availableRows ? Math.max(1, availableRows - chromeLines) : (state.config.bottomLogCount || 10);
|
|
166
|
+
const visibleLines = info.lines.slice(-maxBottomLines);
|
|
167
|
+
const searchQuery = bq && !state.bottomSearchActive ? bq : '';
|
|
168
|
+
visibleLines.forEach((line, li) => {
|
|
169
|
+
const coloredLine = line.substring(0, columns - 4);
|
|
170
|
+
const lineColor = logLineColor(coloredLine, patterns, patternColors) || theme.dim;
|
|
171
|
+
if (searchQuery) {
|
|
172
|
+
const lowerLine = coloredLine.toLowerCase();
|
|
173
|
+
const lowerQ = searchQuery.toLowerCase();
|
|
174
|
+
if (lowerLine.includes(lowerQ)) {
|
|
175
|
+
// Render with search highlights
|
|
176
|
+
const segments = [];
|
|
177
|
+
let pos = 0;
|
|
178
|
+
let segIdx = 0;
|
|
179
|
+
while (pos < coloredLine.length) {
|
|
180
|
+
const idx = lowerLine.indexOf(lowerQ, pos);
|
|
181
|
+
if (idx === -1) {
|
|
182
|
+
segments.push(_jsx(Text, { color: lineColor, children: coloredLine.substring(pos) }, segIdx++));
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
if (idx > pos) {
|
|
186
|
+
segments.push(_jsx(Text, { color: lineColor, children: coloredLine.substring(pos, idx) }, segIdx++));
|
|
187
|
+
}
|
|
188
|
+
segments.push(_jsx(Text, { inverse: true, color: theme.yellow, children: coloredLine.substring(idx, idx + searchQuery.length) }, segIdx++));
|
|
189
|
+
pos = idx + searchQuery.length;
|
|
190
|
+
}
|
|
191
|
+
parts.push(_jsxs(Text, { children: [' ', ...segments] }, `bl-${li}`));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
parts.push(_jsxs(Text, { children: [' ', _jsx(Text, { color: lineColor, children: coloredLine })] }, `bl-${li}`));
|
|
196
|
+
});
|
|
197
|
+
if (state.bottomSearchActive) {
|
|
198
|
+
parts.push(_jsxs(Text, { children: [_jsx(Text, { bold: true, children: '/' }), _jsx(Text, { children: state.bottomSearchQuery }), _jsx(Text, { bold: true, children: '_' })] }, "search-prompt"));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (parts.length === 0)
|
|
202
|
+
return null;
|
|
203
|
+
return _jsx(Box, { flexDirection: "column", children: parts });
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=BottomPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BottomPanel.js","sourceRoot":"","sources":["../../src/components/BottomPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppState } from '../lib/types.js';
|
|
3
|
+
interface ExecScreenProps {
|
|
4
|
+
state: AppState;
|
|
5
|
+
columns: number;
|
|
6
|
+
rows: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function ExecScreen({ state, columns, rows }: ExecScreenProps): React.ReactElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
import { useTheme } from '../lib/inkTheme.js';
|
|
4
|
+
import { Logo } from './Logo.js';
|
|
5
|
+
import { Separator } from './Separator.js';
|
|
6
|
+
import { Legend } from './Legend.js';
|
|
7
|
+
export function ExecScreen({ state, columns, rows }) {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
const serviceName = state.execService || '???';
|
|
10
|
+
const runningIndicator = state.execChild ? 'running' : 'ready';
|
|
11
|
+
const runningColor = state.execChild ? theme.yellow : theme.green;
|
|
12
|
+
// Header = logo(4) + sep(1) + legend(1) + status(1) = 7
|
|
13
|
+
const headerHeight = 7;
|
|
14
|
+
const availableRows = Math.max(1, rows - headerHeight - 1); // -1 for prompt
|
|
15
|
+
const totalLines = state.execOutputLines.length;
|
|
16
|
+
const startLine = Math.max(0, totalLines - availableRows);
|
|
17
|
+
const visibleLines = state.execOutputLines.slice(startLine);
|
|
18
|
+
const paddingNeeded = Math.max(0, rows - headerHeight - visibleLines.length - 1);
|
|
19
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Logo, {}), _jsx(Separator, { columns: columns }), _jsx(Legend, { execMode: true }), _jsxs(Text, { children: [_jsx(Text, { color: theme.cyan, children: ' exec ' }), _jsx(Text, { bold: true, children: serviceName }), _jsx(Text, { children: ' ' }), _jsx(Text, { color: runningColor, children: runningIndicator }), state.execCwd && _jsx(Text, { color: theme.dim, children: ' ' + state.execCwd })] }), visibleLines.map((line, i) => (_jsx(Text, { children: ' ' + line.substring(0, columns - 4) }, i))), paddingNeeded > 0 && Array.from({ length: paddingNeeded }, (_, i) => (_jsx(Text, { children: '' }, `pad-${i}`))), _jsxs(Text, { children: [_jsx(Text, { color: theme.green, children: '$ ' }), _jsx(Text, { children: state.execInput }), _jsx(Text, { bold: true, children: '_' })] })] }));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=ExecScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecScreen.js","sourceRoot":"","sources":["../../src/components/ExecScreen.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAmB;IAClE,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;IAC/C,MAAM,gBAAgB,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAElE,wDAAwD;IACxD,MAAM,YAAY,GAAG,CAAC,CAAC;IACvB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB;IAE5E,MAAM,UAAU,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAE5D,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEjF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,KAAG,EACR,KAAC,SAAS,IAAC,OAAO,EAAE,OAAO,GAAI,EAC/B,KAAC,MAAM,IAAC,QAAQ,EAAE,IAAI,GAAI,EAC1B,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,IAAI,YAAG,QAAQ,GAAQ,EAC1C,KAAC,IAAI,IAAC,IAAI,kBAAE,WAAW,GAAQ,EAC/B,KAAC,IAAI,cAAE,IAAI,GAAQ,EACnB,KAAC,IAAI,IAAC,KAAK,EAAE,YAAY,YAAG,gBAAgB,GAAQ,EACnD,KAAK,CAAC,OAAO,IAAI,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,GAAG,YAAG,IAAI,GAAG,KAAK,CAAC,OAAO,GAAQ,IAClE,EAEN,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAC7B,KAAC,IAAI,cAAU,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,IAAzC,CAAC,CAAgD,CAC7D,CAAC,EAED,aAAa,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACpE,KAAC,IAAI,cAAmB,EAAE,IAAf,OAAO,CAAC,EAAE,CAAa,CACnC,CAAC,EAEF,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,YAAG,IAAI,GAAQ,EACvC,KAAC,IAAI,cAAE,KAAK,CAAC,SAAS,GAAQ,EAC9B,KAAC,IAAI,IAAC,IAAI,kBAAE,GAAG,GAAQ,IAClB,IACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
import { useTheme } from '../lib/inkTheme.js';
|
|
4
|
+
function LegendItem({ text, active }) {
|
|
5
|
+
const theme = useTheme();
|
|
6
|
+
if (active) {
|
|
7
|
+
return _jsx(Text, { inverse: true, children: ' ' + text + ' ' });
|
|
8
|
+
}
|
|
9
|
+
return _jsx(Text, { color: theme.dim, children: text });
|
|
10
|
+
}
|
|
11
|
+
export function Legend(opts) {
|
|
12
|
+
const { logPanelActive = false, logsScrollMode = false, noCacheActive = false, noDepsActive = false, watchActive = false, execMode = false, execInline = false, worktreePickerActive = false, } = opts;
|
|
13
|
+
let items;
|
|
14
|
+
if (opts.multiSelectActive) {
|
|
15
|
+
items = [
|
|
16
|
+
{ text: '[v] toggle', active: false },
|
|
17
|
+
{ text: '[Esc] discard', active: false },
|
|
18
|
+
{ text: 'Re[B]uild all', active: false },
|
|
19
|
+
{ text: '[S]tart all', active: false },
|
|
20
|
+
{ text: 'Sto[P] all', active: false },
|
|
21
|
+
{ text: 'Switch [t]ree all', active: false },
|
|
22
|
+
{ text: '[Q]uit', active: false },
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
else if (worktreePickerActive) {
|
|
26
|
+
items = [
|
|
27
|
+
{ text: '[Esc] cancel', active: false },
|
|
28
|
+
{ text: '[Enter] switch', active: false },
|
|
29
|
+
{ text: '[j/k] navigate', active: false },
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
else if (execMode) {
|
|
33
|
+
items = [
|
|
34
|
+
{ text: '[Esc] back', active: false },
|
|
35
|
+
{ text: '[Enter] run', active: false },
|
|
36
|
+
{ text: '[Up/Down] history', active: false },
|
|
37
|
+
{ text: '[Ctrl+C] kill', active: false },
|
|
38
|
+
{ text: '[Ctrl+Q] quit', active: false },
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
else if (execInline) {
|
|
42
|
+
items = [
|
|
43
|
+
{ text: '[Esc] back', active: false },
|
|
44
|
+
{ text: '[Enter] run', active: false },
|
|
45
|
+
{ text: '[Up/Down] history', active: false },
|
|
46
|
+
{ text: '[Ctrl+C] kill', active: false },
|
|
47
|
+
{ text: '[Ctrl+F] full screen', active: false },
|
|
48
|
+
{ text: '[Ctrl+Q] quit', active: false },
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
else if (logsScrollMode) {
|
|
52
|
+
const hasSearch = opts.hasLogSearch || false;
|
|
53
|
+
items = [
|
|
54
|
+
{ text: hasSearch ? '[Esc] clear search' : '[Esc] back', active: false },
|
|
55
|
+
{ text: '[j/k] scroll', active: false },
|
|
56
|
+
{ text: '[G] bottom', active: false },
|
|
57
|
+
{ text: '[gg] top', active: false },
|
|
58
|
+
{ text: '[/] search', active: false },
|
|
59
|
+
{ text: '[n/N] next/prev', active: false },
|
|
60
|
+
{ text: '[Q]uit', active: false },
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const { buildingActive = false, startingActive = false } = opts;
|
|
65
|
+
items = [
|
|
66
|
+
{ text: buildingActive ? 'Stop [B]uild' : 'Re[B]uild', active: buildingActive },
|
|
67
|
+
{ text: '[D]ep rebuild', active: false },
|
|
68
|
+
{ text: startingActive ? 'Stop [S]tart' : 'Re[S]tart', active: startingActive },
|
|
69
|
+
{ text: 'Sto[P]', active: false },
|
|
70
|
+
{ text: '[W]atch', active: watchActive },
|
|
71
|
+
{ text: '[N]o cache', active: noCacheActive },
|
|
72
|
+
{ text: 'n[O] deps', active: noDepsActive },
|
|
73
|
+
{ text: '[e]xec', active: false },
|
|
74
|
+
{ text: '[F]ull [L]ogs', active: logPanelActive },
|
|
75
|
+
{ text: '[v] select', active: false },
|
|
76
|
+
{ text: 'Switch [t]ree', active: false },
|
|
77
|
+
{ text: '[Q]uit', active: false },
|
|
78
|
+
];
|
|
79
|
+
const customActions = opts.customActions || [];
|
|
80
|
+
for (const action of customActions) {
|
|
81
|
+
items.push({ text: `[${action.key}] ${action.label}`, active: false });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: ' ' }), items.map((item, i) => (_jsxs(Box, { children: [_jsx(LegendItem, { text: item.text, active: item.active }), i < items.length - 1 && _jsx(Text, { children: ' ' })] }, i)))] }));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=Legend.js.map
|