@omercnet/paseo-omp 0.4.0 → 1.0.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/README.md +8 -8
- package/client/external-url.ts +2 -11
- package/client/omp-config-styles.ts +284 -0
- package/client/omp-config-surface.tsx +16 -286
- package/client/omp-routing-editor.tsx +1 -3
- package/client/provider-launch-settings.tsx +118 -0
- package/index.client.tsx +21 -2
- package/index.server.ts +10 -0
- package/package.json +14 -9
- package/paseo-plugin.json +2 -1
- package/scripts/prepare-dependencies.mjs +44 -11
- package/server/omp-models.ts +2 -6
- package/server/package-version.ts +1 -1
- package/server/protocol-violation-diagnostics.ts +1 -1
- package/server/provider/catalog.ts +2 -1
- package/server/provider/config-normalization.ts +19 -3
- package/server/provider/connection.ts +30 -0
- package/server/provider/host-tools.ts +2 -2
- package/server/provider/mcp-transport.ts +9 -2
- package/server/provider/omp-rpc-environment.ts +368 -0
- package/server/provider/omp-rpc-process.ts +119 -0
- package/server/provider/omp-rpc-protocol.ts +1949 -0
- package/server/provider/omp-rpc-transport.ts +1373 -0
- package/server/provider/omp-rpc-values.ts +31 -0
- package/server/provider/omp-rpc.ts +267 -3311
- package/server/provider/profile-providers.ts +2 -1
- package/server/provider/prompt-payload.ts +253 -0
- package/server/provider/registration.ts +10 -2
- package/server/provider/session-compaction.ts +187 -0
- package/server/provider/session-descriptors.ts +52 -18
- package/server/provider/session-events.ts +42 -0
- package/server/provider/session-permissions.ts +987 -0
- package/server/provider/session-terminal.ts +307 -0
- package/server/provider/session-usage.ts +234 -0
- package/server/provider/session.ts +145 -1853
- package/server/provider/settings.ts +8 -5
- package/server/provider/subsessions.ts +30 -9
- package/server/provider/timeline-projector.ts +140 -29
- package/shared/external-url.ts +0 -9
- package/shared/provider-launch-settings.ts +18 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
type TimerHandle = number | NodeJS.Timeout;
|
|
5
|
+
|
|
6
|
+
export const PROCESS_STOP_TIMEOUT_MS = 750;
|
|
7
|
+
const WINDOWS_DEFAULT_SYSTEM_ROOT = "C:\\Windows";
|
|
8
|
+
|
|
9
|
+
export function waitMs(ms: number): Promise<void> {
|
|
10
|
+
const result = Promise.withResolvers<void>();
|
|
11
|
+
setTimeout(result.resolve, ms);
|
|
12
|
+
return result.promise;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function processIsGone(error: unknown): boolean {
|
|
16
|
+
return (error as NodeJS.ErrnoException)?.code === "ESRCH";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isConfirmedNoProcessSpawnFailure(error: unknown): boolean {
|
|
20
|
+
const code = (error as NodeJS.ErrnoException)?.code;
|
|
21
|
+
return code === "ENOENT" || code === "EACCES" || code === "EPERM";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Terminates the detached process group created for OMP. This covers descendants that remain in
|
|
26
|
+
* that group after the leader exits; descendants that deliberately re-parent into another process
|
|
27
|
+
* group are outside this transport's containment boundary.
|
|
28
|
+
*/
|
|
29
|
+
export async function terminatePosixProcessTree(
|
|
30
|
+
pid: number,
|
|
31
|
+
graceMs: number,
|
|
32
|
+
signalProcess: (pid: number, signal: NodeJS.Signals | 0) => void = process.kill,
|
|
33
|
+
wait: (ms: number) => Promise<void> = waitMs,
|
|
34
|
+
): Promise<boolean> {
|
|
35
|
+
try {
|
|
36
|
+
signalProcess(-pid, 0);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return processIsGone(error);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
signalProcess(-pid, "SIGTERM");
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (!processIsGone(error)) return false;
|
|
44
|
+
}
|
|
45
|
+
await wait(graceMs);
|
|
46
|
+
try {
|
|
47
|
+
signalProcess(-pid, 0);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return processIsGone(error);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
signalProcess(-pid, "SIGKILL");
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (!processIsGone(error)) return false;
|
|
55
|
+
}
|
|
56
|
+
await wait(graceMs);
|
|
57
|
+
try {
|
|
58
|
+
signalProcess(-pid, 0);
|
|
59
|
+
return false;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return processIsGone(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type ProcessTreeCleanup = "verified" | "uncertain" | "failed";
|
|
66
|
+
|
|
67
|
+
export async function stopWindowsTree(pid: number): Promise<ProcessTreeCleanup> {
|
|
68
|
+
const result = Promise.withResolvers<ProcessTreeCleanup>();
|
|
69
|
+
const systemRoot = process.env.SystemRoot ?? WINDOWS_DEFAULT_SYSTEM_ROOT;
|
|
70
|
+
let taskkill: ChildProcessWithoutNullStreams;
|
|
71
|
+
try {
|
|
72
|
+
taskkill = spawn(
|
|
73
|
+
join(systemRoot, "System32", "taskkill.exe"),
|
|
74
|
+
["/PID", String(pid), "/T", "/F"],
|
|
75
|
+
{
|
|
76
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
77
|
+
windowsHide: true,
|
|
78
|
+
env: { SystemRoot: systemRoot },
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
} catch {
|
|
82
|
+
return "failed";
|
|
83
|
+
}
|
|
84
|
+
taskkill.stdout.resume();
|
|
85
|
+
taskkill.stderr.resume();
|
|
86
|
+
let settled = false;
|
|
87
|
+
let deadline: TimerHandle | undefined;
|
|
88
|
+
let finalDeadline: TimerHandle | undefined;
|
|
89
|
+
const finish = (outcome: ProcessTreeCleanup) => {
|
|
90
|
+
if (settled) return;
|
|
91
|
+
settled = true;
|
|
92
|
+
clearTimeout(deadline);
|
|
93
|
+
clearTimeout(finalDeadline);
|
|
94
|
+
result.resolve(outcome);
|
|
95
|
+
};
|
|
96
|
+
deadline = setTimeout(() => {
|
|
97
|
+
taskkill.kill("SIGKILL");
|
|
98
|
+
finalDeadline = setTimeout(() => finish("failed"), PROCESS_STOP_TIMEOUT_MS);
|
|
99
|
+
}, PROCESS_STOP_TIMEOUT_MS);
|
|
100
|
+
taskkill.once("error", () => finish("failed"));
|
|
101
|
+
taskkill.once("close", (code, signal) => {
|
|
102
|
+
finish(
|
|
103
|
+
code === 0 && signal === null
|
|
104
|
+
? "verified"
|
|
105
|
+
: code === 128 && signal === null
|
|
106
|
+
? "uncertain"
|
|
107
|
+
: "failed",
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
return result.promise;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function terminateSpawnedProcessTree(
|
|
114
|
+
pid: number,
|
|
115
|
+
platform: NodeJS.Platform = process.platform,
|
|
116
|
+
): Promise<boolean> {
|
|
117
|
+
if (platform === "win32") return (await stopWindowsTree(pid)) === "verified";
|
|
118
|
+
return await terminatePosixProcessTree(pid, PROCESS_STOP_TIMEOUT_MS);
|
|
119
|
+
}
|