@yuriteixeira/pi-muxr 0.1.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/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/cli/dashboard-component.d.ts +41 -0
- package/dist/cli/dashboard-component.js +236 -0
- package/dist/cli/dashboard-component.js.map +1 -0
- package/dist/cli/dashboard-icons.d.ts +10 -0
- package/dist/cli/dashboard-icons.js +40 -0
- package/dist/cli/dashboard-icons.js.map +1 -0
- package/dist/cli/dashboard-layout.d.ts +20 -0
- package/dist/cli/dashboard-layout.js +50 -0
- package/dist/cli/dashboard-layout.js.map +1 -0
- package/dist/cli/dashboard-theme.d.ts +43 -0
- package/dist/cli/dashboard-theme.js +56 -0
- package/dist/cli/dashboard-theme.js.map +1 -0
- package/dist/cli/dashboard.d.ts +4 -0
- package/dist/cli/dashboard.js +186 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.js +35 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +74 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/rows.d.ts +2 -0
- package/dist/cli/rows.js +27 -0
- package/dist/cli/rows.js.map +1 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/config/config.js +37 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/paths.d.ts +5 -0
- package/dist/config/paths.js +22 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/domain/sorting.d.ts +3 -0
- package/dist/domain/sorting.js +28 -0
- package/dist/domain/sorting.js.map +1 -0
- package/dist/domain/status.d.ts +60 -0
- package/dist/domain/status.js +17 -0
- package/dist/domain/status.js.map +1 -0
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +2 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/extension/pi-muxr.d.ts +7 -0
- package/dist/extension/pi-muxr.js +262 -0
- package/dist/extension/pi-muxr.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/desktop.d.ts +2 -0
- package/dist/notifications/desktop.js +29 -0
- package/dist/notifications/desktop.js.map +1 -0
- package/dist/state/dashboard-presence.d.ts +6 -0
- package/dist/state/dashboard-presence.js +23 -0
- package/dist/state/dashboard-presence.js.map +1 -0
- package/dist/state/database.d.ts +3 -0
- package/dist/state/database.js +12 -0
- package/dist/state/database.js.map +1 -0
- package/dist/state/read-statuses.d.ts +3 -0
- package/dist/state/read-statuses.js +5 -0
- package/dist/state/read-statuses.js.map +1 -0
- package/dist/state/rows.d.ts +23 -0
- package/dist/state/rows.js +23 -0
- package/dist/state/rows.js.map +1 -0
- package/dist/state/schema.d.ts +1 -0
- package/dist/state/schema.js +31 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/state/write-status.d.ts +10 -0
- package/dist/state/write-status.js +59 -0
- package/dist/state/write-status.js.map +1 -0
- package/dist/tmux/focus.d.ts +3 -0
- package/dist/tmux/focus.js +19 -0
- package/dist/tmux/focus.js.map +1 -0
- package/dist/tmux/list-panes.d.ts +5 -0
- package/dist/tmux/list-panes.js +21 -0
- package/dist/tmux/list-panes.js.map +1 -0
- package/dist/tmux/sidebar.d.ts +16 -0
- package/dist/tmux/sidebar.js +171 -0
- package/dist/tmux/sidebar.js.map +1 -0
- package/dist/web/assets.d.ts +5 -0
- package/dist/web/assets.js +19 -0
- package/dist/web/assets.js.map +1 -0
- package/dist/web/base16-theme.d.ts +23 -0
- package/dist/web/base16-theme.js +68 -0
- package/dist/web/base16-theme.js.map +1 -0
- package/dist/web/notifications.d.ts +7 -0
- package/dist/web/notifications.js +47 -0
- package/dist/web/notifications.js.map +1 -0
- package/dist/web/page.d.ts +1 -0
- package/dist/web/page.js +155 -0
- package/dist/web/page.js.map +1 -0
- package/dist/web/protocol.d.ts +25 -0
- package/dist/web/protocol.js +2 -0
- package/dist/web/protocol.js.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.js +51 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/terminal-gateway.d.ts +2 -0
- package/dist/web/terminal-gateway.js +110 -0
- package/dist/web/terminal-gateway.js.map +1 -0
- package/dist/web/tmux-session.d.ts +4 -0
- package/dist/web/tmux-session.js +50 -0
- package/dist/web/tmux-session.js.map +1 -0
- package/docs/ARCHITECTURE.md +287 -0
- package/docs/BUILDING.md +78 -0
- package/docs/CONTRIBUTING.md +32 -0
- package/docs/resources/fullscreen.png +0 -0
- package/docs/resources/sidebar.png +0 -0
- package/docs/resources/web.png +0 -0
- package/examples/config.json +13 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yuri Pereira Teixeira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Welcome to `pi-muxr`!
|
|
2
|
+
|
|
3
|
+
If you use [Pi](https://pi.dev) and if you sorta like `herdr`, but you're a die-hard tmux user that doesn't want to change your tooling or workflow, you came to the right place.
|
|
4
|
+
|
|
5
|
+
`pi-muxr` is a dashboard for Pi coding sessions that run in tmux. It also provides a webapp, so you can continue your work whenever you're away from your keyboard!
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Tracks multiple Pi sessions across tmux.
|
|
16
|
+
- Shows `ASK`, `ERROR`, `DONE`, `RUN`, and `IDLE` states for active sessions.
|
|
17
|
+
- Sorts actionable sessions first.
|
|
18
|
+
- Focuses the owning tmux pane from the keyboard.
|
|
19
|
+
- Supports read and dismiss actions.
|
|
20
|
+
- Detects and hides stale sessions with heartbeats and pane checks.
|
|
21
|
+
- Provides terminal and browser interfaces.
|
|
22
|
+
- Provides a toggleable pinned sidebar across all tmux sessions and windows.
|
|
23
|
+
- Sends terminal bell, desktop, and browser notifications.
|
|
24
|
+
- Supports configurable dashboard and browser actionable states.
|
|
25
|
+
- Supports configurable desktop notification and dashboard bell behavior.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Requirements:
|
|
30
|
+
|
|
31
|
+
- [Node.js 24 or later](https://nodejs.org/en/download)
|
|
32
|
+
- [Tmux](https://github.com/tmux/tmux?tab=readme-ov-file)
|
|
33
|
+
- [Pi](https://pi.dev)
|
|
34
|
+
|
|
35
|
+
Install the extension and its command with Pi:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pi install npm:@yuriteixeira/pi-muxr
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Restart Pi after installation, or run `/reload` in an active session.
|
|
42
|
+
|
|
43
|
+
To install only the dashboard command globally:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install --global @yuriteixeira/pi-muxr
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Open the dashboard in the current pane
|
|
53
|
+
pi-muxr
|
|
54
|
+
|
|
55
|
+
# Toggle the pinned dashboard sidebar
|
|
56
|
+
pi-muxr --sidebar
|
|
57
|
+
pi-muxr --sidebar right
|
|
58
|
+
pi-muxr --sidebar left
|
|
59
|
+
|
|
60
|
+
# Exit after selecting a session, useful in a tmux popup
|
|
61
|
+
pi-muxr --quit-on-select
|
|
62
|
+
|
|
63
|
+
# Output Pi sessions to standard output
|
|
64
|
+
pi-muxr --list
|
|
65
|
+
|
|
66
|
+
# Start the web app with a terminal emulator
|
|
67
|
+
# so you can continue your work from another device
|
|
68
|
+
pi-muxr --web
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Run `pi-muxr --sidebar` inside tmux to open and pin a full height dashboard pane on the right side of every window in every tmux session. Pass `left` or `right` to select the side. Each pane uses at most 25 percent of the window width. New tmux sessions and windows receive the same sidebar while it is pinned. The pinned sidebar is toggleable. Run the same command again to close all dashboard sidebar panes and remove the pin.
|
|
72
|
+
|
|
73
|
+
Use `--quit-on-select` to close the interactive dashboard after Enter focuses the selected row. The browser interface runs at `http://127.0.0.1:3042` by default.
|
|
74
|
+
|
|
75
|
+
### Tmux shortcuts
|
|
76
|
+
|
|
77
|
+
Add bindings like these to `~/.tmux.conf`:
|
|
78
|
+
|
|
79
|
+
```tmux
|
|
80
|
+
# Press the tmux prefix, then m, to open pi-muxr in a popup.
|
|
81
|
+
bind-key m display-popup -E -w 90% -h 90% "pi-muxr --quit-on-select"
|
|
82
|
+
|
|
83
|
+
# Press the tmux prefix, then s, to toggle the pinned right sidebar.
|
|
84
|
+
bind-key s run-shell "pi-muxr --sidebar right"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The default tmux prefix is `Ctrl+b`. With these bindings, press `Ctrl+b`, then `m` for the popup, or press `Ctrl+b`, then `s` for the sidebar. Change `right` to `left` if you want the sidebar on the left.
|
|
88
|
+
|
|
89
|
+
Reload the tmux configuration after you save it:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
tmux source-file ~/.tmux.conf
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The popup closes after you select a session because it uses `--quit-on-select`. The sidebar stays pinned across existing and new tmux sessions and windows. Use the same sidebar shortcut again to close it and remove the pin.
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
Configuration is optional. When `~/.pi-muxr/config.json` does not exist, pi-muxr uses its built in defaults.
|
|
100
|
+
|
|
101
|
+
The repository provides [an example configuration](examples/config.json) with every available setting. From a repository checkout, copy it to the configuration path:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
mkdir -p ~/.pi-muxr
|
|
105
|
+
cp examples/config.json ~/.pi-muxr/config.json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
You can then edit the copied file. The settings control:
|
|
109
|
+
|
|
110
|
+
- The state directory and SQLite database path.
|
|
111
|
+
- Which session states need action in the dashboard and browser interface.
|
|
112
|
+
- Desktop notifications for `ASK`, `ERROR`, and `DONE`, and the dashboard bell.
|
|
113
|
+
- Whether the dashboard shows dismissed rows.
|
|
114
|
+
- Stale session, heartbeat, and dashboard presence timing.
|
|
115
|
+
|
|
116
|
+
To check the active configuration, including defaults and your changes, run:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pi-muxr --config
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Development Documentation
|
|
123
|
+
|
|
124
|
+
- [Architecture](docs/ARCHITECTURE.md)
|
|
125
|
+
- [Building and local setup](docs/BUILDING.md)
|
|
126
|
+
- [Contributing](docs/CONTRIBUTING.md)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { DashboardRow } from "../domain/status.js";
|
|
3
|
+
import { type DashboardTheme } from "./dashboard-theme.js";
|
|
4
|
+
export interface DashboardActions {
|
|
5
|
+
moveSelection(delta: number): void;
|
|
6
|
+
selectFirst(): void;
|
|
7
|
+
selectLast(): void;
|
|
8
|
+
refresh(): void;
|
|
9
|
+
focusSelected(): void;
|
|
10
|
+
dismissSelected(): void;
|
|
11
|
+
dismissAllRead(): void;
|
|
12
|
+
quit(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface DashboardSnapshot {
|
|
15
|
+
rows: DashboardRow[];
|
|
16
|
+
selected: number;
|
|
17
|
+
message: string | null;
|
|
18
|
+
}
|
|
19
|
+
export interface RenderDashboardOptions extends DashboardSnapshot {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
now?: number;
|
|
23
|
+
theme?: DashboardTheme;
|
|
24
|
+
}
|
|
25
|
+
export declare class DashboardComponent implements Component {
|
|
26
|
+
private readonly actions;
|
|
27
|
+
private readonly getHeight;
|
|
28
|
+
private readonly theme;
|
|
29
|
+
private rows;
|
|
30
|
+
private selected;
|
|
31
|
+
private message;
|
|
32
|
+
private cachedWidth;
|
|
33
|
+
private cachedHeight;
|
|
34
|
+
private cachedLines;
|
|
35
|
+
constructor(actions: DashboardActions, getHeight: () => number, theme?: DashboardTheme);
|
|
36
|
+
setSnapshot(snapshot: DashboardSnapshot): void;
|
|
37
|
+
handleInput(data: string): void;
|
|
38
|
+
render(width: number): string[];
|
|
39
|
+
invalidate(): void;
|
|
40
|
+
}
|
|
41
|
+
export declare function renderDashboardLines(options: RenderDashboardOptions): string[];
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { getStateVisual } from "./dashboard-icons.js";
|
|
3
|
+
import { chooseDashboardLayout, fitCell, getVisibleRowRange, padToWidth, toRowText } from "./dashboard-layout.js";
|
|
4
|
+
import { DEFAULT_DASHBOARD_THEME } from "./dashboard-theme.js";
|
|
5
|
+
export class DashboardComponent {
|
|
6
|
+
actions;
|
|
7
|
+
getHeight;
|
|
8
|
+
theme;
|
|
9
|
+
rows = [];
|
|
10
|
+
selected = 0;
|
|
11
|
+
message = null;
|
|
12
|
+
cachedWidth;
|
|
13
|
+
cachedHeight;
|
|
14
|
+
cachedLines;
|
|
15
|
+
constructor(actions, getHeight, theme = DEFAULT_DASHBOARD_THEME) {
|
|
16
|
+
this.actions = actions;
|
|
17
|
+
this.getHeight = getHeight;
|
|
18
|
+
this.theme = theme;
|
|
19
|
+
}
|
|
20
|
+
setSnapshot(snapshot) {
|
|
21
|
+
this.rows = snapshot.rows;
|
|
22
|
+
this.selected = snapshot.selected;
|
|
23
|
+
this.message = snapshot.message;
|
|
24
|
+
this.invalidate();
|
|
25
|
+
}
|
|
26
|
+
handleInput(data) {
|
|
27
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k"))
|
|
28
|
+
this.actions.moveSelection(-1);
|
|
29
|
+
else if (matchesKey(data, Key.down) || matchesKey(data, "j"))
|
|
30
|
+
this.actions.moveSelection(1);
|
|
31
|
+
else if (matchesKey(data, Key.enter))
|
|
32
|
+
this.actions.focusSelected();
|
|
33
|
+
else if (matchesKey(data, "d"))
|
|
34
|
+
this.actions.dismissSelected();
|
|
35
|
+
else if (matchesKey(data, Key.shift("d")) || data === "D")
|
|
36
|
+
this.actions.dismissAllRead();
|
|
37
|
+
else if (matchesKey(data, "r"))
|
|
38
|
+
this.actions.refresh();
|
|
39
|
+
else if (matchesKey(data, "g"))
|
|
40
|
+
this.actions.selectFirst();
|
|
41
|
+
else if (matchesKey(data, Key.shift("g")) || data === "G")
|
|
42
|
+
this.actions.selectLast();
|
|
43
|
+
else if (matchesKey(data, "q") || matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")))
|
|
44
|
+
this.actions.quit();
|
|
45
|
+
}
|
|
46
|
+
render(width) {
|
|
47
|
+
const height = this.getHeight();
|
|
48
|
+
if (this.cachedLines && this.cachedWidth === width && this.cachedHeight === height)
|
|
49
|
+
return this.cachedLines;
|
|
50
|
+
this.cachedLines = renderDashboardLines({ rows: this.rows, selected: this.selected, message: this.message, width, height, theme: this.theme });
|
|
51
|
+
this.cachedWidth = width;
|
|
52
|
+
this.cachedHeight = height;
|
|
53
|
+
return this.cachedLines;
|
|
54
|
+
}
|
|
55
|
+
invalidate() {
|
|
56
|
+
this.cachedWidth = undefined;
|
|
57
|
+
this.cachedHeight = undefined;
|
|
58
|
+
this.cachedLines = undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function renderDashboardLines(options) {
|
|
62
|
+
const theme = options.theme ?? DEFAULT_DASHBOARD_THEME;
|
|
63
|
+
const width = Math.max(0, options.width);
|
|
64
|
+
if (width <= 1)
|
|
65
|
+
return ["".slice(0, width)];
|
|
66
|
+
const height = Math.max(1, options.height);
|
|
67
|
+
const innerWidth = Math.max(0, width - 2);
|
|
68
|
+
const messageLines = renderMessageLines(options.message, innerWidth, theme);
|
|
69
|
+
const mode = chooseDashboardLayout(width);
|
|
70
|
+
const showStatusSection = height >= messageLines.length + 8 && statusSectionFits(options.rows, mode, width, theme);
|
|
71
|
+
const fixedLineCount = 2 + messageLines.length + (showStatusSection ? 5 : 0);
|
|
72
|
+
const bodyHeight = Math.max(1, height - fixedLineCount);
|
|
73
|
+
const rows = renderRowsForViewport(options.rows, options.selected, mode, innerWidth, bodyHeight, options.now ?? Date.now(), theme);
|
|
74
|
+
const statusSection = showStatusSection ? renderStatusSection(options.rows, mode, width, theme) : [];
|
|
75
|
+
const lines = [
|
|
76
|
+
renderHeader(width, theme),
|
|
77
|
+
...messageLines.map((line) => frameLine(line, width, theme, theme.surface)),
|
|
78
|
+
...rows.map((line) => frameLine(line.text, width, theme, line.style, line.selected ? theme.accent : undefined)),
|
|
79
|
+
renderBottom(width, theme),
|
|
80
|
+
...statusSection,
|
|
81
|
+
];
|
|
82
|
+
return lines.slice(0, height).map((line) => truncateToWidth(line, width, "", false));
|
|
83
|
+
}
|
|
84
|
+
function renderRowsForViewport(rows, selected, mode, width, height, now, theme) {
|
|
85
|
+
if (rows.length === 0)
|
|
86
|
+
return renderEmptyState(width, height, theme);
|
|
87
|
+
return renderTableRows(rows, selected, mode, width, height, now, theme);
|
|
88
|
+
}
|
|
89
|
+
function renderTableRows(rows, selected, mode, width, height, now, theme) {
|
|
90
|
+
const reserveHint = rows.length > height && height > 1 ? 1 : 0;
|
|
91
|
+
const range = getVisibleRowRange(rows.length, selected, Math.max(1, height - reserveHint));
|
|
92
|
+
const lines = rows.slice(range.start, range.end).map((row, offset) => {
|
|
93
|
+
const index = range.start + offset;
|
|
94
|
+
const isSelected = index === selected;
|
|
95
|
+
return { text: renderTableRow(row, isSelected, mode, width, now, theme), style: isSelected ? theme.selectedSurface : undefined, selected: isSelected };
|
|
96
|
+
});
|
|
97
|
+
if (reserveHint)
|
|
98
|
+
lines.push({ text: renderScrollHint(range, width, theme) });
|
|
99
|
+
return padBody(lines, height, width);
|
|
100
|
+
}
|
|
101
|
+
function renderEmptyState(width, height, theme) {
|
|
102
|
+
const empty = theme.muted("No pi sessions found. Start pi in a tmux pane to populate this dashboard.");
|
|
103
|
+
return padBody([{ text: centerLine(empty, width) }], height, width);
|
|
104
|
+
}
|
|
105
|
+
function renderTableRow(row, selected, mode, width, now, theme) {
|
|
106
|
+
const text = toRowText(row, now);
|
|
107
|
+
const visual = getStateVisual(row.displayState, theme, now);
|
|
108
|
+
const indicator = selected ? theme.accent("❯") : " ";
|
|
109
|
+
const unreadMarker = row.unread ? ` ${theme.warning("●")}` : "";
|
|
110
|
+
const state = `${indicator} ${visual.style(`${visual.icon} ${visual.label}`)}${unreadMarker}`;
|
|
111
|
+
const summaryStyle = row.unread && row.actionable ? theme.bright : theme.text;
|
|
112
|
+
const innerWidth = Math.max(0, width);
|
|
113
|
+
const columns = mode === "wide"
|
|
114
|
+
? { session: 16, project: 24, age: 6 }
|
|
115
|
+
: mode === "medium"
|
|
116
|
+
? { session: 14, project: 22, age: 6 }
|
|
117
|
+
: innerWidth >= 46
|
|
118
|
+
? { session: 12, project: 18, age: 0 }
|
|
119
|
+
: { session: 10, project: 14, age: 0 };
|
|
120
|
+
const statusWidth = 12;
|
|
121
|
+
const fixedWidth = statusWidth + columns.session + columns.project + columns.age;
|
|
122
|
+
const separatorWidth = [statusWidth, columns.session, columns.project, columns.age].filter((value) => value > 0).length - 1;
|
|
123
|
+
const summaryWidth = Math.max(0, innerWidth - fixedWidth - separatorWidth);
|
|
124
|
+
const cells = [
|
|
125
|
+
padCell(state, statusWidth),
|
|
126
|
+
padCell(theme.info(text.session), columns.session),
|
|
127
|
+
padCell(theme.muted(fitPlainCellEnd(text.project, columns.project)), columns.project),
|
|
128
|
+
];
|
|
129
|
+
if (columns.age > 0)
|
|
130
|
+
cells.push(padCell(theme.muted(text.age), columns.age));
|
|
131
|
+
if (summaryWidth > 0)
|
|
132
|
+
cells.push(summaryStyle(fitPlainCell(text.summary, summaryWidth)));
|
|
133
|
+
return cells.join(" ");
|
|
134
|
+
}
|
|
135
|
+
function renderHeader(width, theme) {
|
|
136
|
+
return renderSectionTop("pi-muxr", width, theme, theme.bright);
|
|
137
|
+
}
|
|
138
|
+
function statusSectionFits(rows, mode, width, theme) {
|
|
139
|
+
const contentWidth = Math.max(visibleWidth(renderStats(rows, mode, theme)), visibleWidth(renderFooter(theme)));
|
|
140
|
+
return width >= contentWidth + 2;
|
|
141
|
+
}
|
|
142
|
+
function renderStatusSection(rows, mode, width, theme) {
|
|
143
|
+
return [
|
|
144
|
+
renderSectionTop("status", width, theme),
|
|
145
|
+
frameLine(renderStats(rows, mode, theme), width, theme, theme.surface),
|
|
146
|
+
renderSeparator(width, theme),
|
|
147
|
+
frameLine(renderFooter(theme), width, theme, theme.surface),
|
|
148
|
+
renderBottom(width, theme),
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
function renderStats(rows, mode, theme) {
|
|
152
|
+
const actionable = rows.filter((row) => row.actionable).length;
|
|
153
|
+
const unread = rows.filter((row) => row.unread && !row.dismissed).length;
|
|
154
|
+
const stale = rows.filter((row) => row.displayState === "STALE").length;
|
|
155
|
+
const layout = mode === "wide" ? "wide table" : mode === "medium" ? "compact table" : "small table";
|
|
156
|
+
return ` ${theme.warning("●")} ${unread} unread ${theme.accent("◆")} ${actionable} actionable ${theme.stale("")} ${stale} stale ${theme.muted(layout)}`;
|
|
157
|
+
}
|
|
158
|
+
function renderFooter(theme) {
|
|
159
|
+
return ` ${theme.accent("↑/↓ j/k")} select ${theme.accent("↵")} focus/read ${theme.accent("d")} dismiss ${theme.accent("D")} dismiss read ${theme.accent("r")} refresh ${theme.accent("q")} quit`;
|
|
160
|
+
}
|
|
161
|
+
function renderMessageLines(message, width, theme) {
|
|
162
|
+
if (!message)
|
|
163
|
+
return [];
|
|
164
|
+
return message.split("\n").slice(0, 3).map((line, index) => {
|
|
165
|
+
const prefix = index === 0 ? ` ${theme.warning("")} ` : " ";
|
|
166
|
+
return `${prefix}${fitCell(line, Math.max(0, width - visibleWidth(prefix)))}`;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function renderScrollHint(range, width, theme) {
|
|
170
|
+
const before = range.clippedBefore > 0 ? `${range.clippedBefore} above` : "top";
|
|
171
|
+
const after = range.clippedAfter > 0 ? `${range.clippedAfter} below` : "bottom";
|
|
172
|
+
return centerLine(theme.muted(`— ${before} • ${after} —`), width);
|
|
173
|
+
}
|
|
174
|
+
function renderSectionTop(title, width, theme, titleStyle = theme.muted) {
|
|
175
|
+
const innerWidth = Math.max(0, width - 2);
|
|
176
|
+
const label = ` ${titleStyle(title)} `;
|
|
177
|
+
const fillWidth = Math.max(0, innerWidth - visibleWidth(label) - 1);
|
|
178
|
+
const content = fillWidth > 0 ? `${theme.border("─")}${label}${theme.border("─".repeat(fillWidth))}` : fitCell(label, innerWidth);
|
|
179
|
+
return `${theme.border("╭")}${content}${theme.border("╮")}`;
|
|
180
|
+
}
|
|
181
|
+
function renderSeparator(width, theme) {
|
|
182
|
+
return `${theme.border("├")}${theme.border("─".repeat(Math.max(0, width - 2)))}${theme.border("┤")}`;
|
|
183
|
+
}
|
|
184
|
+
function renderBottom(width, theme) {
|
|
185
|
+
return `${theme.border("╰")}${theme.border("─".repeat(Math.max(0, width - 2)))}${theme.border("╯")}`;
|
|
186
|
+
}
|
|
187
|
+
function frameLine(content, width, theme, style, borderStyle = theme.border) {
|
|
188
|
+
const innerWidth = Math.max(0, width - 2);
|
|
189
|
+
const line = padToWidth(content, innerWidth);
|
|
190
|
+
return `${borderStyle("│")}${style ? style(line) : line}${borderStyle("│")}`;
|
|
191
|
+
}
|
|
192
|
+
function padCell(text, width) {
|
|
193
|
+
const fitted = fitCell(text, width);
|
|
194
|
+
return `${fitted}${" ".repeat(Math.max(0, width - visibleWidth(fitted)))}`;
|
|
195
|
+
}
|
|
196
|
+
function fitPlainCell(text, width, ellipsis = "…") {
|
|
197
|
+
if (width <= 0)
|
|
198
|
+
return "";
|
|
199
|
+
if (visibleWidth(text) <= width)
|
|
200
|
+
return text;
|
|
201
|
+
const ellipsisWidth = visibleWidth(ellipsis);
|
|
202
|
+
const targetWidth = Math.max(0, width - ellipsisWidth);
|
|
203
|
+
let result = "";
|
|
204
|
+
for (const char of text) {
|
|
205
|
+
if (visibleWidth(result + char) > targetWidth)
|
|
206
|
+
break;
|
|
207
|
+
result += char;
|
|
208
|
+
}
|
|
209
|
+
return `${result}${ellipsis}`;
|
|
210
|
+
}
|
|
211
|
+
function fitPlainCellEnd(text, width, ellipsis = "…") {
|
|
212
|
+
if (width <= 0)
|
|
213
|
+
return "";
|
|
214
|
+
if (visibleWidth(text) <= width)
|
|
215
|
+
return text;
|
|
216
|
+
const ellipsisWidth = visibleWidth(ellipsis);
|
|
217
|
+
const targetWidth = Math.max(0, width - ellipsisWidth);
|
|
218
|
+
let result = "";
|
|
219
|
+
for (const char of [...text].reverse()) {
|
|
220
|
+
if (visibleWidth(char + result) > targetWidth)
|
|
221
|
+
break;
|
|
222
|
+
result = char + result;
|
|
223
|
+
}
|
|
224
|
+
return `${ellipsis}${result}`;
|
|
225
|
+
}
|
|
226
|
+
function padBody(lines, height, width) {
|
|
227
|
+
const padded = lines.slice(0, height);
|
|
228
|
+
while (padded.length < height)
|
|
229
|
+
padded.push({ text: "" });
|
|
230
|
+
return padded.map((line) => ({ ...line, text: padToWidth(line.text, width) }));
|
|
231
|
+
}
|
|
232
|
+
function centerLine(text, width) {
|
|
233
|
+
const leftPadding = Math.max(0, Math.floor((width - visibleWidth(text)) / 2));
|
|
234
|
+
return padToWidth(`${" ".repeat(leftPadding)}${text}`, width);
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=dashboard-component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-component.js","sourceRoot":"","sources":["../../src/cli/dashboard-component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PiMuxrState } from "../domain/status.js";
|
|
2
|
+
import type { DashboardTheme, StyleFn } from "./dashboard-theme.js";
|
|
3
|
+
export interface StateVisual {
|
|
4
|
+
icon: string;
|
|
5
|
+
label: PiMuxrState;
|
|
6
|
+
style: StyleFn;
|
|
7
|
+
}
|
|
8
|
+
export declare const RUN_SPINNER_INTERVAL_MS = 80;
|
|
9
|
+
export declare function getStateIcon(state: PiMuxrState, now?: number): string;
|
|
10
|
+
export declare function getStateVisual(state: PiMuxrState, theme: DashboardTheme, now?: number): StateVisual;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const RUN_SPINNER_INTERVAL_MS = 80;
|
|
2
|
+
const RUN_SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
3
|
+
const STATE_ICONS = {
|
|
4
|
+
ASK: "",
|
|
5
|
+
ERROR: "",
|
|
6
|
+
DONE: "",
|
|
7
|
+
QUEUED: "",
|
|
8
|
+
IDLE: "",
|
|
9
|
+
STALE: "",
|
|
10
|
+
};
|
|
11
|
+
export function getStateIcon(state, now = 0) {
|
|
12
|
+
if (state === "RUN")
|
|
13
|
+
return getRunSpinnerFrame(now);
|
|
14
|
+
return STATE_ICONS[state];
|
|
15
|
+
}
|
|
16
|
+
export function getStateVisual(state, theme, now = 0) {
|
|
17
|
+
return { icon: getStateIcon(state, now), label: state, style: getStateStyle(state, theme) };
|
|
18
|
+
}
|
|
19
|
+
function getRunSpinnerFrame(now) {
|
|
20
|
+
const index = Math.floor(now / RUN_SPINNER_INTERVAL_MS) % RUN_SPINNER_FRAMES.length;
|
|
21
|
+
return RUN_SPINNER_FRAMES[index] ?? RUN_SPINNER_FRAMES[0];
|
|
22
|
+
}
|
|
23
|
+
function getStateStyle(state, theme) {
|
|
24
|
+
switch (state) {
|
|
25
|
+
case "ASK":
|
|
26
|
+
return theme.warning;
|
|
27
|
+
case "ERROR":
|
|
28
|
+
return theme.error;
|
|
29
|
+
case "DONE":
|
|
30
|
+
return theme.success;
|
|
31
|
+
case "RUN":
|
|
32
|
+
return theme.info;
|
|
33
|
+
case "QUEUED":
|
|
34
|
+
return theme.purple;
|
|
35
|
+
case "IDLE":
|
|
36
|
+
case "STALE":
|
|
37
|
+
return theme.stale;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=dashboard-icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-icons.js","sourceRoot":"","sources":["../../src/cli/dashboard-icons.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAEvF,MAAM,WAAW,GAAgD;IAC/D,GAAG,EAAE,GAAG;IACR,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,KAAkB,EAAE,GAAG,GAAG,CAAC;IACtD,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAkB,EAAE,KAAqB,EAAE,GAAG,GAAG,CAAC;IAC/E,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,uBAAuB,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC;IACpF,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,aAAa,CAAC,KAAkB,EAAE,KAAqB;IAC9D,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,KAAK,CAAC;QACrB,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,IAAI,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,KAAK,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DashboardRow } from "../domain/status.js";
|
|
2
|
+
export type DashboardLayoutMode = "wide" | "medium" | "narrow";
|
|
3
|
+
export interface RowText {
|
|
4
|
+
age: string;
|
|
5
|
+
project: string;
|
|
6
|
+
session: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
}
|
|
9
|
+
export interface VisibleRange {
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
clippedBefore: number;
|
|
13
|
+
clippedAfter: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function chooseDashboardLayout(width: number): DashboardLayoutMode;
|
|
16
|
+
export declare function getVisibleRowRange(totalRows: number, selected: number, maxRows: number): VisibleRange;
|
|
17
|
+
export declare function toRowText(row: DashboardRow, now?: number): RowText;
|
|
18
|
+
export declare function shortenPath(cwd: string): string;
|
|
19
|
+
export declare function fitCell(text: string, width: number, ellipsis?: string): string;
|
|
20
|
+
export declare function padToWidth(text: string, width: number): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
3
|
+
import { formatAge } from "./format.js";
|
|
4
|
+
export function chooseDashboardLayout(width) {
|
|
5
|
+
if (width >= 120)
|
|
6
|
+
return "wide";
|
|
7
|
+
if (width >= 80)
|
|
8
|
+
return "medium";
|
|
9
|
+
return "narrow";
|
|
10
|
+
}
|
|
11
|
+
export function getVisibleRowRange(totalRows, selected, maxRows) {
|
|
12
|
+
if (totalRows <= 0 || maxRows <= 0)
|
|
13
|
+
return { start: 0, end: 0, clippedBefore: 0, clippedAfter: totalRows };
|
|
14
|
+
const safeSelected = Math.min(Math.max(selected, 0), totalRows - 1);
|
|
15
|
+
const count = Math.min(totalRows, maxRows);
|
|
16
|
+
const centeredStart = safeSelected - Math.floor(count / 2);
|
|
17
|
+
const start = Math.min(Math.max(centeredStart, 0), totalRows - count);
|
|
18
|
+
const end = start + count;
|
|
19
|
+
return { start, end, clippedBefore: start, clippedAfter: totalRows - end };
|
|
20
|
+
}
|
|
21
|
+
export function toRowText(row, now = Date.now()) {
|
|
22
|
+
return {
|
|
23
|
+
age: shouldRunRowTimer(row) ? formatAge(now - row.lastEventAt) : "",
|
|
24
|
+
project: shortenPath(row.cwd),
|
|
25
|
+
session: row.pane?.sessionName ?? row.tmuxSession ?? "?",
|
|
26
|
+
summary: row.summary,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function shouldRunRowTimer(row) {
|
|
30
|
+
return row.displayState === "RUN" || row.displayState === "ASK" || row.displayState === "QUEUED";
|
|
31
|
+
}
|
|
32
|
+
export function shortenPath(cwd) {
|
|
33
|
+
const home = process.env.HOME;
|
|
34
|
+
const value = home && cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd;
|
|
35
|
+
return value.startsWith(process.cwd()) ? relative(process.cwd(), value) || "." : value;
|
|
36
|
+
}
|
|
37
|
+
export function fitCell(text, width, ellipsis = "…") {
|
|
38
|
+
if (width <= 0)
|
|
39
|
+
return "";
|
|
40
|
+
return truncateToWidth(text, width, ellipsis, true);
|
|
41
|
+
}
|
|
42
|
+
export function padToWidth(text, width) {
|
|
43
|
+
if (width <= 0)
|
|
44
|
+
return "";
|
|
45
|
+
const currentWidth = visibleWidth(text);
|
|
46
|
+
if (currentWidth > width)
|
|
47
|
+
return truncateToWidth(text, width, "…", true);
|
|
48
|
+
return text + " ".repeat(width - currentWidth);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=dashboard-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-layout.js","sourceRoot":"","sources":["../../src/cli/dashboard-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type StyleFn = (text: string) => string;
|
|
2
|
+
export type AnsiColor = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
|
|
3
|
+
export interface Base16Palette {
|
|
4
|
+
base00: AnsiColor;
|
|
5
|
+
base01: AnsiColor;
|
|
6
|
+
base02: AnsiColor;
|
|
7
|
+
base03: AnsiColor;
|
|
8
|
+
base04: AnsiColor;
|
|
9
|
+
base05: AnsiColor;
|
|
10
|
+
base06: AnsiColor;
|
|
11
|
+
base07: AnsiColor;
|
|
12
|
+
base08: AnsiColor;
|
|
13
|
+
base09: AnsiColor;
|
|
14
|
+
base0A: AnsiColor;
|
|
15
|
+
base0B: AnsiColor;
|
|
16
|
+
base0C: AnsiColor;
|
|
17
|
+
base0D: AnsiColor;
|
|
18
|
+
base0E: AnsiColor;
|
|
19
|
+
base0F: AnsiColor;
|
|
20
|
+
}
|
|
21
|
+
export interface DashboardTheme {
|
|
22
|
+
palette: Base16Palette;
|
|
23
|
+
background: StyleFn;
|
|
24
|
+
surface: StyleFn;
|
|
25
|
+
selectedSurface: StyleFn;
|
|
26
|
+
border: StyleFn;
|
|
27
|
+
muted: StyleFn;
|
|
28
|
+
text: StyleFn;
|
|
29
|
+
bright: StyleFn;
|
|
30
|
+
accent: StyleFn;
|
|
31
|
+
success: StyleFn;
|
|
32
|
+
warning: StyleFn;
|
|
33
|
+
error: StyleFn;
|
|
34
|
+
info: StyleFn;
|
|
35
|
+
purple: StyleFn;
|
|
36
|
+
stale: StyleFn;
|
|
37
|
+
}
|
|
38
|
+
export declare const DEFAULT_BASE16_PALETTE: Base16Palette;
|
|
39
|
+
export declare const DEFAULT_DASHBOARD_THEME: DashboardTheme;
|
|
40
|
+
export declare function createDashboardTheme(palette: Base16Palette): DashboardTheme;
|
|
41
|
+
export declare function ansiForeground(color: AnsiColor): StyleFn;
|
|
42
|
+
export declare function ansiBackground(color: AnsiColor): StyleFn;
|
|
43
|
+
export declare function bold(text: string): string;
|