@ericsanchezok/meta-synergy 0.0.0-dev-202603260728
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/.turbo/turbo-typecheck.log +1 -0
- package/dist/meta-protocol/src/bash.d.ts +89 -0
- package/dist/meta-protocol/src/bash.js +40 -0
- package/dist/meta-protocol/src/client.d.ts +9 -0
- package/dist/meta-protocol/src/client.js +1 -0
- package/dist/meta-protocol/src/env.d.ts +16 -0
- package/dist/meta-protocol/src/env.js +17 -0
- package/dist/meta-protocol/src/envelope.d.ts +50 -0
- package/dist/meta-protocol/src/envelope.js +23 -0
- package/dist/meta-protocol/src/error.d.ts +39 -0
- package/dist/meta-protocol/src/error.js +24 -0
- package/dist/meta-protocol/src/host.d.ts +90 -0
- package/dist/meta-protocol/src/host.js +27 -0
- package/dist/meta-protocol/src/index.d.ts +7 -0
- package/dist/meta-protocol/src/index.js +7 -0
- package/dist/meta-protocol/src/process.d.ts +274 -0
- package/dist/meta-protocol/src/process.js +89 -0
- package/dist/meta-synergy/src/client/holos-client.d.ts +15 -0
- package/dist/meta-synergy/src/client/holos-client.js +35 -0
- package/dist/meta-synergy/src/exec/bash-runner.d.ts +7 -0
- package/dist/meta-synergy/src/exec/bash-runner.js +9 -0
- package/dist/meta-synergy/src/exec/process-registry.d.ts +11 -0
- package/dist/meta-synergy/src/exec/process-registry.js +597 -0
- package/dist/meta-synergy/src/host.d.ts +32 -0
- package/dist/meta-synergy/src/host.js +27 -0
- package/dist/meta-synergy/src/index.d.ts +8 -0
- package/dist/meta-synergy/src/index.js +8 -0
- package/dist/meta-synergy/src/platform.d.ts +25 -0
- package/dist/meta-synergy/src/platform.js +230 -0
- package/dist/meta-synergy/src/rpc/handler.d.ts +66 -0
- package/dist/meta-synergy/src/rpc/handler.js +60 -0
- package/dist/meta-synergy/src/rpc/schema.d.ts +163 -0
- package/dist/meta-synergy/src/rpc/schema.js +11 -0
- package/dist/meta-synergy/src/types.d.ts +14 -0
- package/dist/meta-synergy/src/types.js +1 -0
- package/package.json +30 -0
- package/script/publish.ts +32 -0
- package/src/client/holos-client.ts +49 -0
- package/src/exec/bash-runner.ts +10 -0
- package/src/exec/process-registry.ts +728 -0
- package/src/host.ts +39 -0
- package/src/index.ts +8 -0
- package/src/platform.ts +227 -0
- package/src/rpc/handler.ts +76 -0
- package/src/rpc/schema.ts +16 -0
- package/src/types.ts +17 -0
- package/test/rpc-handler.test.ts +76 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MetaProtocolHost } from "@ericsanchezok/meta-protocol";
|
|
2
|
+
export type ProcessEnv = Record<string, string | undefined>;
|
|
3
|
+
export type ChildLike = {
|
|
4
|
+
pid?: number;
|
|
5
|
+
kill(signal?: number | NodeJS.Signals): boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare namespace Platform {
|
|
8
|
+
function runtime(): MetaProtocolHost.Runtime;
|
|
9
|
+
function defaultShell(): MetaProtocolHost.Shell;
|
|
10
|
+
function supportedShells(): MetaProtocolHost.Shell[];
|
|
11
|
+
function detectCapabilities(): MetaProtocolHost.Capabilities;
|
|
12
|
+
function normalizeEnv(env: ProcessEnv): ProcessEnv;
|
|
13
|
+
function resolveShellLaunch(command: string): {
|
|
14
|
+
shell: MetaProtocolHost.Shell;
|
|
15
|
+
file: string;
|
|
16
|
+
args: string[];
|
|
17
|
+
};
|
|
18
|
+
function killTree(child: ChildLike, exited?: () => boolean): Promise<void>;
|
|
19
|
+
function encodeKeySequence(keys: string[]): {
|
|
20
|
+
data: string;
|
|
21
|
+
warnings: string[];
|
|
22
|
+
};
|
|
23
|
+
function resolveWorkdir(workdir?: string): string;
|
|
24
|
+
function sleep(ms: number): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
const SIGKILL_TIMEOUT_MS = 200;
|
|
6
|
+
const ESC = "\u001b";
|
|
7
|
+
export var Platform;
|
|
8
|
+
(function (Platform) {
|
|
9
|
+
function runtime() {
|
|
10
|
+
if (typeof process.versions?.bun === "string")
|
|
11
|
+
return "bun";
|
|
12
|
+
if (typeof process.versions?.node === "string")
|
|
13
|
+
return "node";
|
|
14
|
+
return "unknown";
|
|
15
|
+
}
|
|
16
|
+
Platform.runtime = runtime;
|
|
17
|
+
function defaultShell() {
|
|
18
|
+
if (process.platform === "win32") {
|
|
19
|
+
const comspec = (process.env.ComSpec || process.env.COMSPEC || "").toLowerCase();
|
|
20
|
+
if (comspec.includes("pwsh"))
|
|
21
|
+
return "pwsh";
|
|
22
|
+
if (comspec.includes("powershell"))
|
|
23
|
+
return "powershell";
|
|
24
|
+
return "cmd";
|
|
25
|
+
}
|
|
26
|
+
return "sh";
|
|
27
|
+
}
|
|
28
|
+
Platform.defaultShell = defaultShell;
|
|
29
|
+
function supportedShells() {
|
|
30
|
+
return process.platform === "win32" ? ["cmd", "powershell", "pwsh"] : ["sh"];
|
|
31
|
+
}
|
|
32
|
+
Platform.supportedShells = supportedShells;
|
|
33
|
+
function detectCapabilities() {
|
|
34
|
+
return {
|
|
35
|
+
platform: process.platform,
|
|
36
|
+
arch: process.arch,
|
|
37
|
+
hostname: safeHostname(),
|
|
38
|
+
runtime: runtime(),
|
|
39
|
+
defaultShell: defaultShell(),
|
|
40
|
+
supportedShells: supportedShells(),
|
|
41
|
+
supportsPty: false,
|
|
42
|
+
supportsSendKeys: true,
|
|
43
|
+
supportsSoftKill: process.platform !== "win32",
|
|
44
|
+
supportsProcessGroups: process.platform !== "win32",
|
|
45
|
+
envCaseInsensitive: process.platform === "win32",
|
|
46
|
+
lineEndings: process.platform === "win32" ? "crlf" : "lf",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
Platform.detectCapabilities = detectCapabilities;
|
|
50
|
+
function normalizeEnv(env) {
|
|
51
|
+
if (process.platform !== "win32") {
|
|
52
|
+
return { ...env };
|
|
53
|
+
}
|
|
54
|
+
const result = {};
|
|
55
|
+
const entries = Object.entries(env).sort(([left], [right]) => left.localeCompare(right));
|
|
56
|
+
const seen = new Set();
|
|
57
|
+
for (const [key, value] of entries) {
|
|
58
|
+
const upper = key.toUpperCase();
|
|
59
|
+
if (seen.has(upper) && key !== "Path")
|
|
60
|
+
continue;
|
|
61
|
+
seen.add(upper);
|
|
62
|
+
result[key === "PATH" ? "Path" : key] = value;
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
Platform.normalizeEnv = normalizeEnv;
|
|
67
|
+
function resolveShellLaunch(command) {
|
|
68
|
+
if (process.platform === "win32") {
|
|
69
|
+
return {
|
|
70
|
+
shell: "cmd",
|
|
71
|
+
file: process.env.ComSpec || process.env.COMSPEC || "cmd.exe",
|
|
72
|
+
args: ["/d", "/s", "/c", command],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
shell: "sh",
|
|
77
|
+
file: "/bin/sh",
|
|
78
|
+
args: ["-c", command],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
Platform.resolveShellLaunch = resolveShellLaunch;
|
|
82
|
+
async function killTree(child, exited) {
|
|
83
|
+
const pid = child.pid;
|
|
84
|
+
if (!pid || exited?.())
|
|
85
|
+
return;
|
|
86
|
+
if (process.platform === "win32") {
|
|
87
|
+
await new Promise((resolve) => {
|
|
88
|
+
const killer = spawn("taskkill", ["/pid", String(pid), "/f", "/t"], {
|
|
89
|
+
stdio: "ignore",
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
});
|
|
92
|
+
killer.once("exit", () => resolve());
|
|
93
|
+
killer.once("error", () => resolve());
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
process.kill(-pid, "SIGTERM");
|
|
99
|
+
await sleep(SIGKILL_TIMEOUT_MS);
|
|
100
|
+
if (!exited?.())
|
|
101
|
+
process.kill(-pid, "SIGKILL");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
catch { }
|
|
105
|
+
child.kill("SIGTERM");
|
|
106
|
+
await sleep(SIGKILL_TIMEOUT_MS);
|
|
107
|
+
if (!exited?.())
|
|
108
|
+
child.kill("SIGKILL");
|
|
109
|
+
}
|
|
110
|
+
Platform.killTree = killTree;
|
|
111
|
+
function encodeKeySequence(keys) {
|
|
112
|
+
const warnings = [];
|
|
113
|
+
let data = "";
|
|
114
|
+
for (const token of keys) {
|
|
115
|
+
data += encodeKeyToken(token, warnings);
|
|
116
|
+
}
|
|
117
|
+
return { data, warnings };
|
|
118
|
+
}
|
|
119
|
+
Platform.encodeKeySequence = encodeKeySequence;
|
|
120
|
+
function resolveWorkdir(workdir) {
|
|
121
|
+
if (!workdir)
|
|
122
|
+
return process.cwd();
|
|
123
|
+
if (path.isAbsolute(workdir))
|
|
124
|
+
return workdir;
|
|
125
|
+
return path.resolve(process.cwd(), workdir);
|
|
126
|
+
}
|
|
127
|
+
Platform.resolveWorkdir = resolveWorkdir;
|
|
128
|
+
function sleep(ms) {
|
|
129
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
130
|
+
}
|
|
131
|
+
Platform.sleep = sleep;
|
|
132
|
+
})(Platform || (Platform = {}));
|
|
133
|
+
function encodeKeyToken(raw, warnings) {
|
|
134
|
+
const token = raw.trim();
|
|
135
|
+
if (!token)
|
|
136
|
+
return "";
|
|
137
|
+
if (token.length === 2 && token.startsWith("^")) {
|
|
138
|
+
const ctrl = toCtrlChar(token[1]);
|
|
139
|
+
if (ctrl)
|
|
140
|
+
return ctrl;
|
|
141
|
+
}
|
|
142
|
+
const parsed = parseModifiers(token);
|
|
143
|
+
const named = namedKey(parsed.base.toLowerCase());
|
|
144
|
+
if (named) {
|
|
145
|
+
return parsed.alt ? `${ESC}${named}` : named;
|
|
146
|
+
}
|
|
147
|
+
if (parsed.base.length === 1) {
|
|
148
|
+
let value = parsed.shift && /[a-z]/.test(parsed.base) ? parsed.base.toUpperCase() : parsed.base;
|
|
149
|
+
if (parsed.ctrl)
|
|
150
|
+
value = toCtrlChar(value) || value;
|
|
151
|
+
if (parsed.alt)
|
|
152
|
+
value = `${ESC}${value}`;
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
if (parsed.hasModifiers) {
|
|
156
|
+
warnings.push(`Unknown key \"${parsed.base}\" for modifiers; sending literal.`);
|
|
157
|
+
}
|
|
158
|
+
return parsed.base;
|
|
159
|
+
}
|
|
160
|
+
function parseModifiers(token) {
|
|
161
|
+
let rest = token;
|
|
162
|
+
let ctrl = false;
|
|
163
|
+
let alt = false;
|
|
164
|
+
let shift = false;
|
|
165
|
+
let hasModifiers = false;
|
|
166
|
+
while (rest.length > 2 && rest[1] === "-") {
|
|
167
|
+
const mod = rest[0].toLowerCase();
|
|
168
|
+
if (mod === "c")
|
|
169
|
+
ctrl = true;
|
|
170
|
+
else if (mod === "m")
|
|
171
|
+
alt = true;
|
|
172
|
+
else if (mod === "s")
|
|
173
|
+
shift = true;
|
|
174
|
+
else
|
|
175
|
+
break;
|
|
176
|
+
hasModifiers = true;
|
|
177
|
+
rest = rest.slice(2);
|
|
178
|
+
}
|
|
179
|
+
return { base: rest, ctrl, alt, shift, hasModifiers };
|
|
180
|
+
}
|
|
181
|
+
function namedKey(input) {
|
|
182
|
+
const map = new Map([
|
|
183
|
+
["enter", "\r"],
|
|
184
|
+
["return", "\r"],
|
|
185
|
+
["tab", "\t"],
|
|
186
|
+
["escape", ESC],
|
|
187
|
+
["esc", ESC],
|
|
188
|
+
["space", " "],
|
|
189
|
+
["backspace", process.platform === "win32" ? "\b" : "\u007f"],
|
|
190
|
+
["up", `${ESC}[A`],
|
|
191
|
+
["down", `${ESC}[B`],
|
|
192
|
+
["right", `${ESC}[C`],
|
|
193
|
+
["left", `${ESC}[D`],
|
|
194
|
+
["home", `${ESC}[1~`],
|
|
195
|
+
["end", `${ESC}[4~`],
|
|
196
|
+
["pageup", `${ESC}[5~`],
|
|
197
|
+
["pagedown", `${ESC}[6~`],
|
|
198
|
+
["insert", `${ESC}[2~`],
|
|
199
|
+
["delete", `${ESC}[3~`],
|
|
200
|
+
["f1", `${ESC}OP`],
|
|
201
|
+
["f2", `${ESC}OQ`],
|
|
202
|
+
["f3", `${ESC}OR`],
|
|
203
|
+
["f4", `${ESC}OS`],
|
|
204
|
+
["f5", `${ESC}[15~`],
|
|
205
|
+
["f6", `${ESC}[17~`],
|
|
206
|
+
["f7", `${ESC}[18~`],
|
|
207
|
+
["f8", `${ESC}[19~`],
|
|
208
|
+
["f9", `${ESC}[20~`],
|
|
209
|
+
["f10", `${ESC}[21~`],
|
|
210
|
+
["f11", `${ESC}[23~`],
|
|
211
|
+
["f12", `${ESC}[24~`],
|
|
212
|
+
]);
|
|
213
|
+
return map.get(input);
|
|
214
|
+
}
|
|
215
|
+
function toCtrlChar(char) {
|
|
216
|
+
if (char.length !== 1)
|
|
217
|
+
return null;
|
|
218
|
+
if (char === "?")
|
|
219
|
+
return "\u007f";
|
|
220
|
+
const code = char.toUpperCase().charCodeAt(0);
|
|
221
|
+
return code >= 64 && code <= 95 ? String.fromCharCode(code & 0x1f) : null;
|
|
222
|
+
}
|
|
223
|
+
function safeHostname() {
|
|
224
|
+
try {
|
|
225
|
+
return os.hostname();
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ProcessRegistry } from "../exec/process-registry";
|
|
2
|
+
import { MetaSynergyHost, type MetaSynergyHostOptions } from "../host";
|
|
3
|
+
import { BashRunner } from "../exec/bash-runner";
|
|
4
|
+
export declare class RPCHandler {
|
|
5
|
+
readonly host: MetaSynergyHost;
|
|
6
|
+
readonly processRegistry: ProcessRegistry;
|
|
7
|
+
readonly bashRunner: BashRunner;
|
|
8
|
+
constructor(options?: MetaSynergyHostOptions);
|
|
9
|
+
handle(input: unknown): Promise<{
|
|
10
|
+
version: 1;
|
|
11
|
+
requestID: string;
|
|
12
|
+
ok: false;
|
|
13
|
+
error: {
|
|
14
|
+
code: "env_not_found" | "env_inactive" | "device_offline" | "request_timeout" | "request_cancelled" | "remote_execution_error" | "invalid_request" | "unsupported_tool" | "unsupported_action" | "unsupported_capability" | "host_internal_error" | "stale_process_handle" | "stdin_unavailable";
|
|
15
|
+
message: string;
|
|
16
|
+
details?: unknown;
|
|
17
|
+
};
|
|
18
|
+
} | {
|
|
19
|
+
readonly version: 1;
|
|
20
|
+
readonly requestID: string;
|
|
21
|
+
readonly ok: true;
|
|
22
|
+
readonly result: {
|
|
23
|
+
title: string;
|
|
24
|
+
metadata: {
|
|
25
|
+
output?: string | undefined;
|
|
26
|
+
description?: string | undefined;
|
|
27
|
+
exit?: number | null | undefined;
|
|
28
|
+
processId?: string | undefined;
|
|
29
|
+
background?: boolean | undefined;
|
|
30
|
+
timedOut?: boolean | undefined;
|
|
31
|
+
durationMs?: number | undefined;
|
|
32
|
+
hostSessionID?: string | undefined;
|
|
33
|
+
envID?: string | undefined;
|
|
34
|
+
backend?: "local" | "remote" | undefined;
|
|
35
|
+
};
|
|
36
|
+
output: string;
|
|
37
|
+
};
|
|
38
|
+
} | {
|
|
39
|
+
readonly version: 1;
|
|
40
|
+
readonly requestID: string;
|
|
41
|
+
readonly ok: true;
|
|
42
|
+
readonly result: {
|
|
43
|
+
title: string;
|
|
44
|
+
metadata: {
|
|
45
|
+
action: "list" | "poll" | "log" | "write" | "send-keys" | "kill" | "clear" | "remove";
|
|
46
|
+
processId?: string | undefined;
|
|
47
|
+
status?: "error" | "running" | "completed" | "failed" | "killed" | "not_found" | "cleared" | "removed" | undefined;
|
|
48
|
+
exitCode?: number | undefined;
|
|
49
|
+
command?: string | undefined;
|
|
50
|
+
description?: string | undefined;
|
|
51
|
+
nextOffset?: number | undefined;
|
|
52
|
+
hostSessionID?: string | undefined;
|
|
53
|
+
envID?: string | undefined;
|
|
54
|
+
backend?: "local" | "remote" | undefined;
|
|
55
|
+
processes?: {
|
|
56
|
+
processId: string;
|
|
57
|
+
status: "running" | "completed" | "failed" | "killed";
|
|
58
|
+
command: string;
|
|
59
|
+
runtimeMs: number;
|
|
60
|
+
description?: string | undefined;
|
|
61
|
+
}[] | undefined;
|
|
62
|
+
};
|
|
63
|
+
output: string;
|
|
64
|
+
};
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ProcessRegistry } from "../exec/process-registry";
|
|
2
|
+
import { MetaSynergyHost } from "../host";
|
|
3
|
+
import { BashRunner } from "../exec/bash-runner";
|
|
4
|
+
import { RPCRequestSchema } from "./schema";
|
|
5
|
+
export class RPCHandler {
|
|
6
|
+
host;
|
|
7
|
+
processRegistry;
|
|
8
|
+
bashRunner;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.host = new MetaSynergyHost(options);
|
|
11
|
+
this.processRegistry = new ProcessRegistry(this.host);
|
|
12
|
+
this.bashRunner = new BashRunner(this.processRegistry);
|
|
13
|
+
}
|
|
14
|
+
async handle(input) {
|
|
15
|
+
try {
|
|
16
|
+
const request = RPCRequestSchema.parse(input);
|
|
17
|
+
this.host.assertEnv(request.envID);
|
|
18
|
+
if (request.tool === "bash") {
|
|
19
|
+
const result = await this.bashRunner.run(request.payload, request.envID);
|
|
20
|
+
return {
|
|
21
|
+
version: 1,
|
|
22
|
+
requestID: request.requestID,
|
|
23
|
+
ok: true,
|
|
24
|
+
result,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (request.tool === "process") {
|
|
28
|
+
const result = await this.processRegistry.execute(request.payload, request.envID);
|
|
29
|
+
return {
|
|
30
|
+
version: 1,
|
|
31
|
+
requestID: request.requestID,
|
|
32
|
+
ok: true,
|
|
33
|
+
result,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return errorResult(undefined, "unsupported_tool", "Unsupported tool");
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (isEnvelopeError(error)) {
|
|
40
|
+
return errorResult(error.requestID, error.code, error.message, error.details);
|
|
41
|
+
}
|
|
42
|
+
return errorResult(undefined, "host_internal_error", error instanceof Error ? error.message : String(error));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function errorResult(requestID, code, message, details) {
|
|
47
|
+
return {
|
|
48
|
+
version: 1,
|
|
49
|
+
requestID: requestID || crypto.randomUUID(),
|
|
50
|
+
ok: false,
|
|
51
|
+
error: {
|
|
52
|
+
code,
|
|
53
|
+
message,
|
|
54
|
+
details,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function isEnvelopeError(error) {
|
|
59
|
+
return typeof error === "object" && error !== null && "code" in error && "message" in error;
|
|
60
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export declare const RPCRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
3
|
+
version: z.ZodLiteral<1>;
|
|
4
|
+
requestID: z.ZodString;
|
|
5
|
+
envID: z.ZodString;
|
|
6
|
+
tool: z.ZodLiteral<"bash">;
|
|
7
|
+
action: z.ZodLiteral<"execute">;
|
|
8
|
+
payload: z.ZodObject<{
|
|
9
|
+
command: z.ZodString;
|
|
10
|
+
description: z.ZodString;
|
|
11
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
workdir: z.ZodOptional<z.ZodString>;
|
|
13
|
+
background: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
yieldMs: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
17
|
+
version: z.ZodLiteral<1>;
|
|
18
|
+
requestID: z.ZodString;
|
|
19
|
+
envID: z.ZodString;
|
|
20
|
+
tool: z.ZodLiteral<"process">;
|
|
21
|
+
action: z.ZodEnum<{
|
|
22
|
+
list: "list";
|
|
23
|
+
poll: "poll";
|
|
24
|
+
log: "log";
|
|
25
|
+
write: "write";
|
|
26
|
+
"send-keys": "send-keys";
|
|
27
|
+
kill: "kill";
|
|
28
|
+
clear: "clear";
|
|
29
|
+
remove: "remove";
|
|
30
|
+
}>;
|
|
31
|
+
payload: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
32
|
+
action: z.ZodLiteral<"list">;
|
|
33
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
34
|
+
action: z.ZodLiteral<"poll">;
|
|
35
|
+
processId: z.ZodString;
|
|
36
|
+
block: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
39
|
+
action: z.ZodLiteral<"log">;
|
|
40
|
+
processId: z.ZodString;
|
|
41
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
44
|
+
action: z.ZodLiteral<"write">;
|
|
45
|
+
processId: z.ZodString;
|
|
46
|
+
data: z.ZodString;
|
|
47
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
48
|
+
action: z.ZodLiteral<"send-keys">;
|
|
49
|
+
processId: z.ZodString;
|
|
50
|
+
keys: z.ZodArray<z.ZodString>;
|
|
51
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
52
|
+
action: z.ZodLiteral<"kill">;
|
|
53
|
+
processId: z.ZodString;
|
|
54
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
55
|
+
action: z.ZodLiteral<"clear">;
|
|
56
|
+
processId: z.ZodString;
|
|
57
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
58
|
+
action: z.ZodLiteral<"remove">;
|
|
59
|
+
processId: z.ZodString;
|
|
60
|
+
}, z.core.$strip>], "action">;
|
|
61
|
+
}, z.core.$strip>], "tool">;
|
|
62
|
+
export declare const RPCResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
63
|
+
version: z.ZodLiteral<1>;
|
|
64
|
+
requestID: z.ZodString;
|
|
65
|
+
ok: z.ZodLiteral<true>;
|
|
66
|
+
result: z.ZodObject<{
|
|
67
|
+
title: z.ZodString;
|
|
68
|
+
metadata: z.ZodObject<{
|
|
69
|
+
output: z.ZodOptional<z.ZodString>;
|
|
70
|
+
description: z.ZodOptional<z.ZodString>;
|
|
71
|
+
exit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
72
|
+
processId: z.ZodOptional<z.ZodString>;
|
|
73
|
+
background: z.ZodOptional<z.ZodBoolean>;
|
|
74
|
+
timedOut: z.ZodOptional<z.ZodBoolean>;
|
|
75
|
+
durationMs: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
hostSessionID: z.ZodOptional<z.ZodString>;
|
|
77
|
+
envID: z.ZodOptional<z.ZodString>;
|
|
78
|
+
backend: z.ZodOptional<z.ZodEnum<{
|
|
79
|
+
local: "local";
|
|
80
|
+
remote: "remote";
|
|
81
|
+
}>>;
|
|
82
|
+
}, z.core.$strip>;
|
|
83
|
+
output: z.ZodString;
|
|
84
|
+
}, z.core.$strip>;
|
|
85
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
86
|
+
version: z.ZodLiteral<1>;
|
|
87
|
+
requestID: z.ZodString;
|
|
88
|
+
ok: z.ZodLiteral<true>;
|
|
89
|
+
result: z.ZodObject<{
|
|
90
|
+
title: z.ZodString;
|
|
91
|
+
metadata: z.ZodObject<{
|
|
92
|
+
action: z.ZodEnum<{
|
|
93
|
+
list: "list";
|
|
94
|
+
poll: "poll";
|
|
95
|
+
log: "log";
|
|
96
|
+
write: "write";
|
|
97
|
+
"send-keys": "send-keys";
|
|
98
|
+
kill: "kill";
|
|
99
|
+
clear: "clear";
|
|
100
|
+
remove: "remove";
|
|
101
|
+
}>;
|
|
102
|
+
processId: z.ZodOptional<z.ZodString>;
|
|
103
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
104
|
+
error: "error";
|
|
105
|
+
running: "running";
|
|
106
|
+
completed: "completed";
|
|
107
|
+
failed: "failed";
|
|
108
|
+
killed: "killed";
|
|
109
|
+
not_found: "not_found";
|
|
110
|
+
cleared: "cleared";
|
|
111
|
+
removed: "removed";
|
|
112
|
+
}>>;
|
|
113
|
+
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
114
|
+
command: z.ZodOptional<z.ZodString>;
|
|
115
|
+
description: z.ZodOptional<z.ZodString>;
|
|
116
|
+
nextOffset: z.ZodOptional<z.ZodNumber>;
|
|
117
|
+
hostSessionID: z.ZodOptional<z.ZodString>;
|
|
118
|
+
envID: z.ZodOptional<z.ZodString>;
|
|
119
|
+
backend: z.ZodOptional<z.ZodEnum<{
|
|
120
|
+
local: "local";
|
|
121
|
+
remote: "remote";
|
|
122
|
+
}>>;
|
|
123
|
+
processes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
124
|
+
processId: z.ZodString;
|
|
125
|
+
status: z.ZodEnum<{
|
|
126
|
+
running: "running";
|
|
127
|
+
completed: "completed";
|
|
128
|
+
failed: "failed";
|
|
129
|
+
killed: "killed";
|
|
130
|
+
}>;
|
|
131
|
+
command: z.ZodString;
|
|
132
|
+
description: z.ZodOptional<z.ZodString>;
|
|
133
|
+
runtimeMs: z.ZodNumber;
|
|
134
|
+
}, z.core.$strip>>>;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
output: z.ZodString;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
139
|
+
version: z.ZodLiteral<1>;
|
|
140
|
+
requestID: z.ZodString;
|
|
141
|
+
ok: z.ZodLiteral<false>;
|
|
142
|
+
error: z.ZodObject<{
|
|
143
|
+
code: z.ZodEnum<{
|
|
144
|
+
env_not_found: "env_not_found";
|
|
145
|
+
env_inactive: "env_inactive";
|
|
146
|
+
device_offline: "device_offline";
|
|
147
|
+
request_timeout: "request_timeout";
|
|
148
|
+
request_cancelled: "request_cancelled";
|
|
149
|
+
remote_execution_error: "remote_execution_error";
|
|
150
|
+
invalid_request: "invalid_request";
|
|
151
|
+
unsupported_tool: "unsupported_tool";
|
|
152
|
+
unsupported_action: "unsupported_action";
|
|
153
|
+
unsupported_capability: "unsupported_capability";
|
|
154
|
+
host_internal_error: "host_internal_error";
|
|
155
|
+
stale_process_handle: "stale_process_handle";
|
|
156
|
+
stdin_unavailable: "stdin_unavailable";
|
|
157
|
+
}>;
|
|
158
|
+
message: z.ZodString;
|
|
159
|
+
details: z.ZodOptional<z.ZodUnknown>;
|
|
160
|
+
}, z.core.$strip>;
|
|
161
|
+
}, z.core.$strip>], "ok">;
|
|
162
|
+
export type RPCRequest = z.infer<typeof RPCRequestSchema>;
|
|
163
|
+
export type RPCResult = z.infer<typeof RPCResultSchema>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { MetaProtocolBash, MetaProtocolEnvelope, MetaProtocolProcess } from "@ericsanchezok/meta-protocol";
|
|
3
|
+
export const RPCRequestSchema = z.discriminatedUnion("tool", [
|
|
4
|
+
MetaProtocolBash.ExecuteRequest,
|
|
5
|
+
MetaProtocolProcess.ExecuteRequest,
|
|
6
|
+
]);
|
|
7
|
+
export const RPCResultSchema = z.discriminatedUnion("ok", [
|
|
8
|
+
MetaProtocolBash.ExecuteResult,
|
|
9
|
+
MetaProtocolProcess.ExecuteResult,
|
|
10
|
+
MetaProtocolEnvelope.ErrorResult,
|
|
11
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MetaProtocolEnv, MetaProtocolHost } from "@ericsanchezok/meta-protocol";
|
|
2
|
+
export type EnvID = MetaProtocolEnv.EnvID;
|
|
3
|
+
export type RequestID = string;
|
|
4
|
+
export interface RemoteHostIdentity {
|
|
5
|
+
envID: EnvID;
|
|
6
|
+
hostSessionID: MetaProtocolEnv.HostSessionID;
|
|
7
|
+
capabilities: MetaProtocolHost.Capabilities;
|
|
8
|
+
label?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface HostTransport {
|
|
11
|
+
connect(): Promise<void>;
|
|
12
|
+
disconnect(): Promise<void>;
|
|
13
|
+
send(message: unknown): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@ericsanchezok/meta-synergy",
|
|
4
|
+
"version": "0.0.0-dev-202603260728",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./*": {
|
|
13
|
+
"import": "./dist/*.js",
|
|
14
|
+
"types": "./dist/*.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"build": "tsc -p tsconfig.json"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@ericsanchezok/meta-protocol": "0.0.0-dev-202603260728",
|
|
23
|
+
"zod": "4.1.8"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@tsconfig/node22": "22.0.2",
|
|
27
|
+
"@types/node": "22.13.9",
|
|
28
|
+
"typescript": "5.8.2"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Script } from "@ericsanchezok/synergy-script"
|
|
3
|
+
import { $ } from "bun"
|
|
4
|
+
|
|
5
|
+
const dir = new URL("..", import.meta.url).pathname
|
|
6
|
+
process.chdir(dir)
|
|
7
|
+
|
|
8
|
+
await $`bun tsc`
|
|
9
|
+
const pkg = await import("../package.json").then((m) => m.default)
|
|
10
|
+
const original = JSON.parse(JSON.stringify(pkg))
|
|
11
|
+
for (const [key, value] of Object.entries(pkg.exports)) {
|
|
12
|
+
const source = typeof value === "string" ? value : (value as { import?: string }).import
|
|
13
|
+
if (!source || typeof source !== "string") continue
|
|
14
|
+
const file = source.replace("./src/", "./dist/").replace(".ts", "").replace(".js", "")
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
pkg.exports[key] = {
|
|
17
|
+
import: file + ".js",
|
|
18
|
+
types: file + ".d.ts",
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
await Bun.write("package.json", JSON.stringify(pkg, null, 2))
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const NPM_REGISTRY = "https://registry.npmjs.org"
|
|
25
|
+
await $`rm -f *.tgz`.nothrow()
|
|
26
|
+
await $`bun pm pack`
|
|
27
|
+
const tgz = (await $`ls *.tgz`.text()).trim()
|
|
28
|
+
const authFlag = process.env.NPM_TOKEN ? `--//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}` : ""
|
|
29
|
+
await $`npm publish ${tgz} --tag ${Script.channel} --registry ${NPM_REGISTRY} --access public ${authFlag}`
|
|
30
|
+
} finally {
|
|
31
|
+
await Bun.write("package.json", JSON.stringify(original, null, 2))
|
|
32
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MetaSynergyHost, type MetaSynergyHostOptions } from "../host"
|
|
2
|
+
import type { HostTransport, RemoteHostIdentity } from "../types"
|
|
3
|
+
|
|
4
|
+
export interface HolosClientOptions extends MetaSynergyHostOptions {
|
|
5
|
+
transport?: HostTransport
|
|
6
|
+
label?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class HolosClient {
|
|
10
|
+
readonly host: MetaSynergyHost
|
|
11
|
+
readonly transport?: HostTransport
|
|
12
|
+
readonly label?: string
|
|
13
|
+
|
|
14
|
+
constructor(options: HolosClientOptions = {}) {
|
|
15
|
+
this.host = new MetaSynergyHost(options)
|
|
16
|
+
this.transport = options.transport
|
|
17
|
+
this.label = options.label
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
identity(): RemoteHostIdentity {
|
|
21
|
+
if (!this.host.envID) {
|
|
22
|
+
throw new Error("HolosClient requires envID to build identity")
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
envID: this.host.envID,
|
|
27
|
+
hostSessionID: this.host.hostSessionID,
|
|
28
|
+
capabilities: this.host.capabilities,
|
|
29
|
+
label: this.label,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async connect(): Promise<void> {
|
|
34
|
+
if (!this.transport) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
await this.transport.connect()
|
|
39
|
+
await this.transport.send(this.host.hello())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async disconnect(): Promise<void> {
|
|
43
|
+
if (!this.transport) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.transport.disconnect()
|
|
48
|
+
}
|
|
49
|
+
}
|