@calltelemetry/ct-lab-mcp 0.8.38 → 0.8.40

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.
@@ -0,0 +1,36 @@
1
+ import type { CanonicalCommandResult } from "../canonical/types.js";
2
+ /** Trusted composition input, never an MCP argument or an alternate catalog. */
3
+ export interface CanonicalHostReader {
4
+ readonly isConfigured: boolean;
5
+ run(args: string[], timeoutMsOverride?: number): Promise<CanonicalCommandResult>;
6
+ }
7
+ export type HostResolutionCode = "HOST_ASSET_ID_INVALID" | "HOST_INVENTORY_UNAVAILABLE" | "HOST_INVENTORY_FAILED" | "HOST_INVENTORY_INVALID" | "HOST_ASSET_UNKNOWN" | "HOST_ASSET_INELIGIBLE" | "HOST_BINDING_MISSING" | "HOST_BINDING_INVALID" | "HOST_IDENTITY_MISMATCH";
8
+ export declare class HostResolutionError extends Error {
9
+ readonly code: HostResolutionCode;
10
+ constructor(code: HostResolutionCode);
11
+ }
12
+ /** Internal selection evidence, NOT a live identity check or permission grant. */
13
+ export interface ResolvedHostBinding {
14
+ readonly scope: "inventory_binding_not_live_identity_or_authorization";
15
+ readonly assetId: string;
16
+ readonly machineId: string;
17
+ readonly tailnetHostname: string;
18
+ readonly remoteUser: string;
19
+ readonly sshHostKeySha256: string;
20
+ readonly capabilityClass: "lab-admin" | "worker";
21
+ /** Digest reported by the canonical reader; not independently attested here. */
22
+ readonly inventorySha256: string;
23
+ }
24
+ /**
25
+ * Inert resolver behind the existing canonical bridge. No SSH, secret lookup,
26
+ * fallback IP/alias, MCP registration, caching, or automatic host enrollment.
27
+ * Only reviewed canonical relationships.host_transport metadata may select a
28
+ * destination. The subsequent transport must independently verify live host
29
+ * identity and enforce caller/action authorization.
30
+ */
31
+ export declare class InventoryHostResolver {
32
+ private readonly canonical;
33
+ constructor(canonical: CanonicalHostReader);
34
+ resolve(assetId: unknown): Promise<Readonly<ResolvedHostBinding>>;
35
+ }
36
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/host/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAClF;AAED,MAAM,MAAM,kBAAkB,GAC1B,uBAAuB,GACvB,4BAA4B,GAC5B,uBAAuB,GACvB,wBAAwB,GACxB,oBAAoB,GACpB,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,wBAAwB,CAAC;AAE7B,qBAAa,mBAAoB,SAAQ,KAAK;IAChC,QAAQ,CAAC,IAAI,EAAE,kBAAkB;gBAAxB,IAAI,EAAE,kBAAkB;CAK9C;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,sDAAsD,CAAC;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,WAAW,GAAG,QAAQ,CAAC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AA+DD;;;;;;GAMG;AACH,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,mBAAmB;IAErD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;CAsDxE"}
@@ -0,0 +1,137 @@
1
+ export class HostResolutionError extends Error {
2
+ code;
3
+ constructor(code) {
4
+ // Never attach caller input, canonical stdout/stderr, or the original cause.
5
+ super(code);
6
+ this.code = code;
7
+ this.name = "HostResolutionError";
8
+ }
9
+ }
10
+ const MAX_INVENTORY_BYTES = 4 * 1024 * 1024;
11
+ const MAX_ASSETS = 10_000;
12
+ const READ_TIMEOUT_MS = 10_000;
13
+ const ASSET_ID = /^[a-z][a-z0-9_-]{0,127}$/;
14
+ const CATALOG_ID = /^[a-z0-9][a-z0-9._-]{0,255}$/;
15
+ const MACHINE_ID = /^(?!0{32}$)[a-f0-9]{32}$/;
16
+ const SHA256 = /^[a-f0-9]{64}$/;
17
+ const DNS_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
18
+ const TAILNET = /^tail[a-z0-9]{1,59}\.ts\.net$/;
19
+ const REMOTE_USER = /^[a-z_][a-z0-9_-]{0,31}$/;
20
+ const BINDING_KEYS = [
21
+ "schema", "status", "asset_id", "machine_id", "tailnet", "hostname",
22
+ "remote_user", "ssh_host_key_sha256", "capability_class",
23
+ ];
24
+ const VM_KEYS = ["host_asset_id", "vmid", "proxmox_vmid", "smbios_uuid", "instance_uuid", "esxi_vm_path"];
25
+ function record(value) {
26
+ return value !== null && typeof value === "object" && !Array.isArray(value);
27
+ }
28
+ function requireThat(ok, code) {
29
+ if (!ok)
30
+ throw new HostResolutionError(code);
31
+ }
32
+ function matches(value, pattern) {
33
+ return typeof value === "string" && !/[\r\n\u2028\u2029]/.test(value) && pattern.test(value);
34
+ }
35
+ function exactKeys(value, keys) {
36
+ return Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key));
37
+ }
38
+ function fingerprint(value) {
39
+ if (typeof value !== "string" || !/^SHA256:[A-Za-z0-9+/]{43}$/.test(value))
40
+ return false;
41
+ const bytes = Buffer.from(value.slice(7), "base64");
42
+ return bytes.length === 32 && bytes.toString("base64").replace(/=+$/, "") === value.slice(7);
43
+ }
44
+ function inventory(stdout) {
45
+ requireThat(typeof stdout === "string" && Buffer.byteLength(stdout, "utf8") <= MAX_INVENTORY_BYTES, "HOST_INVENTORY_INVALID");
46
+ let payload;
47
+ try {
48
+ payload = JSON.parse(stdout);
49
+ }
50
+ catch {
51
+ throw new HostResolutionError("HOST_INVENTORY_INVALID");
52
+ }
53
+ // This is the existing canonical `all --full` envelope, not `show` (which
54
+ // selects the first match and cannot establish the absence of duplicate IDs).
55
+ requireThat(record(payload) && exactKeys(payload, ["inventory_path", "inventory_sha256", "asset_count", "assets"]), "HOST_INVENTORY_INVALID");
56
+ requireThat(typeof payload.inventory_path === "string" && payload.inventory_path.length > 0
57
+ && matches(payload.inventory_sha256, SHA256), "HOST_INVENTORY_INVALID");
58
+ requireThat(Array.isArray(payload.assets) && payload.assets.length <= MAX_ASSETS
59
+ && Number.isInteger(payload.asset_count) && payload.asset_count === payload.assets.length, "HOST_INVENTORY_INVALID");
60
+ const ids = new Set();
61
+ const assets = [];
62
+ for (const asset of payload.assets) {
63
+ requireThat(record(asset) && matches(asset.id, CATALOG_ID) && !ids.has(asset.id), "HOST_INVENTORY_INVALID");
64
+ ids.add(asset.id);
65
+ assets.push(asset);
66
+ }
67
+ return { assets, digest: payload.inventory_sha256 };
68
+ }
69
+ /**
70
+ * Inert resolver behind the existing canonical bridge. No SSH, secret lookup,
71
+ * fallback IP/alias, MCP registration, caching, or automatic host enrollment.
72
+ * Only reviewed canonical relationships.host_transport metadata may select a
73
+ * destination. The subsequent transport must independently verify live host
74
+ * identity and enforce caller/action authorization.
75
+ */
76
+ export class InventoryHostResolver {
77
+ canonical;
78
+ constructor(canonical) {
79
+ this.canonical = canonical;
80
+ }
81
+ async resolve(assetId) {
82
+ // Do not normalize identifiers: case folding or trimming changes authority.
83
+ requireThat(matches(assetId, ASSET_ID), "HOST_ASSET_ID_INVALID");
84
+ requireThat(this.canonical.isConfigured === true, "HOST_INVENTORY_UNAVAILABLE");
85
+ let result;
86
+ try {
87
+ result = await this.canonical.run(["all", "--full"], READ_TIMEOUT_MS);
88
+ }
89
+ catch {
90
+ throw new HostResolutionError("HOST_INVENTORY_UNAVAILABLE");
91
+ }
92
+ requireThat(record(result) && result.exitCode === 0 && result.signalCode === undefined
93
+ && (result.timedOut === undefined || result.timedOut === false), "HOST_INVENTORY_FAILED");
94
+ const { assets, digest } = inventory(result.stdout);
95
+ const asset = assets.find(candidate => candidate.id === assetId);
96
+ requireThat(asset, "HOST_ASSET_UNKNOWN");
97
+ // First slice admits only persistent Linux physical hosts. Protected
98
+ // fixtures, hypervisors and guests remain with their existing authorities.
99
+ requireThat(asset.type === "physical-host" && asset.platform === "linux"
100
+ && asset.lifecycle === "persistent" && !Object.hasOwn(asset, "host"), "HOST_ASSET_INELIGIBLE");
101
+ requireThat(record(asset.relationships), "HOST_BINDING_MISSING");
102
+ const relationships = asset.relationships;
103
+ requireThat(!VM_KEYS.some(key => Object.hasOwn(relationships, key)), "HOST_ASSET_INELIGIBLE");
104
+ requireThat(Object.hasOwn(relationships, "host_transport"), "HOST_BINDING_MISSING");
105
+ const binding = relationships.host_transport;
106
+ requireThat(record(binding) && exactKeys(binding, BINDING_KEYS)
107
+ && binding.schema === "ct-lab-host-transport/v1" && binding.status === "approved", "HOST_BINDING_INVALID");
108
+ requireThat(matches(relationships.machine_id, MACHINE_ID) && matches(binding.machine_id, MACHINE_ID)
109
+ && binding.asset_id === assetId && binding.machine_id === relationships.machine_id, "HOST_IDENTITY_MISMATCH");
110
+ requireThat(matches(binding.tailnet, TAILNET) && typeof binding.hostname === "string", "HOST_BINDING_INVALID");
111
+ const suffix = `.${binding.tailnet}`;
112
+ requireThat(binding.hostname.endsWith(suffix)
113
+ && matches(binding.hostname.slice(0, -suffix.length), DNS_LABEL)
114
+ && matches(binding.remote_user, REMOTE_USER) && fingerprint(binding.ssh_host_key_sha256)
115
+ && (binding.capability_class === "lab-admin" || binding.capability_class === "worker"), "HOST_BINDING_INVALID");
116
+ // Two durable IDs must not silently authorize the same machine/destination.
117
+ requireThat(!assets.some(other => {
118
+ if (other === asset || !record(other.relationships))
119
+ return false;
120
+ const otherBinding = other.relationships.host_transport;
121
+ return other.relationships.machine_id === binding.machine_id
122
+ || (record(otherBinding) && (otherBinding.machine_id === binding.machine_id
123
+ || otherBinding.hostname === binding.hostname));
124
+ }), "HOST_IDENTITY_MISMATCH");
125
+ return Object.freeze({
126
+ scope: "inventory_binding_not_live_identity_or_authorization",
127
+ assetId,
128
+ machineId: binding.machine_id,
129
+ tailnetHostname: binding.hostname,
130
+ remoteUser: binding.remote_user,
131
+ sshHostKeySha256: binding.ssh_host_key_sha256,
132
+ capabilityClass: binding.capability_class,
133
+ inventorySha256: digest,
134
+ });
135
+ }
136
+ }
137
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/host/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type ChildProcessWithoutNullStreams } from "node:child_process";
2
+ import type { ResolvedHostBinding } from "./resolver.js";
3
+ export type HostReadOperation = {
4
+ readonly kind: "host_status";
5
+ } | {
6
+ readonly kind: "service_status";
7
+ readonly service: "bifrost" | "tailscaled" | "ct-agent";
8
+ } | {
9
+ readonly kind: "tailnet_status";
10
+ };
11
+ export type HostTransportCode = "HOST_OPERATION_INVALID" | "HOST_ENROLLMENT_MISSING" | "HOST_HOSTKEY_INVALID" | "HOST_PROCESS_FAILED" | "HOST_TIMEOUT" | "HOST_OUTPUT_INVALID" | "HOST_IDENTITY_MISMATCH";
12
+ export declare class HostTransportError extends Error {
13
+ readonly code: HostTransportCode;
14
+ constructor(code: HostTransportCode);
15
+ }
16
+ export interface HostKeyEnrollmentReader {
17
+ getPublicHostKey(assetId: string): Promise<string | undefined>;
18
+ }
19
+ export interface HostSpawn {
20
+ (file: string, args: readonly string[], options: {
21
+ stdio: ["ignore", "pipe", "pipe"];
22
+ detached: boolean;
23
+ env: NodeJS.ProcessEnv;
24
+ }): ChildProcessWithoutNullStreams;
25
+ }
26
+ export interface HostReadResult {
27
+ readonly scope: "read_only_host_status";
28
+ readonly assetId: string;
29
+ readonly operation: HostReadOperation["kind"];
30
+ readonly machineId: string;
31
+ readonly status: "ok" | "degraded" | "unknown";
32
+ readonly detail: string;
33
+ }
34
+ export declare class BoundedHostTransport {
35
+ private readonly enrollment;
36
+ private readonly spawnProcess;
37
+ private readonly sshExecutable;
38
+ private readonly timeoutMs;
39
+ constructor(enrollment: HostKeyEnrollmentReader, spawnProcess?: HostSpawn, sshExecutable?: string, timeoutMs?: number);
40
+ read(binding: Readonly<ResolvedHostBinding>, input: unknown): Promise<Readonly<HostReadResult>>;
41
+ }
42
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/host/transport.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,KAAK,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,YAAY,GAAG,UAAU,CAAA;CAAE,GAC5F;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AACxC,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,GAAC,yBAAyB,GAAC,sBAAsB,GAAC,qBAAqB,GAAC,cAAc,GAAC,qBAAqB,GAAC,wBAAwB,CAAC;AAC9L,qBAAa,kBAAmB,SAAQ,KAAK;IAAe,QAAQ,CAAC,IAAI,EAAE,iBAAiB;gBAAvB,IAAI,EAAE,iBAAiB;CAAoD;AAChJ,MAAM,WAAW,uBAAuB;IAAG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAC,SAAS,CAAC,CAAC;CAAE;AAC1G,MAAM,WAAW,SAAS;IAAG,CAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,SAAS,MAAM,EAAE,EAAC,OAAO,EAAC;QAAC,KAAK,EAAC,CAAC,QAAQ,EAAC,MAAM,EAAC,MAAM,CAAC,CAAC;QAAA,QAAQ,EAAC,OAAO,CAAC;QAAA,GAAG,EAAC,MAAM,CAAC,UAAU,CAAA;KAAC,GAAE,8BAA8B,CAAC;CAAE;AACnL,MAAM,WAAW,cAAc;IAAG,QAAQ,CAAC,KAAK,EAAC,uBAAuB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAC,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAC,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAC,IAAI,GAAC,UAAU,GAAC,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAC,MAAM,CAAC;CAAE;AAmChP,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAAyB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAA8B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAAgB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAtK,UAAU,EAAC,uBAAuB,EAAkB,YAAY,GAAC,SAA4B,EAAkB,aAAa,SAAe,EAAkB,SAAS,SAAW;IACxM,IAAI,CAAC,OAAO,EAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAC,KAAK,EAAC,OAAO,GAAE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;CAkBlG"}
@@ -0,0 +1,111 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { spawn } from "node:child_process";
6
+ export class HostTransportError extends Error {
7
+ code;
8
+ constructor(code) {
9
+ super(code);
10
+ this.code = code;
11
+ this.name = "HostTransportError";
12
+ }
13
+ }
14
+ const MAX_BYTES = 16 * 1024, TIMEOUT_MS = 8_000;
15
+ const SERVICES = new Set(["bifrost", "tailscaled", "ct-agent"]);
16
+ const PUBLIC_KEY = /^(ssh-ed25519|ecdsa-sha2-nistp256) ([A-Za-z0-9+/]+={0,2})$/;
17
+ function fail(code) { throw new HostTransportError(code); }
18
+ function readOperation(input) {
19
+ if (!input || typeof input !== "object" || Array.isArray(input))
20
+ fail("HOST_OPERATION_INVALID");
21
+ const r = input;
22
+ if ((r.kind === "host_status" || r.kind === "tailnet_status") && Object.keys(r).length === 1)
23
+ return { kind: r.kind };
24
+ if (r.kind === "service_status" && typeof r.service === "string" && SERVICES.has(r.service) && Object.keys(r).length === 2)
25
+ return { kind: r.kind, service: r.service };
26
+ fail("HOST_OPERATION_INVALID");
27
+ }
28
+ function fingerprint(key) {
29
+ const m = PUBLIC_KEY.exec(key);
30
+ if (!m)
31
+ fail("HOST_HOSTKEY_INVALID");
32
+ const bytes = Buffer.from(m[2], "base64");
33
+ if (!bytes.length || bytes.toString("base64").replace(/=+$/, "") !== m[2].replace(/=+$/, ""))
34
+ fail("HOST_HOSTKEY_INVALID");
35
+ return "SHA256:" + createHash("sha256").update(bytes).digest("base64").replace(/=+$/, "");
36
+ }
37
+ function remoteScript(op) {
38
+ const p = 'm=$(cat /etc/machine-id 2>/dev/null) || exit 40; printf "CTMID=%s\\n" "$m"; ';
39
+ if (op.kind === "host_status")
40
+ return p + 'printf "CTSTATUS=ok\\nCTDETAIL=reachable\\n"';
41
+ const service = op.kind === "tailnet_status" ? "tailscaled" : op.service;
42
+ return p + `systemctl is-active --quiet ${service} && s=ok || s=degraded; printf "CTSTATUS=%s\\nCTDETAIL=${service}\\n" "$s"`;
43
+ }
44
+ function parse(stdout, b, op) {
45
+ const l = stdout.split("\n").filter(Boolean);
46
+ if (l.length !== 3 || !l[0].startsWith("CTMID=") || !l[1].startsWith("CTSTATUS=") || !l[2].startsWith("CTDETAIL="))
47
+ fail("HOST_OUTPUT_INVALID");
48
+ const machineId = l[0].slice(6);
49
+ if (!/^[a-f0-9]{32}$/.test(machineId) || machineId !== b.machineId)
50
+ fail("HOST_IDENTITY_MISMATCH");
51
+ const status = l[1].slice(9);
52
+ if (status !== "ok" && status !== "degraded" && status !== "unknown")
53
+ fail("HOST_OUTPUT_INVALID");
54
+ const detail = l[2].slice(9), expected = op.kind === "host_status" ? "reachable" : op.kind === "tailnet_status" ? "tailscaled" : op.service;
55
+ if (detail !== expected)
56
+ fail("HOST_OUTPUT_INVALID");
57
+ return Object.freeze({ scope: "read_only_host_status", assetId: b.assetId, operation: op.kind, machineId, status, detail });
58
+ }
59
+ export class BoundedHostTransport {
60
+ enrollment;
61
+ spawnProcess;
62
+ sshExecutable;
63
+ timeoutMs;
64
+ constructor(enrollment, spawnProcess = spawn, sshExecutable = "/usr/bin/ssh", timeoutMs = TIMEOUT_MS) {
65
+ this.enrollment = enrollment;
66
+ this.spawnProcess = spawnProcess;
67
+ this.sshExecutable = sshExecutable;
68
+ this.timeoutMs = timeoutMs;
69
+ }
70
+ async read(binding, input) {
71
+ const op = readOperation(input), key = await this.enrollment.getPublicHostKey(binding.assetId);
72
+ if (typeof key !== "string")
73
+ fail("HOST_ENROLLMENT_MISSING");
74
+ if (fingerprint(key) !== binding.sshHostKeySha256)
75
+ fail("HOST_HOSTKEY_INVALID");
76
+ const dir = await mkdtemp(join(tmpdir(), "ct-host-")), knownHosts = join(dir, "known_hosts");
77
+ try {
78
+ await writeFile(knownHosts, `${binding.tailnetHostname} ${key}\n`, { encoding: "utf8", mode: 0o600 });
79
+ const args = ["-F", "/dev/null", "-T", "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", "-o", `UserKnownHostsFile=${knownHosts}`, "-o", "GlobalKnownHostsFile=/dev/null", "-o", "CheckHostIP=no", "-o", "ConnectTimeout=5", "-o", "ConnectionAttempts=1", "--", `${binding.remoteUser}@${binding.tailnetHostname}`, remoteScript(op)];
80
+ const child = this.spawnProcess(this.sshExecutable, args, { stdio: ["ignore", "pipe", "pipe"], detached: true, env: { PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" } });
81
+ const out = [];
82
+ let bytes = 0, overflow = false, timedOut = false;
83
+ child.stdout.on("data", (c) => { bytes += c.length; if (bytes <= MAX_BYTES)
84
+ out.push(c);
85
+ else
86
+ overflow = true; });
87
+ child.stderr.on("data", (c) => { bytes += c.length; if (bytes > MAX_BYTES)
88
+ overflow = true; });
89
+ const timer = setTimeout(() => { timedOut = true; if (typeof child.pid === "number")
90
+ try {
91
+ process.kill(-child.pid, "SIGKILL");
92
+ }
93
+ catch { } ; try {
94
+ child.kill("SIGKILL");
95
+ }
96
+ catch { } }, this.timeoutMs);
97
+ const code = await new Promise((resolve, reject) => { child.once("error", reject); child.once("close", resolve); }).catch(() => fail("HOST_PROCESS_FAILED")).finally(() => clearTimeout(timer));
98
+ if (timedOut)
99
+ fail("HOST_TIMEOUT");
100
+ if (overflow)
101
+ fail("HOST_OUTPUT_INVALID");
102
+ if (code !== 0)
103
+ fail("HOST_PROCESS_FAILED");
104
+ return parse(Buffer.concat(out).toString("utf8"), binding, op);
105
+ }
106
+ finally {
107
+ await rm(dir, { recursive: true, force: true }).catch(() => undefined);
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/host/transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calltelemetry/ct-lab-mcp",
3
- "version": "0.8.38",
3
+ "version": "0.8.40",
4
4
  "description": "Expanded Model Context Protocol (MCP) server for Call Telemetry lab, fleet, and appliance management across Proxmox VE and VMware ESXi.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",