@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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const DEFAULT_BASE16_PALETTE = {
|
|
2
|
+
base00: 0,
|
|
3
|
+
base01: 8,
|
|
4
|
+
base02: 8,
|
|
5
|
+
base03: 8,
|
|
6
|
+
base04: 8,
|
|
7
|
+
base05: 7,
|
|
8
|
+
base06: 15,
|
|
9
|
+
base07: 15,
|
|
10
|
+
base08: 9,
|
|
11
|
+
base09: 3,
|
|
12
|
+
base0A: 11,
|
|
13
|
+
base0B: 10,
|
|
14
|
+
base0C: 14,
|
|
15
|
+
base0D: 12,
|
|
16
|
+
base0E: 13,
|
|
17
|
+
base0F: 3,
|
|
18
|
+
};
|
|
19
|
+
export const DEFAULT_DASHBOARD_THEME = createDashboardTheme(DEFAULT_BASE16_PALETTE);
|
|
20
|
+
export function createDashboardTheme(palette) {
|
|
21
|
+
return {
|
|
22
|
+
palette,
|
|
23
|
+
background: ansiBackground(palette.base00),
|
|
24
|
+
surface: identity,
|
|
25
|
+
selectedSurface: identity,
|
|
26
|
+
border: ansiForeground(palette.base03),
|
|
27
|
+
muted: ansiForeground(palette.base04),
|
|
28
|
+
text: ansiForeground(palette.base05),
|
|
29
|
+
bright: compose(ansiForeground(palette.base06), bold),
|
|
30
|
+
accent: ansiForeground(palette.base0D),
|
|
31
|
+
success: ansiForeground(palette.base0B),
|
|
32
|
+
warning: ansiForeground(palette.base0A),
|
|
33
|
+
error: ansiForeground(palette.base08),
|
|
34
|
+
info: ansiForeground(palette.base0C),
|
|
35
|
+
purple: ansiForeground(palette.base0E),
|
|
36
|
+
stale: ansiForeground(palette.base04),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function ansiForeground(color) {
|
|
40
|
+
const code = color < 8 ? 30 + color : 82 + color;
|
|
41
|
+
return (text) => `\x1b[${code}m${text}\x1b[39m`;
|
|
42
|
+
}
|
|
43
|
+
export function ansiBackground(color) {
|
|
44
|
+
const code = color < 8 ? 40 + color : 92 + color;
|
|
45
|
+
return (text) => `\x1b[${code}m${text}\x1b[49m`;
|
|
46
|
+
}
|
|
47
|
+
export function bold(text) {
|
|
48
|
+
return `\x1b[1m${text}\x1b[22m`;
|
|
49
|
+
}
|
|
50
|
+
function compose(...styles) {
|
|
51
|
+
return (text) => styles.reduceRight((value, style) => style(value), text);
|
|
52
|
+
}
|
|
53
|
+
function identity(text) {
|
|
54
|
+
return text;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=dashboard-theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-theme.js","sourceRoot":"","sources":["../../src/cli/dashboard-theme.ts"],"names":[],"mappings":"AAyCA,MAAM,CAAC,MAAM,sBAAsB,GAAkB;IACnD,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC,sBAAsB,CAAC,CAAC;AAEpF,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IACzD,OAAO;QACL,OAAO;QACP,UAAU,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1C,OAAO,EAAE,QAAQ;QACjB,eAAe,EAAE,QAAQ;QACzB,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACtC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACrC,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACpC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;QACrD,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACtC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACvC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACvC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACrC,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACpC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;QACtC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;IACjD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,IAAI,IAAI,IAAI,UAAU,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;IACjD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,IAAI,IAAI,IAAI,UAAU,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,UAAU,IAAI,UAAU,CAAC;AAClC,CAAC;AAED,SAAS,OAAO,CAAC,GAAG,MAAiB;IACnC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { ProcessTerminal, TuiAltScreen } from "@earendil-works/pi-tui";
|
|
2
|
+
import { loadConfig } from "../config/config.js";
|
|
3
|
+
import { createPresenceId, removeDashboardPresence, writeDashboardPresence } from "../state/dashboard-presence.js";
|
|
4
|
+
import { openDatabase } from "../state/database.js";
|
|
5
|
+
import { readStatuses } from "../state/read-statuses.js";
|
|
6
|
+
import { dismissAllRead, dismissStatus, markRead } from "../state/write-status.js";
|
|
7
|
+
import { focusPane } from "../tmux/focus.js";
|
|
8
|
+
import { listTmuxPanes } from "../tmux/list-panes.js";
|
|
9
|
+
import { DashboardComponent } from "./dashboard-component.js";
|
|
10
|
+
import { RUN_SPINNER_INTERVAL_MS } from "./dashboard-icons.js";
|
|
11
|
+
import { buildDashboardRows } from "./rows.js";
|
|
12
|
+
export function runDashboard(options = {}) {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
const db = openDatabase(config.databasePath);
|
|
15
|
+
const presenceId = createPresenceId();
|
|
16
|
+
const state = { rows: [], selected: 0, seenEvents: new Set(), message: null };
|
|
17
|
+
const terminal = new ProcessTerminal();
|
|
18
|
+
const tui = new TuiAltScreen(terminal);
|
|
19
|
+
let runtime;
|
|
20
|
+
const actions = createDashboardActions(() => runtime);
|
|
21
|
+
const component = new DashboardComponent(actions, () => terminal.rows);
|
|
22
|
+
runtime = {
|
|
23
|
+
config,
|
|
24
|
+
db,
|
|
25
|
+
presenceId,
|
|
26
|
+
state,
|
|
27
|
+
terminal,
|
|
28
|
+
tui,
|
|
29
|
+
component,
|
|
30
|
+
quitOnSelect: options.quitOnSelect ?? false,
|
|
31
|
+
refreshTimer: setInterval(() => refresh(runtime, true), 1_000),
|
|
32
|
+
presenceTimer: setInterval(() => writeDashboardPresence(db, presenceId, process.env.TMUX_PANE ?? null), config.dashboardPresenceIntervalMs),
|
|
33
|
+
animationTimer: setInterval(() => renderAnimationFrame(runtime), RUN_SPINNER_INTERVAL_MS),
|
|
34
|
+
cleaned: false,
|
|
35
|
+
};
|
|
36
|
+
tui.addChild(component);
|
|
37
|
+
tui.setFocus(component);
|
|
38
|
+
writeDashboardPresence(db, presenceId, process.env.TMUX_PANE ?? null);
|
|
39
|
+
refresh(runtime, false);
|
|
40
|
+
tui.start();
|
|
41
|
+
const cleanupHandler = () => cleanup(runtime);
|
|
42
|
+
const sigintHandler = () => { cleanup(runtime); process.exit(0); };
|
|
43
|
+
process.on("exit", cleanupHandler);
|
|
44
|
+
process.on("SIGINT", sigintHandler);
|
|
45
|
+
}
|
|
46
|
+
function createDashboardActions(getRuntime) {
|
|
47
|
+
return {
|
|
48
|
+
moveSelection: (delta) => moveSelection(getRuntime(), delta),
|
|
49
|
+
selectFirst: () => selectFirst(getRuntime()),
|
|
50
|
+
selectLast: () => selectLast(getRuntime()),
|
|
51
|
+
refresh: () => refreshFromInput(getRuntime()),
|
|
52
|
+
focusSelected: () => focusSelectedFromInput(getRuntime()),
|
|
53
|
+
dismissSelected: () => dismissSelectedFromInput(getRuntime()),
|
|
54
|
+
dismissAllRead: () => dismissAllReadFromInput(getRuntime()),
|
|
55
|
+
quit: () => quit(getRuntime()),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function cleanup(runtime) {
|
|
59
|
+
if (runtime.cleaned)
|
|
60
|
+
return;
|
|
61
|
+
runtime.cleaned = true;
|
|
62
|
+
clearInterval(runtime.refreshTimer);
|
|
63
|
+
clearInterval(runtime.presenceTimer);
|
|
64
|
+
clearInterval(runtime.animationTimer);
|
|
65
|
+
removeDashboardPresence(runtime.db, runtime.presenceId);
|
|
66
|
+
runtime.tui.stop();
|
|
67
|
+
runtime.db.close();
|
|
68
|
+
}
|
|
69
|
+
function refresh(runtime, beep) {
|
|
70
|
+
runtime.state.rows = buildDashboardRows(readStatuses(runtime.db), listTmuxPanes(), runtime.config);
|
|
71
|
+
clampSelection(runtime.state);
|
|
72
|
+
if (beep && runtime.config.dashboardBell)
|
|
73
|
+
beepForNewEvents(runtime);
|
|
74
|
+
else
|
|
75
|
+
rememberCurrentActionableEvents(runtime.state);
|
|
76
|
+
render(runtime);
|
|
77
|
+
}
|
|
78
|
+
function render(runtime) {
|
|
79
|
+
runtime.component.setSnapshot({ rows: runtime.state.rows, selected: runtime.state.selected, message: runtime.state.message });
|
|
80
|
+
runtime.tui.requestRender();
|
|
81
|
+
}
|
|
82
|
+
function renderAnimationFrame(runtime) {
|
|
83
|
+
if (!runtime.state.rows.some((row) => row.displayState === "RUN"))
|
|
84
|
+
return;
|
|
85
|
+
runtime.component.invalidate();
|
|
86
|
+
runtime.tui.requestRender();
|
|
87
|
+
}
|
|
88
|
+
function moveSelection(runtime, delta) {
|
|
89
|
+
runtime.state.message = null;
|
|
90
|
+
const lastIndex = Math.max(0, runtime.state.rows.length - 1);
|
|
91
|
+
runtime.state.selected = Math.min(lastIndex, Math.max(0, runtime.state.selected + delta));
|
|
92
|
+
render(runtime);
|
|
93
|
+
}
|
|
94
|
+
function selectFirst(runtime) {
|
|
95
|
+
runtime.state.message = null;
|
|
96
|
+
runtime.state.selected = 0;
|
|
97
|
+
render(runtime);
|
|
98
|
+
}
|
|
99
|
+
function selectLast(runtime) {
|
|
100
|
+
runtime.state.message = null;
|
|
101
|
+
runtime.state.selected = Math.max(0, runtime.state.rows.length - 1);
|
|
102
|
+
render(runtime);
|
|
103
|
+
}
|
|
104
|
+
function refreshFromInput(runtime) {
|
|
105
|
+
runtime.state.message = null;
|
|
106
|
+
refresh(runtime, false);
|
|
107
|
+
}
|
|
108
|
+
function dismissSelectedFromInput(runtime) {
|
|
109
|
+
runtime.state.message = null;
|
|
110
|
+
dismissSelected(runtime.db, runtime.state);
|
|
111
|
+
refresh(runtime, false);
|
|
112
|
+
}
|
|
113
|
+
function dismissAllReadFromInput(runtime) {
|
|
114
|
+
runtime.state.message = null;
|
|
115
|
+
dismissAllRead(runtime.db, runtime.config.actionableStates);
|
|
116
|
+
refresh(runtime, false);
|
|
117
|
+
}
|
|
118
|
+
function focusSelectedFromInput(runtime) {
|
|
119
|
+
runtime.state.message = null;
|
|
120
|
+
const rowSelected = focusSelected(runtime.db, runtime.state);
|
|
121
|
+
if (rowSelected && runtime.quitOnSelect) {
|
|
122
|
+
quit(runtime);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
refresh(runtime, false);
|
|
126
|
+
}
|
|
127
|
+
function quit(runtime) {
|
|
128
|
+
cleanup(runtime);
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
function clampSelection(state) {
|
|
132
|
+
state.selected = Math.min(state.selected, Math.max(0, state.rows.length - 1));
|
|
133
|
+
}
|
|
134
|
+
function beepForNewEvents(runtime) {
|
|
135
|
+
for (const row of runtime.state.rows) {
|
|
136
|
+
const key = eventKey(row);
|
|
137
|
+
if (row.actionable && row.unread && !row.dismissed && !runtime.state.seenEvents.has(key)) {
|
|
138
|
+
runtime.terminal.write("\x07");
|
|
139
|
+
runtime.state.seenEvents.add(key);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function rememberCurrentActionableEvents(state) {
|
|
144
|
+
for (const row of state.rows) {
|
|
145
|
+
if (row.actionable && !row.dismissed)
|
|
146
|
+
state.seenEvents.add(eventKey(row));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function eventKey(row) {
|
|
150
|
+
return `${row.id}:${row.lastEventAt}`;
|
|
151
|
+
}
|
|
152
|
+
function dismissSelected(db, state) {
|
|
153
|
+
const row = state.rows[state.selected];
|
|
154
|
+
if (row)
|
|
155
|
+
dismissStatus(db, row.id, row.lastEventAt);
|
|
156
|
+
}
|
|
157
|
+
function focusSelected(db, state) {
|
|
158
|
+
const row = state.rows[state.selected];
|
|
159
|
+
if (!row)
|
|
160
|
+
return false;
|
|
161
|
+
markRead(db, row.id, row.lastEventAt);
|
|
162
|
+
const pane = findPaneForFocus(row);
|
|
163
|
+
if (!pane) {
|
|
164
|
+
state.message = `Pane ${row.paneId ?? "?"} is no longer available. Refresh marks this row as STALE.`;
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const commands = focusPane(pane);
|
|
169
|
+
if (!process.env.TMUX)
|
|
170
|
+
state.message = `Not inside tmux. Run:\n${commands.join("\n")}`;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
state.message = `Failed to focus ${pane.paneId}: ${formatError(error)}`;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
function findPaneForFocus(row) {
|
|
178
|
+
const paneId = row.pane?.paneId ?? row.paneId;
|
|
179
|
+
if (!paneId)
|
|
180
|
+
return null;
|
|
181
|
+
return listTmuxPanes().find((pane) => pane.paneId === paneId) ?? null;
|
|
182
|
+
}
|
|
183
|
+
function formatError(error) {
|
|
184
|
+
return error instanceof Error ? error.message : String(error);
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DashboardRow } from "../domain/status.js";
|
|
2
|
+
export declare function renderRows(rows: DashboardRow[], selected?: number, now?: number): string;
|
|
3
|
+
export declare function formatRow(row: DashboardRow, selected: boolean, now?: number): string;
|
|
4
|
+
export declare function formatAge(ms: number): string;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
export function renderRows(rows, selected = 0, now = Date.now()) {
|
|
3
|
+
const lines = ["STATE AGE SESSION PROJECT LAST EVENT"];
|
|
4
|
+
rows.forEach((row, index) => lines.push(formatRow(row, index === selected, now)));
|
|
5
|
+
if (rows.length === 0)
|
|
6
|
+
lines.push("No pi sessions found.");
|
|
7
|
+
return lines.join("\n");
|
|
8
|
+
}
|
|
9
|
+
export function formatRow(row, selected, now = Date.now()) {
|
|
10
|
+
const marker = selected ? ">" : " ";
|
|
11
|
+
const state = row.displayState.padEnd(6);
|
|
12
|
+
const age = formatAge(now - row.lastEventAt).padEnd(5);
|
|
13
|
+
const session = (row.pane?.sessionName ?? row.tmuxSession ?? "?").padEnd(16).slice(0, 16);
|
|
14
|
+
const project = shortenPath(row.cwd).padEnd(22).slice(0, 22);
|
|
15
|
+
const unread = row.unread ? "*" : " ";
|
|
16
|
+
return `${marker}${unread}${state} ${age} ${session} ${project} ${row.summary}`;
|
|
17
|
+
}
|
|
18
|
+
export function formatAge(ms) {
|
|
19
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
20
|
+
if (seconds < 60)
|
|
21
|
+
return `${seconds}s`;
|
|
22
|
+
const minutes = Math.floor(seconds / 60);
|
|
23
|
+
if (minutes < 60)
|
|
24
|
+
return `${minutes}m`;
|
|
25
|
+
const hours = Math.floor(minutes / 60);
|
|
26
|
+
if (hours < 24)
|
|
27
|
+
return `${hours}h`;
|
|
28
|
+
return `${Math.floor(hours / 24)}d`;
|
|
29
|
+
}
|
|
30
|
+
function shortenPath(cwd) {
|
|
31
|
+
const home = process.env.HOME;
|
|
32
|
+
const value = home && cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd;
|
|
33
|
+
return value.startsWith(process.cwd()) ? relative(process.cwd(), value) || "." : value;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/cli/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadConfig } from "../config/config.js";
|
|
3
|
+
import { openDatabase } from "../state/database.js";
|
|
4
|
+
import { readStatuses } from "../state/read-statuses.js";
|
|
5
|
+
import { listTmuxPanes } from "../tmux/list-panes.js";
|
|
6
|
+
import { ensurePinnedSidebar, parseSidebarSide, parseSidebarWindowTarget, toggleSidebar } from "../tmux/sidebar.js";
|
|
7
|
+
import { renderRows } from "./format.js";
|
|
8
|
+
import { buildDashboardRows } from "./rows.js";
|
|
9
|
+
import { runWebServer } from "../web/server.js";
|
|
10
|
+
import { runDashboard } from "./dashboard.js";
|
|
11
|
+
const HELP = `pi-muxr
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
pi-muxr Open interactive dashboard
|
|
15
|
+
pi-muxr --sidebar [SIDE] Toggle pinned panes in every tmux window (default: right)
|
|
16
|
+
pi-muxr --list Print current rows and exit
|
|
17
|
+
pi-muxr --config Print resolved config
|
|
18
|
+
pi-muxr --web Serve browser terminal for a pi-muxr tmux session
|
|
19
|
+
pi-muxr --quit-on-select Exit after Enter focuses the selected row
|
|
20
|
+
pi-muxr --help Show this help
|
|
21
|
+
|
|
22
|
+
Keys: ↑/↓ or j/k select, Enter focus/read, d dismiss, D dismiss all read, r refresh, q quit.
|
|
23
|
+
|
|
24
|
+
Web: set HOST/PORT to change the bind address (defaults to 127.0.0.1:3042).
|
|
25
|
+
`;
|
|
26
|
+
function main(argv) {
|
|
27
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
28
|
+
console.log(HELP);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const sidebarWindowTarget = parseSidebarWindowTarget(argv);
|
|
33
|
+
if (sidebarWindowTarget) {
|
|
34
|
+
ensurePinnedSidebar(sidebarWindowTarget);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const sidebarSide = parseSidebarSide(argv);
|
|
38
|
+
if (sidebarSide) {
|
|
39
|
+
const result = toggleSidebar(sidebarSide);
|
|
40
|
+
console.log(result === "created" ? `Opened and pinned pi-muxr sidebars on the ${sidebarSide}.` : "Closed and unpinned pi-muxr sidebars.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error(formatError(error));
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const config = loadConfig();
|
|
50
|
+
if (argv.includes("--config")) {
|
|
51
|
+
console.log(JSON.stringify(config, null, 2));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (argv.includes("--web")) {
|
|
55
|
+
runWebServer();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (argv.includes("--list")) {
|
|
59
|
+
const db = openDatabase(config.databasePath);
|
|
60
|
+
try {
|
|
61
|
+
console.log(renderRows(buildDashboardRows(readStatuses(db), listTmuxPanes(), config)));
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
db.close();
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
runDashboard({ quitOnSelect: argv.includes("--quit-on-select") });
|
|
69
|
+
}
|
|
70
|
+
function formatError(error) {
|
|
71
|
+
return error instanceof Error ? error.message : String(error);
|
|
72
|
+
}
|
|
73
|
+
main(process.argv.slice(2));
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/rows.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isActionableStatus, isDismissedForCurrentEvent, isUnreadStatus } from "../domain/status.js";
|
|
2
|
+
import { sortDashboardRows } from "../domain/sorting.js";
|
|
3
|
+
export function buildDashboardRows(statuses, panes, config, now = Date.now()) {
|
|
4
|
+
const panesById = new Map(panes.map((pane) => [pane.paneId, pane]));
|
|
5
|
+
const rows = statuses.map((status) => toDashboardRow(status, panesById, config, now));
|
|
6
|
+
return sortDashboardRows(rows)
|
|
7
|
+
.filter((row) => row.displayState !== "STALE")
|
|
8
|
+
.filter((row) => config.showDismissedRows || !row.dismissed);
|
|
9
|
+
}
|
|
10
|
+
function toDashboardRow(status, panesById, config, now) {
|
|
11
|
+
const pane = status.paneId ? panesById.get(status.paneId) ?? null : null;
|
|
12
|
+
const missingPane = Boolean(status.paneId) && !pane;
|
|
13
|
+
const oldHeartbeat = now - status.heartbeatAt > config.staleAfterMs;
|
|
14
|
+
const displayState = oldHeartbeat || missingPane ? "STALE" : status.state;
|
|
15
|
+
const staleReason = oldHeartbeat ? "heartbeat expired" : missingPane ? "pane missing" : undefined;
|
|
16
|
+
const currentStatus = { ...status, state: displayState };
|
|
17
|
+
return {
|
|
18
|
+
...status,
|
|
19
|
+
displayState,
|
|
20
|
+
pane,
|
|
21
|
+
staleReason,
|
|
22
|
+
dismissed: isDismissedForCurrentEvent(status),
|
|
23
|
+
actionable: displayState === status.state && isActionableStatus(currentStatus, config.actionableStates),
|
|
24
|
+
unread: displayState === status.state && isUnreadStatus(currentStatus),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rows.js","sourceRoot":"","sources":["../../src/cli/rows.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrG,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,UAAU,kBAAkB,CAAC,QAAwB,EAAE,KAAiB,EAAE,MAAuB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACvH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACtF,OAAO,iBAAiB,CAAC,IAAI,CAAC;SAC3B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,OAAO,CAAC;SAC7C,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,cAAc,CAAC,MAAoB,EAAE,SAAgC,EAAE,MAAuB,EAAE,GAAW;IAClH,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACzE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IACpD,MAAM,YAAY,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC;IACpE,MAAM,YAAY,GAAG,YAAY,IAAI,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IAC1E,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,aAAa,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IACzD,OAAO;QACL,GAAG,MAAM;QACT,YAAY;QACZ,IAAI;QACJ,WAAW;QACX,SAAS,EAAE,0BAA0B,CAAC,MAAM,CAAC;QAC7C,UAAU,EAAE,YAAY,KAAK,MAAM,CAAC,KAAK,IAAI,kBAAkB,CAAC,aAAa,EAAE,MAAM,CAAC,gBAAgB,CAAC;QACvG,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC,aAAa,CAAC;KACvE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { DEFAULT_ACTIONABLE_STATES, PI_MUXR_STATES } from "../domain/status.js";
|
|
3
|
+
import { defaultConfigPath, defaultDatabasePath, defaultStateDir, expandHome } from "./paths.js";
|
|
4
|
+
export const DEFAULT_CONFIG = {
|
|
5
|
+
stateDir: defaultStateDir(),
|
|
6
|
+
databasePath: defaultDatabasePath(),
|
|
7
|
+
actionableStates: DEFAULT_ACTIONABLE_STATES,
|
|
8
|
+
desktopNotifications: true,
|
|
9
|
+
suppressDesktopNotificationsWhenDashboardOpen: true,
|
|
10
|
+
dashboardBell: true,
|
|
11
|
+
showDismissedRows: false,
|
|
12
|
+
staleAfterMs: 30_000,
|
|
13
|
+
heartbeatIntervalMs: 5_000,
|
|
14
|
+
dashboardPresenceIntervalMs: 2_000,
|
|
15
|
+
dashboardPresenceStaleAfterMs: 5_000,
|
|
16
|
+
};
|
|
17
|
+
export function loadConfig(configPath = defaultConfigPath()) {
|
|
18
|
+
let raw = {};
|
|
19
|
+
try {
|
|
20
|
+
raw = JSON.parse(readFileSync(expandHome(configPath), "utf8"));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error.code !== "ENOENT")
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
const stateDir = expandHome(raw.stateDir ?? DEFAULT_CONFIG.stateDir);
|
|
27
|
+
const databasePath = expandHome(raw.databasePath ?? (raw.stateDir ? `${stateDir}/pi-muxr.sqlite` : DEFAULT_CONFIG.databasePath));
|
|
28
|
+
const actionableStates = (raw.actionableStates ?? DEFAULT_CONFIG.actionableStates).filter((state) => PI_MUXR_STATES.includes(state));
|
|
29
|
+
return {
|
|
30
|
+
...DEFAULT_CONFIG,
|
|
31
|
+
...raw,
|
|
32
|
+
stateDir,
|
|
33
|
+
databasePath,
|
|
34
|
+
actionableStates: actionableStates.length > 0 ? actionableStates : DEFAULT_CONFIG.actionableStates,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjG,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,QAAQ,EAAE,eAAe,EAAE;IAC3B,YAAY,EAAE,mBAAmB,EAAE;IACnC,gBAAgB,EAAE,yBAAyB;IAC3C,oBAAoB,EAAE,IAAI;IAC1B,6CAA6C,EAAE,IAAI;IACnD,aAAa,EAAE,IAAI;IACnB,iBAAiB,EAAE,KAAK;IACxB,YAAY,EAAE,MAAM;IACpB,mBAAmB,EAAE,KAAK;IAC1B,2BAA2B,EAAE,KAAK;IAClC,6BAA6B,EAAE,KAAK;CACrC,CAAC;AAIF,MAAM,UAAU,UAAU,CAAC,UAAU,GAAG,iBAAiB,EAAE;IACzD,IAAI,GAAG,GAAc,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,CAAc,CAAC;IAC9E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IACtE,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IACrE,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,iBAAiB,CAAC,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IACjI,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,gBAAgB,IAAI,cAAc,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAwD,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAc,CAAC,CAAC,CAAC;IAEpM,OAAO;QACL,GAAG,cAAc;QACjB,GAAG,GAAG;QACN,QAAQ;QACR,YAAY;QACZ,gBAAgB,EAAE,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,CAAC,gBAAgB;KACnG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function expandHome(input: string): string;
|
|
2
|
+
export declare function defaultStateDir(): string;
|
|
3
|
+
export declare function defaultDatabasePath(): string;
|
|
4
|
+
export declare function defaultConfigPath(): string;
|
|
5
|
+
export declare function parentDir(path: string): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
export function expandHome(input) {
|
|
4
|
+
if (input === "~")
|
|
5
|
+
return homedir();
|
|
6
|
+
if (input.startsWith("~/"))
|
|
7
|
+
return join(homedir(), input.slice(2));
|
|
8
|
+
return input;
|
|
9
|
+
}
|
|
10
|
+
export function defaultStateDir() {
|
|
11
|
+
return join(homedir(), ".pi-muxr");
|
|
12
|
+
}
|
|
13
|
+
export function defaultDatabasePath() {
|
|
14
|
+
return join(defaultStateDir(), "pi-muxr.sqlite");
|
|
15
|
+
}
|
|
16
|
+
export function defaultConfigPath() {
|
|
17
|
+
return join(defaultStateDir(), "config.json");
|
|
18
|
+
}
|
|
19
|
+
export function parentDir(path) {
|
|
20
|
+
return dirname(path);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,OAAO,EAAE,CAAC;IACpC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,eAAe,EAAE,EAAE,gBAAgB,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,eAAe,EAAE,EAAE,aAAa,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { projectName } from "./status.js";
|
|
2
|
+
const STATE_PRIORITY = {
|
|
3
|
+
ASK: 0,
|
|
4
|
+
ERROR: 1,
|
|
5
|
+
DONE: 2,
|
|
6
|
+
QUEUED: 3,
|
|
7
|
+
RUN: 4,
|
|
8
|
+
IDLE: 5,
|
|
9
|
+
STALE: 6,
|
|
10
|
+
};
|
|
11
|
+
function actionBucket(row) {
|
|
12
|
+
if (row.actionable && row.unread)
|
|
13
|
+
return 0;
|
|
14
|
+
if (row.actionable)
|
|
15
|
+
return 1;
|
|
16
|
+
return 2;
|
|
17
|
+
}
|
|
18
|
+
export function compareDashboardRows(a, b) {
|
|
19
|
+
return actionBucket(a) - actionBucket(b)
|
|
20
|
+
|| STATE_PRIORITY[a.displayState] - STATE_PRIORITY[b.displayState]
|
|
21
|
+
|| b.lastEventAt - a.lastEventAt
|
|
22
|
+
|| projectName(a.cwd).localeCompare(projectName(b.cwd))
|
|
23
|
+
|| a.id.localeCompare(b.id);
|
|
24
|
+
}
|
|
25
|
+
export function sortDashboardRows(rows) {
|
|
26
|
+
return [...rows].sort(compareDashboardRows);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=sorting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sorting.js","sourceRoot":"","sources":["../../src/domain/sorting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,cAAc,GAAgC;IAClD,GAAG,EAAE,CAAC;IACN,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,SAAS,YAAY,CAAC,GAAiB;IACrC,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,CAAe,EAAE,CAAe;IACnE,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;WACnC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC;WAC/D,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;WAC7B,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;WACpD,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAoB;IACpD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export declare const PI_MUXR_STATES: readonly ["ASK", "ERROR", "DONE", "QUEUED", "RUN", "IDLE", "STALE"];
|
|
2
|
+
export type PiMuxrState = (typeof PI_MUXR_STATES)[number];
|
|
3
|
+
export declare const SEVERITIES: readonly ["low", "medium", "high"];
|
|
4
|
+
export type PiMuxrSeverity = (typeof SEVERITIES)[number];
|
|
5
|
+
export interface PiMuxrStatus {
|
|
6
|
+
id: string;
|
|
7
|
+
paneId: string | null;
|
|
8
|
+
tmuxSession: string | null;
|
|
9
|
+
tmuxWindow: string | null;
|
|
10
|
+
tmuxWindowIndex: string | null;
|
|
11
|
+
pid: number;
|
|
12
|
+
cwd: string;
|
|
13
|
+
piSessionFile: string | null;
|
|
14
|
+
model: string | null;
|
|
15
|
+
state: PiMuxrState;
|
|
16
|
+
severity: PiMuxrSeverity;
|
|
17
|
+
summary: string;
|
|
18
|
+
lastEventAt: number;
|
|
19
|
+
heartbeatAt: number;
|
|
20
|
+
readUntilEventAt?: number | null;
|
|
21
|
+
acknowledgedAt?: number | null;
|
|
22
|
+
dismissedUntilEventAt?: number | null;
|
|
23
|
+
lastNotifiedEventAt?: number | null;
|
|
24
|
+
}
|
|
25
|
+
export interface DashboardConfig {
|
|
26
|
+
stateDir: string;
|
|
27
|
+
databasePath: string;
|
|
28
|
+
actionableStates: PiMuxrState[];
|
|
29
|
+
desktopNotifications: boolean;
|
|
30
|
+
suppressDesktopNotificationsWhenDashboardOpen: boolean;
|
|
31
|
+
dashboardBell: boolean;
|
|
32
|
+
showDismissedRows: boolean;
|
|
33
|
+
staleAfterMs: number;
|
|
34
|
+
heartbeatIntervalMs: number;
|
|
35
|
+
dashboardPresenceIntervalMs: number;
|
|
36
|
+
dashboardPresenceStaleAfterMs: number;
|
|
37
|
+
}
|
|
38
|
+
export interface TmuxPane {
|
|
39
|
+
sessionName: string;
|
|
40
|
+
windowIndex: string;
|
|
41
|
+
windowName: string;
|
|
42
|
+
paneId: string;
|
|
43
|
+
paneActive: boolean;
|
|
44
|
+
currentCommand: string;
|
|
45
|
+
paneTitle: string;
|
|
46
|
+
panePid: number;
|
|
47
|
+
}
|
|
48
|
+
export interface DashboardRow extends PiMuxrStatus {
|
|
49
|
+
displayState: PiMuxrState;
|
|
50
|
+
pane: TmuxPane | null;
|
|
51
|
+
actionable: boolean;
|
|
52
|
+
unread: boolean;
|
|
53
|
+
dismissed: boolean;
|
|
54
|
+
staleReason?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare const DEFAULT_ACTIONABLE_STATES: PiMuxrState[];
|
|
57
|
+
export declare function isActionableStatus(status: Pick<PiMuxrStatus, "state" | "lastEventAt" | "dismissedUntilEventAt">, actionableStates?: ("ASK" | "DONE" | "ERROR" | "IDLE" | "QUEUED" | "RUN" | "STALE")[]): boolean;
|
|
58
|
+
export declare function isUnreadStatus(status: Pick<PiMuxrStatus, "lastEventAt" | "readUntilEventAt" | "dismissedUntilEventAt">): boolean;
|
|
59
|
+
export declare function isDismissedForCurrentEvent(status: Pick<PiMuxrStatus, "lastEventAt" | "dismissedUntilEventAt">): boolean;
|
|
60
|
+
export declare function projectName(cwd: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const PI_MUXR_STATES = ["ASK", "ERROR", "DONE", "QUEUED", "RUN", "IDLE", "STALE"];
|
|
2
|
+
export const SEVERITIES = ["low", "medium", "high"];
|
|
3
|
+
export const DEFAULT_ACTIONABLE_STATES = ["ASK", "ERROR", "DONE"];
|
|
4
|
+
export function isActionableStatus(status, actionableStates = DEFAULT_ACTIONABLE_STATES) {
|
|
5
|
+
return actionableStates.includes(status.state) && !isDismissedForCurrentEvent(status);
|
|
6
|
+
}
|
|
7
|
+
export function isUnreadStatus(status) {
|
|
8
|
+
return !isDismissedForCurrentEvent(status) && (status.readUntilEventAt ?? 0) < status.lastEventAt;
|
|
9
|
+
}
|
|
10
|
+
export function isDismissedForCurrentEvent(status) {
|
|
11
|
+
return (status.dismissedUntilEventAt ?? 0) >= status.lastEventAt;
|
|
12
|
+
}
|
|
13
|
+
export function projectName(cwd) {
|
|
14
|
+
const normalized = cwd.replace(/\/$/, "");
|
|
15
|
+
return normalized.split("/").filter(Boolean).at(-1) ?? cwd;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/domain/status.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAGlG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AA0D7D,MAAM,CAAC,MAAM,yBAAyB,GAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAEjF,MAAM,UAAU,kBAAkB,CAAC,MAA6E,EAAE,gBAAgB,GAAG,yBAAyB;IAC5J,OAAO,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAwF;IACrH,OAAO,CAAC,0BAA0B,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAmE;IAC5G,OAAO,CAAC,MAAM,CAAC,qBAAqB,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AAC7D,CAAC"}
|