mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-09 17:06:24 +08:00
[fix] recover initial MCP signaling connections and preserve failure reasons
This commit is contained in:
@@ -13,6 +13,7 @@ export class Failure extends Error {
|
||||
public code: string,
|
||||
public sideEffect = false,
|
||||
public retryable = false,
|
||||
public reason?: string,
|
||||
) {
|
||||
super(code);
|
||||
}
|
||||
@@ -23,6 +24,7 @@ export function failure(error: unknown): Data {
|
||||
code: e.code,
|
||||
retryable: e.retryable,
|
||||
side_effect_possible: e.sideEffect,
|
||||
...(e.reason ? { reason: e.reason } : {}),
|
||||
};
|
||||
}
|
||||
export function parse<T extends z.ZodType>(
|
||||
|
||||
@@ -201,6 +201,7 @@ async function main() {
|
||||
});
|
||||
}
|
||||
main().catch((error) => {
|
||||
process.stderr.write(`crossdesk-mcp: ${failure(error).code}\n`);
|
||||
const result = failure(error);
|
||||
process.stderr.write(`crossdesk-mcp: ${result.code}${result.reason ? ` (${result.reason})` : ""}\n`);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
||||
@@ -15,6 +15,26 @@ import { DeviceStore, type Device } from "./store.js";
|
||||
import { nativeBinary, NativeClient } from "./native.js";
|
||||
import { displayEnvironment } from "./environment.js";
|
||||
|
||||
// Keep the public error categories while exposing only known native reasons.
|
||||
const connectionErrors = new Map<string, string>([
|
||||
["incorrect_password", "AUTH_FAILED"],
|
||||
["signaling_timeout", "CONNECTION_TIMEOUT"],
|
||||
["connection_timeout", "CONNECTION_TIMEOUT"],
|
||||
["signaling_login_failed", "CONNECTION_FAILED"],
|
||||
["signaling_disconnected", "CONNECTION_FAILED"],
|
||||
["tls_certificate_error", "CONNECTION_FAILED"],
|
||||
["cli_identity_not_supported", "CONNECTION_FAILED"],
|
||||
["join_request_failed", "CONNECTION_FAILED"],
|
||||
["device_not_found", "CONNECTION_FAILED"],
|
||||
["device_offline_or_unavailable", "CONNECTION_FAILED"],
|
||||
["connection_lost", "CONNECTION_FAILED"],
|
||||
["connection_failed", "CONNECTION_FAILED"],
|
||||
["remote_disconnected", "CONNECTION_FAILED"],
|
||||
["display_not_available", "CONNECTION_FAILED"],
|
||||
["media_initialization_failed", "CONNECTION_FAILED"],
|
||||
["control_event_overflow", "CONNECTION_FAILED"],
|
||||
]);
|
||||
|
||||
export interface View {
|
||||
id: string;
|
||||
generation: number;
|
||||
@@ -346,12 +366,11 @@ export class Sessions {
|
||||
s.connecting = false;
|
||||
return { ...s.status, session_id: s.id, device_alias: s.device.alias };
|
||||
}
|
||||
if (["failed", "closed", "disconnected"].includes(s.status.state))
|
||||
throw new Failure(
|
||||
s.status.error === "incorrect_password"
|
||||
? "AUTH_FAILED"
|
||||
: "CONNECTION_FAILED",
|
||||
);
|
||||
if (["failed", "closed", "disconnected"].includes(s.status.state)) {
|
||||
const code = connectionErrors.get(s.status.error);
|
||||
throw new Failure(code ?? "CONNECTION_FAILED", false, false,
|
||||
code ? s.status.error : undefined);
|
||||
}
|
||||
await delay(100, undefined, { signal });
|
||||
}
|
||||
throw new Failure("CONNECTION_TIMEOUT");
|
||||
|
||||
@@ -161,7 +161,8 @@ export class TerminalClient {
|
||||
if (!buffer.includes(10)) return;
|
||||
try {
|
||||
const reply = JSON.parse(buffer.toString("utf8"));
|
||||
if (reply.error) finish(new Failure(reply.error.code));
|
||||
if (reply.error) finish(new Failure(reply.error.code,
|
||||
!!reply.error.side_effect_possible, !!reply.error.retryable, reply.error.reason));
|
||||
else if (reply.result && typeof reply.result === "object") finish(undefined, reply.result);
|
||||
else finish(new Failure("INVALID_RESPONSE"));
|
||||
} catch { finish(new Failure("INVALID_RESPONSE")); }
|
||||
|
||||
Reference in New Issue
Block a user