@aliou/pi-processes 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -17
- package/package.json +28 -13
- package/src/index.ts +27 -0
- package/commands/index.ts +0 -334
- package/commands/settings-command.ts +0 -128
- package/components/log-stream-component.ts +0 -149
- package/components/process-picker-component.ts +0 -155
- package/components/processes-component.ts +0 -450
- package/components/status-format.ts +0 -38
- package/config.ts +0 -62
- package/constants/index.ts +0 -11
- package/constants/types.ts +0 -65
- package/hooks/cleanup.ts +0 -10
- package/hooks/index.ts +0 -18
- package/hooks/message-renderer.ts +0 -83
- package/hooks/process-end.ts +0 -92
- package/hooks/widget.ts +0 -146
- package/index.ts +0 -27
- package/manager.ts +0 -519
- package/tools/actions/clear.ts +0 -20
- package/tools/actions/index.ts +0 -49
- package/tools/actions/kill.ts +0 -76
- package/tools/actions/list.ts +0 -37
- package/tools/actions/logs.ts +0 -59
- package/tools/actions/output.ts +0 -144
- package/tools/actions/start.ts +0 -55
- package/tools/index.ts +0 -280
- package/utils/ansi.ts +0 -36
- package/utils/format.ts +0 -42
- package/utils/index.ts +0 -3
- package/utils/process-group.ts +0 -22
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createPanelPadder,
|
|
3
|
-
renderPanelRule,
|
|
4
|
-
renderPanelTitleLine,
|
|
5
|
-
} from "@aliou/pi-utils-ui";
|
|
6
|
-
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
7
|
-
import {
|
|
8
|
-
type Component,
|
|
9
|
-
truncateToWidth,
|
|
10
|
-
visibleWidth,
|
|
11
|
-
} from "@mariozechner/pi-tui";
|
|
12
|
-
import type { ProcessManager } from "../manager";
|
|
13
|
-
import { stripAnsi } from "../utils";
|
|
14
|
-
import { statusIcon, statusLabel } from "./status-format";
|
|
15
|
-
|
|
16
|
-
const MAX_LOG_LINES = 16;
|
|
17
|
-
const POLL_INTERVAL_MS = 500;
|
|
18
|
-
|
|
19
|
-
export class LogStreamComponent implements Component {
|
|
20
|
-
private tui: { requestRender: () => void };
|
|
21
|
-
private theme: Theme;
|
|
22
|
-
private manager: ProcessManager;
|
|
23
|
-
private processId: string;
|
|
24
|
-
private timer: ReturnType<typeof setInterval> | null = null;
|
|
25
|
-
private unsubscribe: (() => void) | null = null;
|
|
26
|
-
private cachedLines: string[] = [];
|
|
27
|
-
private cachedWidth = 0;
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
tui: { requestRender: () => void },
|
|
31
|
-
theme: Theme,
|
|
32
|
-
manager: ProcessManager,
|
|
33
|
-
processId: string,
|
|
34
|
-
) {
|
|
35
|
-
this.tui = tui;
|
|
36
|
-
this.theme = theme;
|
|
37
|
-
this.manager = manager;
|
|
38
|
-
this.processId = processId;
|
|
39
|
-
|
|
40
|
-
// Poll log file for new output.
|
|
41
|
-
this.timer = setInterval(() => {
|
|
42
|
-
this.invalidate();
|
|
43
|
-
this.tui.requestRender();
|
|
44
|
-
}, POLL_INTERVAL_MS);
|
|
45
|
-
|
|
46
|
-
// Also re-render on process events (status changes, etc.).
|
|
47
|
-
this.unsubscribe = this.manager.onEvent(() => {
|
|
48
|
-
this.invalidate();
|
|
49
|
-
this.tui.requestRender();
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
handleInput(_data: string): boolean {
|
|
54
|
-
// Widget doesn't handle input — the editor is still active.
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
invalidate(): void {
|
|
59
|
-
this.cachedWidth = 0;
|
|
60
|
-
this.cachedLines = [];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
render(width: number): string[] {
|
|
64
|
-
if (width === this.cachedWidth && this.cachedLines.length > 0) {
|
|
65
|
-
return this.cachedLines;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const theme = this.theme;
|
|
69
|
-
const dim = (s: string) => theme.fg("dim", s);
|
|
70
|
-
const warning = (s: string) => theme.fg("warning", s);
|
|
71
|
-
const innerWidth = width - 2;
|
|
72
|
-
|
|
73
|
-
const basePadLine = createPanelPadder(width);
|
|
74
|
-
const padLine = (content: string): string => {
|
|
75
|
-
const contentWidth = visibleWidth(content);
|
|
76
|
-
return basePadLine(
|
|
77
|
-
contentWidth > innerWidth
|
|
78
|
-
? truncateToWidth(content, innerWidth)
|
|
79
|
-
: content,
|
|
80
|
-
);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const lines: string[] = [];
|
|
84
|
-
const proc = this.manager.get(this.processId);
|
|
85
|
-
|
|
86
|
-
if (!proc) {
|
|
87
|
-
lines.push(renderPanelRule(width, theme));
|
|
88
|
-
lines.push(padLine(warning("Process not found")));
|
|
89
|
-
lines.push(renderPanelRule(width, theme));
|
|
90
|
-
this.cachedLines = lines;
|
|
91
|
-
this.cachedWidth = width;
|
|
92
|
-
return this.cachedLines;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Header
|
|
96
|
-
const icon = statusIcon(proc.status, proc.success);
|
|
97
|
-
const label = statusLabel(proc);
|
|
98
|
-
lines.push(
|
|
99
|
-
renderPanelTitleLine(
|
|
100
|
-
`Process: ${proc.name} (${proc.id}) ${icon} ${label}`,
|
|
101
|
-
width,
|
|
102
|
-
theme,
|
|
103
|
-
),
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
// Log lines (interleaved stdout + stderr in temporal order).
|
|
107
|
-
const logLines = this.manager.getCombinedOutput(
|
|
108
|
-
this.processId,
|
|
109
|
-
MAX_LOG_LINES,
|
|
110
|
-
);
|
|
111
|
-
if (logLines && logLines.length > 0) {
|
|
112
|
-
for (const line of logLines) {
|
|
113
|
-
const cleaned = stripAnsi(line.text);
|
|
114
|
-
const display = truncateToWidth(cleaned, innerWidth - 2);
|
|
115
|
-
if (line.type === "stderr") {
|
|
116
|
-
lines.push(padLine(warning(display)));
|
|
117
|
-
} else {
|
|
118
|
-
lines.push(padLine(display));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
lines.push(padLine(dim("(no output yet)")));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Pad to MAX_LOG_LINES for stable height.
|
|
126
|
-
const renderedLogLines = lines.length - 1; // minus header
|
|
127
|
-
for (let i = renderedLogLines; i < MAX_LOG_LINES; i++) {
|
|
128
|
-
lines.push(padLine(""));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Footer hint
|
|
132
|
-
lines.push(renderPanelRule(width, theme));
|
|
133
|
-
lines.push(padLine(dim("Run /process:stream to dismiss")));
|
|
134
|
-
lines.push(renderPanelRule(width, theme));
|
|
135
|
-
|
|
136
|
-
this.cachedLines = lines;
|
|
137
|
-
this.cachedWidth = width;
|
|
138
|
-
return this.cachedLines;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
dispose(): void {
|
|
142
|
-
if (this.timer) {
|
|
143
|
-
clearInterval(this.timer);
|
|
144
|
-
this.timer = null;
|
|
145
|
-
}
|
|
146
|
-
this.unsubscribe?.();
|
|
147
|
-
this.unsubscribe = null;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createPanelPadder,
|
|
3
|
-
renderPanelRule,
|
|
4
|
-
renderPanelTitleLine,
|
|
5
|
-
} from "@aliou/pi-utils-ui";
|
|
6
|
-
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
7
|
-
import { type Component, matchesKey } from "@mariozechner/pi-tui";
|
|
8
|
-
import type { ProcessInfo } from "../constants";
|
|
9
|
-
import type { ProcessManager } from "../manager";
|
|
10
|
-
import { statusIcon, statusLabel } from "./status-format";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A simple process picker component. Shows a list of processes and lets the
|
|
14
|
-
* user select one with up/down + Enter, or dismiss with Escape/q.
|
|
15
|
-
*/
|
|
16
|
-
export class ProcessPickerComponent implements Component {
|
|
17
|
-
private tui: { requestRender: () => void };
|
|
18
|
-
private theme: Theme;
|
|
19
|
-
private onClose: (processId?: string) => void;
|
|
20
|
-
private manager: ProcessManager;
|
|
21
|
-
private title: string;
|
|
22
|
-
private filter: (proc: ProcessInfo) => boolean;
|
|
23
|
-
|
|
24
|
-
private selectedIndex = 0;
|
|
25
|
-
private cachedLines: string[] = [];
|
|
26
|
-
private cachedWidth = 0;
|
|
27
|
-
private unsubscribe: (() => void) | null = null;
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
tui: { requestRender: () => void },
|
|
31
|
-
theme: Theme,
|
|
32
|
-
onClose: (processId?: string) => void,
|
|
33
|
-
manager: ProcessManager,
|
|
34
|
-
title: string,
|
|
35
|
-
filter?: (proc: ProcessInfo) => boolean,
|
|
36
|
-
) {
|
|
37
|
-
this.tui = tui;
|
|
38
|
-
this.theme = theme;
|
|
39
|
-
this.onClose = onClose;
|
|
40
|
-
this.manager = manager;
|
|
41
|
-
this.title = title;
|
|
42
|
-
this.filter = filter ?? (() => true);
|
|
43
|
-
|
|
44
|
-
this.unsubscribe = this.manager.onEvent(() => {
|
|
45
|
-
this.invalidate();
|
|
46
|
-
this.tui.requestRender();
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private getProcesses(): ProcessInfo[] {
|
|
51
|
-
return this.manager.list().filter(this.filter);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
handleInput(data: string): boolean {
|
|
55
|
-
const processes = this.getProcesses();
|
|
56
|
-
|
|
57
|
-
if (matchesKey(data, "down") || data === "j") {
|
|
58
|
-
if (processes.length > 0) {
|
|
59
|
-
this.selectedIndex = Math.min(
|
|
60
|
-
this.selectedIndex + 1,
|
|
61
|
-
processes.length - 1,
|
|
62
|
-
);
|
|
63
|
-
this.invalidate();
|
|
64
|
-
this.tui.requestRender();
|
|
65
|
-
}
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (matchesKey(data, "up") || data === "k") {
|
|
70
|
-
if (processes.length > 0) {
|
|
71
|
-
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
|
|
72
|
-
this.invalidate();
|
|
73
|
-
this.tui.requestRender();
|
|
74
|
-
}
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (matchesKey(data, "return")) {
|
|
79
|
-
if (processes.length > 0 && this.selectedIndex < processes.length) {
|
|
80
|
-
const proc = processes[this.selectedIndex];
|
|
81
|
-
if (proc) {
|
|
82
|
-
this.unsubscribe?.();
|
|
83
|
-
this.unsubscribe = null;
|
|
84
|
-
this.onClose(proc.id);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (matchesKey(data, "escape") || data === "q" || data === "Q") {
|
|
91
|
-
this.unsubscribe?.();
|
|
92
|
-
this.unsubscribe = null;
|
|
93
|
-
this.onClose();
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
invalidate(): void {
|
|
101
|
-
this.cachedWidth = 0;
|
|
102
|
-
this.cachedLines = [];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
render(width: number): string[] {
|
|
106
|
-
if (width === this.cachedWidth && this.cachedLines.length > 0) {
|
|
107
|
-
return this.cachedLines;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const theme = this.theme;
|
|
111
|
-
const dim = (s: string) => theme.fg("dim", s);
|
|
112
|
-
const accent = (s: string) => theme.fg("accent", s);
|
|
113
|
-
|
|
114
|
-
const padLine = createPanelPadder(width);
|
|
115
|
-
|
|
116
|
-
const lines: string[] = [];
|
|
117
|
-
const processes = this.getProcesses();
|
|
118
|
-
|
|
119
|
-
lines.push(renderPanelTitleLine(this.title, width, theme));
|
|
120
|
-
|
|
121
|
-
if (processes.length === 0) {
|
|
122
|
-
lines.push(padLine(""));
|
|
123
|
-
lines.push(padLine(dim("No processes available")));
|
|
124
|
-
lines.push(padLine(""));
|
|
125
|
-
} else {
|
|
126
|
-
lines.push(padLine(""));
|
|
127
|
-
for (let i = 0; i < processes.length; i++) {
|
|
128
|
-
const proc = processes[i];
|
|
129
|
-
if (!proc) continue;
|
|
130
|
-
const isSelected = i === this.selectedIndex;
|
|
131
|
-
const icon = statusIcon(proc.status, proc.success);
|
|
132
|
-
const label = statusLabel(proc);
|
|
133
|
-
const prefix = isSelected ? accent("> ") : " ";
|
|
134
|
-
const name = isSelected ? accent(proc.name) : proc.name;
|
|
135
|
-
const id = dim(`(${proc.id})`);
|
|
136
|
-
const status = dim(`${icon} ${label}`);
|
|
137
|
-
lines.push(padLine(`${prefix}${name} ${id} ${status}`));
|
|
138
|
-
}
|
|
139
|
-
lines.push(padLine(""));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Footer
|
|
143
|
-
lines.push(renderPanelRule(width, theme));
|
|
144
|
-
lines.push(
|
|
145
|
-
padLine(
|
|
146
|
-
`${dim("j/k")} select ${dim("enter")} confirm ${dim("q")} cancel`,
|
|
147
|
-
),
|
|
148
|
-
);
|
|
149
|
-
lines.push(renderPanelRule(width, theme));
|
|
150
|
-
|
|
151
|
-
this.cachedLines = lines;
|
|
152
|
-
this.cachedWidth = width;
|
|
153
|
-
return this.cachedLines;
|
|
154
|
-
}
|
|
155
|
-
}
|