@aliou/pi-processes 0.4.5 → 0.4.6
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/package.json +1 -1
- package/src/commands/index.ts +334 -0
- package/src/commands/settings-command.ts +157 -0
- package/src/components/log-stream-component.ts +149 -0
- package/src/components/process-picker-component.ts +155 -0
- package/src/components/processes-component.ts +450 -0
- package/src/components/status-format.ts +38 -0
- package/src/config.ts +70 -0
- package/src/constants/index.ts +11 -0
- package/src/constants/types.ts +65 -0
- package/src/hooks/cleanup.ts +10 -0
- package/src/hooks/index.ts +18 -0
- package/src/hooks/message-renderer.ts +83 -0
- package/src/hooks/process-end.ts +92 -0
- package/src/hooks/widget.ts +146 -0
- package/src/index.ts +22 -20
- package/src/manager.ts +522 -0
- package/src/test/test-exit-crash.sh +19 -0
- package/src/test/test-exit-failure.sh +17 -0
- package/src/test/test-exit-success.sh +16 -0
- package/src/test/test-output.sh +28 -0
- package/src/tools/actions/clear.ts +20 -0
- package/src/tools/actions/index.ts +49 -0
- package/src/tools/actions/kill.ts +76 -0
- package/src/tools/actions/list.ts +37 -0
- package/src/tools/actions/logs.ts +59 -0
- package/src/tools/actions/output.ts +144 -0
- package/src/tools/actions/start.ts +55 -0
- package/src/tools/index.ts +280 -0
- package/src/utils/ansi.ts +36 -0
- package/src/utils/command-executor.test.ts +47 -0
- package/src/utils/command-executor.ts +56 -0
- package/src/utils/format.ts +42 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/process-group.ts +22 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Custom message type for process update notifications
|
|
2
|
+
export const MESSAGE_TYPE_PROCESS_UPDATE = "ad-process:update";
|
|
3
|
+
|
|
4
|
+
export type ProcessStatus =
|
|
5
|
+
| "running"
|
|
6
|
+
| "terminating"
|
|
7
|
+
| "terminate_timeout"
|
|
8
|
+
| "exited"
|
|
9
|
+
| "killed";
|
|
10
|
+
|
|
11
|
+
export const LIVE_STATUSES: ReadonlySet<ProcessStatus> = new Set([
|
|
12
|
+
"running",
|
|
13
|
+
"terminating",
|
|
14
|
+
"terminate_timeout",
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export interface ProcessInfo {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
pid: number; // On Unix, this is also the PGID (process group leader)
|
|
21
|
+
command: string;
|
|
22
|
+
cwd: string;
|
|
23
|
+
startTime: number;
|
|
24
|
+
endTime: number | null;
|
|
25
|
+
status: ProcessStatus;
|
|
26
|
+
exitCode: number | null;
|
|
27
|
+
success: boolean | null; // null if running, true if exit code 0, false otherwise
|
|
28
|
+
stdoutFile: string;
|
|
29
|
+
stderrFile: string;
|
|
30
|
+
alertOnSuccess: boolean;
|
|
31
|
+
alertOnFailure: boolean;
|
|
32
|
+
alertOnKill: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type ManagerEvent =
|
|
36
|
+
| { type: "process_started"; info: ProcessInfo }
|
|
37
|
+
| { type: "process_status_changed"; info: ProcessInfo; prev: ProcessStatus }
|
|
38
|
+
| { type: "process_ended"; info: ProcessInfo }
|
|
39
|
+
| { type: "processes_changed" };
|
|
40
|
+
|
|
41
|
+
export type KillResult =
|
|
42
|
+
| { ok: true; info: ProcessInfo }
|
|
43
|
+
| { ok: false; info: ProcessInfo; reason: "not_found" | "timeout" | "error" };
|
|
44
|
+
|
|
45
|
+
export interface StartOptions {
|
|
46
|
+
alertOnSuccess?: boolean;
|
|
47
|
+
alertOnFailure?: boolean;
|
|
48
|
+
alertOnKill?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ProcessesDetails {
|
|
52
|
+
action: string;
|
|
53
|
+
success: boolean;
|
|
54
|
+
message: string;
|
|
55
|
+
process?: ProcessInfo;
|
|
56
|
+
processes?: ProcessInfo[];
|
|
57
|
+
output?: { stdout: string[]; stderr: string[]; status: string };
|
|
58
|
+
logFiles?: { stdoutFile: string; stderrFile: string };
|
|
59
|
+
cleared?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ExecuteResult {
|
|
63
|
+
content: Array<{ type: "text"; text: string }>;
|
|
64
|
+
details: ProcessesDetails;
|
|
65
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { ProcessManager } from "../manager";
|
|
3
|
+
|
|
4
|
+
export function setupCleanupHook(pi: ExtensionAPI, manager: ProcessManager) {
|
|
5
|
+
pi.on("session_shutdown", () => {
|
|
6
|
+
manager.stopWatcher();
|
|
7
|
+
manager.shutdownKillAll();
|
|
8
|
+
manager.cleanup();
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { ProcessManager } from "../manager";
|
|
3
|
+
import { setupCleanupHook } from "./cleanup";
|
|
4
|
+
import { setupMessageRenderer } from "./message-renderer";
|
|
5
|
+
import { setupProcessEndHook } from "./process-end";
|
|
6
|
+
import { setupProcessWidget } from "./widget";
|
|
7
|
+
|
|
8
|
+
export function setupProcessesHooks(pi: ExtensionAPI, manager: ProcessManager) {
|
|
9
|
+
setupCleanupHook(pi, manager);
|
|
10
|
+
setupProcessEndHook(pi, manager);
|
|
11
|
+
|
|
12
|
+
// Set up widget AFTER process-end so it chains onto the existing callback
|
|
13
|
+
const widget = setupProcessWidget(pi, manager);
|
|
14
|
+
|
|
15
|
+
setupMessageRenderer(pi);
|
|
16
|
+
|
|
17
|
+
return widget;
|
|
18
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
MessageRenderOptions,
|
|
4
|
+
Theme,
|
|
5
|
+
} from "@mariozechner/pi-coding-agent";
|
|
6
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
7
|
+
import { MESSAGE_TYPE_PROCESS_UPDATE } from "../constants";
|
|
8
|
+
|
|
9
|
+
interface ProcessUpdateDetails {
|
|
10
|
+
processId: string;
|
|
11
|
+
processName: string;
|
|
12
|
+
command: string;
|
|
13
|
+
status: "exited" | "killed";
|
|
14
|
+
exitCode: number | null;
|
|
15
|
+
success: boolean;
|
|
16
|
+
runtime: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ProcessUpdateMessage {
|
|
20
|
+
customType: string;
|
|
21
|
+
content: string | Array<{ type: string; text?: string }>;
|
|
22
|
+
details?: ProcessUpdateDetails;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getContentText(
|
|
26
|
+
content: string | Array<{ type: string; text?: string }>,
|
|
27
|
+
): string {
|
|
28
|
+
if (typeof content === "string") {
|
|
29
|
+
return content;
|
|
30
|
+
}
|
|
31
|
+
return content
|
|
32
|
+
.filter((c) => c.type === "text" && c.text)
|
|
33
|
+
.map((c) => c.text as string)
|
|
34
|
+
.join("");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function setupMessageRenderer(pi: ExtensionAPI) {
|
|
38
|
+
pi.registerMessageRenderer<ProcessUpdateDetails>(
|
|
39
|
+
MESSAGE_TYPE_PROCESS_UPDATE,
|
|
40
|
+
(
|
|
41
|
+
message: ProcessUpdateMessage,
|
|
42
|
+
_options: MessageRenderOptions,
|
|
43
|
+
theme: Theme,
|
|
44
|
+
) => {
|
|
45
|
+
const details = message.details;
|
|
46
|
+
|
|
47
|
+
if (!details) {
|
|
48
|
+
return new Text(getContentText(message.content), 0, 0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let icon: string;
|
|
52
|
+
let color: "success" | "error" | "warning";
|
|
53
|
+
|
|
54
|
+
if (details.status === "killed") {
|
|
55
|
+
icon = "\u2717"; // x mark
|
|
56
|
+
color = "warning";
|
|
57
|
+
} else if (details.success) {
|
|
58
|
+
icon = "\u2713"; // check mark
|
|
59
|
+
color = "success";
|
|
60
|
+
} else {
|
|
61
|
+
icon = "\u2717"; // x mark
|
|
62
|
+
color = "error";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const statusText =
|
|
66
|
+
details.status === "killed"
|
|
67
|
+
? "terminated"
|
|
68
|
+
: details.success
|
|
69
|
+
? "completed"
|
|
70
|
+
: `exited(${details.exitCode ?? "?"})`;
|
|
71
|
+
|
|
72
|
+
const text =
|
|
73
|
+
theme.fg(color, `${icon} `) +
|
|
74
|
+
theme.fg("accent", `"${details.processName}"`) +
|
|
75
|
+
theme.fg("muted", ` (${details.processId})`) +
|
|
76
|
+
" " +
|
|
77
|
+
theme.fg(color, statusText) +
|
|
78
|
+
theme.fg("muted", ` ${details.runtime}`);
|
|
79
|
+
|
|
80
|
+
return new Text(text, 0, 0);
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { MESSAGE_TYPE_PROCESS_UPDATE, type ProcessInfo } from "../constants";
|
|
6
|
+
import type { ProcessManager } from "../manager";
|
|
7
|
+
import { formatRuntime } from "../utils";
|
|
8
|
+
|
|
9
|
+
interface ProcessUpdateDetails {
|
|
10
|
+
processId: string;
|
|
11
|
+
processName: string;
|
|
12
|
+
command: string;
|
|
13
|
+
status: "exited" | "killed";
|
|
14
|
+
exitCode: number | null;
|
|
15
|
+
success: boolean;
|
|
16
|
+
runtime: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function setupProcessEndHook(pi: ExtensionAPI, manager: ProcessManager) {
|
|
20
|
+
let latestContext: ExtensionContext | null = null;
|
|
21
|
+
|
|
22
|
+
// Capture context from session events
|
|
23
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
24
|
+
latestContext = ctx;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
pi.on("turn_start", async (_event, ctx) => {
|
|
28
|
+
latestContext = ctx;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
32
|
+
latestContext = ctx;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
manager.onEvent((event) => {
|
|
36
|
+
if (event.type !== "process_ended") return;
|
|
37
|
+
|
|
38
|
+
const info: ProcessInfo = event.info;
|
|
39
|
+
|
|
40
|
+
// Determine if the agent should get a turn to react to this process ending.
|
|
41
|
+
// When true, the agent receives the message in its context and can respond
|
|
42
|
+
// (e.g. check results, fix code, restart the process).
|
|
43
|
+
const triggerAgentTurn =
|
|
44
|
+
(info.status === "killed" && info.alertOnKill) ||
|
|
45
|
+
(info.status === "exited" && info.success && info.alertOnSuccess) ||
|
|
46
|
+
(info.status === "exited" && !info.success && info.alertOnFailure);
|
|
47
|
+
|
|
48
|
+
const runtime = formatRuntime(info.startTime, info.endTime);
|
|
49
|
+
|
|
50
|
+
// Build notification message
|
|
51
|
+
let message: string;
|
|
52
|
+
let level: "info" | "error" | "warning";
|
|
53
|
+
|
|
54
|
+
if (info.status === "killed") {
|
|
55
|
+
message = `Process '${info.name}' was terminated (${runtime})`;
|
|
56
|
+
level = "warning";
|
|
57
|
+
} else if (info.success) {
|
|
58
|
+
message = `Process '${info.name}' completed successfully (${runtime})`;
|
|
59
|
+
level = "info";
|
|
60
|
+
} else {
|
|
61
|
+
message = `Process '${info.name}' crashed with exit code ${info.exitCode ?? "?"} (${runtime})`;
|
|
62
|
+
level = "error";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Always notify user via UI
|
|
66
|
+
if (latestContext?.hasUI) {
|
|
67
|
+
latestContext.ui.notify(message, level);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Always send the message so it appears in the conversation history.
|
|
71
|
+
// Only trigger an agent turn when the notification preferences say so.
|
|
72
|
+
const details: ProcessUpdateDetails = {
|
|
73
|
+
processId: info.id,
|
|
74
|
+
processName: info.name,
|
|
75
|
+
command: info.command,
|
|
76
|
+
status: info.status as "exited" | "killed",
|
|
77
|
+
exitCode: info.exitCode,
|
|
78
|
+
success: info.success ?? false,
|
|
79
|
+
runtime,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
pi.sendMessage(
|
|
83
|
+
{
|
|
84
|
+
customType: MESSAGE_TYPE_PROCESS_UPDATE,
|
|
85
|
+
content: message,
|
|
86
|
+
display: true,
|
|
87
|
+
details,
|
|
88
|
+
},
|
|
89
|
+
{ triggerTurn: triggerAgentTurn },
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { visibleWidth } from "@mariozechner/pi-tui";
|
|
6
|
+
import { configLoader } from "../config";
|
|
7
|
+
import type { ProcessInfo } from "../constants";
|
|
8
|
+
import type { ProcessManager } from "../manager";
|
|
9
|
+
|
|
10
|
+
const WIDGET_ID = "processes-status";
|
|
11
|
+
|
|
12
|
+
function formatProcessStatus(
|
|
13
|
+
proc: ProcessInfo,
|
|
14
|
+
theme: ExtensionContext["ui"]["theme"],
|
|
15
|
+
): string {
|
|
16
|
+
const name =
|
|
17
|
+
proc.name.length > 20 ? `${proc.name.slice(0, 17)}...` : proc.name;
|
|
18
|
+
|
|
19
|
+
switch (proc.status) {
|
|
20
|
+
case "running":
|
|
21
|
+
return `${theme.fg("accent", name)} ${theme.fg("dim", "running")}`;
|
|
22
|
+
case "terminating":
|
|
23
|
+
return `${theme.fg("warning", name)} ${theme.fg("dim", "terminating")}`;
|
|
24
|
+
case "terminate_timeout":
|
|
25
|
+
return `${theme.fg("error", name)} ${theme.fg("error", "terminate_timeout")}`;
|
|
26
|
+
case "killed":
|
|
27
|
+
return `${theme.fg("warning", name)} ${theme.fg("dim", "killed")}`;
|
|
28
|
+
case "exited":
|
|
29
|
+
if (proc.success) {
|
|
30
|
+
return `${theme.fg("dim", name)} ${theme.fg("success", "done")}`;
|
|
31
|
+
}
|
|
32
|
+
return `${theme.fg("error", name)} ${theme.fg("error", `exit(${proc.exitCode ?? "?"})`)}`;
|
|
33
|
+
default:
|
|
34
|
+
return `${theme.fg("dim", name)} ${theme.fg("dim", proc.status)}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function renderWidget(
|
|
39
|
+
processes: ProcessInfo[],
|
|
40
|
+
theme: ExtensionContext["ui"]["theme"],
|
|
41
|
+
maxWidth?: number,
|
|
42
|
+
): string[] {
|
|
43
|
+
if (processes.length === 0) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const aliveish = processes.filter(
|
|
48
|
+
(p) =>
|
|
49
|
+
p.status === "running" ||
|
|
50
|
+
p.status === "terminating" ||
|
|
51
|
+
p.status === "terminate_timeout",
|
|
52
|
+
);
|
|
53
|
+
const finished = processes.filter(
|
|
54
|
+
(p) =>
|
|
55
|
+
p.status !== "running" &&
|
|
56
|
+
p.status !== "terminating" &&
|
|
57
|
+
p.status !== "terminate_timeout",
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const allProcs: ProcessInfo[] = [
|
|
61
|
+
...aliveish,
|
|
62
|
+
...finished.sort((a, b) => (b.endTime ?? 0) - (a.endTime ?? 0)),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const prefix = theme.fg("dim", "processes: ");
|
|
66
|
+
const prefixLen = visibleWidth(prefix);
|
|
67
|
+
const separator = theme.fg("dim", " | ");
|
|
68
|
+
const separatorLen = visibleWidth(separator);
|
|
69
|
+
const effectiveMax = maxWidth ?? 200;
|
|
70
|
+
|
|
71
|
+
const parts: string[] = [];
|
|
72
|
+
let currentLen = prefixLen;
|
|
73
|
+
let includedCount = 0;
|
|
74
|
+
|
|
75
|
+
for (const proc of allProcs) {
|
|
76
|
+
const formatted = formatProcessStatus(proc, theme);
|
|
77
|
+
const formattedLen = visibleWidth(formatted);
|
|
78
|
+
|
|
79
|
+
// Check if adding this part would exceed the width
|
|
80
|
+
const needed =
|
|
81
|
+
includedCount > 0 ? separatorLen + formattedLen : formattedLen;
|
|
82
|
+
|
|
83
|
+
if (currentLen + needed > effectiveMax && includedCount > 0) {
|
|
84
|
+
// Show how many are hidden
|
|
85
|
+
const remaining = allProcs.length - includedCount;
|
|
86
|
+
if (remaining > 0) {
|
|
87
|
+
parts.push(theme.fg("dim", `+${remaining} more`));
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
parts.push(formatted);
|
|
93
|
+
currentLen += needed;
|
|
94
|
+
includedCount++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (parts.length === 0) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return [prefix + parts.join(separator)];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function setupProcessWidget(pi: ExtensionAPI, manager: ProcessManager) {
|
|
105
|
+
let latestContext: ExtensionContext | null = null;
|
|
106
|
+
|
|
107
|
+
function updateWidget() {
|
|
108
|
+
if (!latestContext?.hasUI) return;
|
|
109
|
+
|
|
110
|
+
if (!configLoader.getConfig().widget.showStatusWidget) {
|
|
111
|
+
latestContext.ui.setWidget(WIDGET_ID, undefined);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const processes = manager.list();
|
|
116
|
+
const maxWidth = process.stdout.columns || 120;
|
|
117
|
+
const lines = renderWidget(processes, latestContext.ui.theme, maxWidth);
|
|
118
|
+
|
|
119
|
+
if (lines.length === 0) {
|
|
120
|
+
latestContext.ui.setWidget(WIDGET_ID, undefined);
|
|
121
|
+
} else {
|
|
122
|
+
latestContext.ui.setWidget(WIDGET_ID, lines, {
|
|
123
|
+
placement: "belowEditor",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
129
|
+
// Startup defer: capture context only. First render happens on process
|
|
130
|
+
// manager events or explicit settings updates.
|
|
131
|
+
latestContext = ctx;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
pi.on("session_switch", async (_event, ctx) => {
|
|
135
|
+
latestContext = ctx;
|
|
136
|
+
updateWidget();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
manager.onEvent(() => {
|
|
140
|
+
updateWidget();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
update: updateWidget,
|
|
145
|
+
};
|
|
146
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { setupProcessesCommands } from "./commands";
|
|
3
|
+
import { registerProcessesSettings } from "./commands/settings-command";
|
|
4
|
+
import { configLoader } from "./config";
|
|
5
|
+
import { setupProcessesHooks } from "./hooks";
|
|
6
|
+
import { ProcessManager } from "./manager";
|
|
7
|
+
import { setupProcessesTools } from "./tools";
|
|
8
8
|
|
|
9
9
|
export default async function (pi: ExtensionAPI) {
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
if (process.platform === "win32") {
|
|
11
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
12
|
+
if (!ctx.hasUI) return;
|
|
13
|
+
ctx.ui.notify("processes extension not available on Windows", "warning");
|
|
14
|
+
});
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"then remove it from the pi-extensions package config.",
|
|
20
|
-
"warning",
|
|
21
|
-
);
|
|
22
|
-
}
|
|
18
|
+
await configLoader.load();
|
|
19
|
+
const manager = new ProcessManager({
|
|
20
|
+
getConfiguredShellPath: () => configLoader.getConfig().execution.shellPath,
|
|
21
|
+
});
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const { update: updateWidget } = setupProcessesHooks(pi, manager);
|
|
24
|
+
setupProcessesCommands(pi, manager);
|
|
25
|
+
setupProcessesTools(pi, manager);
|
|
26
|
+
registerProcessesSettings(pi, () => {
|
|
27
|
+
updateWidget();
|
|
26
28
|
});
|
|
27
29
|
}
|