recomposable 1.1.6 → 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.
Files changed (49) hide show
  1. package/README.md +23 -8
  2. package/dist/components/App.d.ts +10 -0
  3. package/dist/components/App.js +149 -0
  4. package/dist/components/App.js.map +1 -0
  5. package/dist/components/BottomPanel.d.ts +9 -0
  6. package/dist/components/BottomPanel.js +205 -0
  7. package/dist/components/BottomPanel.js.map +1 -0
  8. package/dist/components/ExecScreen.d.ts +9 -0
  9. package/dist/components/ExecScreen.js +21 -0
  10. package/dist/components/ExecScreen.js.map +1 -0
  11. package/dist/components/Legend.d.ts +3 -0
  12. package/dist/components/Legend.js +86 -0
  13. package/dist/components/Legend.js.map +1 -0
  14. package/dist/components/ListScreen.d.ts +9 -0
  15. package/dist/components/ListScreen.js +85 -0
  16. package/dist/components/ListScreen.js.map +1 -0
  17. package/dist/components/LogScreen.d.ts +9 -0
  18. package/dist/components/LogScreen.js +130 -0
  19. package/dist/components/LogScreen.js.map +1 -0
  20. package/dist/components/Logo.d.ts +2 -0
  21. package/dist/components/Logo.js +8 -0
  22. package/dist/components/Logo.js.map +1 -0
  23. package/dist/components/Separator.d.ts +6 -0
  24. package/dist/components/Separator.js +8 -0
  25. package/dist/components/Separator.js.map +1 -0
  26. package/dist/components/ServiceRow.d.ts +11 -0
  27. package/dist/components/ServiceRow.js +159 -0
  28. package/dist/components/ServiceRow.js.map +1 -0
  29. package/dist/index.d.ts +26 -1
  30. package/dist/index.js +715 -293
  31. package/dist/index.js.map +1 -1
  32. package/dist/lib/docker.d.ts +12 -10
  33. package/dist/lib/docker.js +190 -103
  34. package/dist/lib/docker.js.map +1 -1
  35. package/dist/lib/inkTheme.d.ts +18 -0
  36. package/dist/lib/inkTheme.js +33 -0
  37. package/dist/lib/inkTheme.js.map +1 -0
  38. package/dist/lib/renderer.d.ts +1 -1
  39. package/dist/lib/renderer.js +120 -76
  40. package/dist/lib/renderer.js.map +1 -1
  41. package/dist/lib/state.d.ts +12 -1
  42. package/dist/lib/state.js +30 -21
  43. package/dist/lib/state.js.map +1 -1
  44. package/dist/lib/theme.js +15 -25
  45. package/dist/lib/theme.js.map +1 -1
  46. package/dist/lib/types.d.ts +14 -0
  47. package/dist/lib/types.js +1 -4
  48. package/dist/lib/types.js.map +1 -1
  49. 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. Pure Node.js.
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
  ![recomposable demo](screenshots/demo.gif)
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 (`x`), with `cd` support and command history
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 `x` for full-screen exec. `cd` works — the working directory is tracked across commands.
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
  ![recomposable exec view](screenshots/exec-view.png)
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` | Number of log lines shown in the inline log panel |
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` | Start (if stopped) or restart (if running) |
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
- | `x` | Expand inline exec to full screen |
179
- | `Ctrl+C` | Kill running command (double to quit) |
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,3 @@
1
+ import React from 'react';
2
+ import type { LegendOptions } from '../lib/types.js';
3
+ export declare function Legend(opts: LegendOptions): React.ReactElement;
@@ -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