function formatSidecarStderrSuffix(stderr: string): string { return stderr ? `\nstderr:\n${stderr}` : "";} export interface SidecarRejectionDetail { code: string; message: string; limit_name: string | null; configured_limit: number | null; current_usage: number | null; requested: number | null; unit: string | null; scope: string | null; vm_id: string | null; session_generation: number | null; capability_id: number | null; operation: string | null; configuration_path: string | null; retryable: boolean | null; errno: string | null;} export class SidecarRejectedError extends Error { readonly requestId: number; readonly detail: SidecarRejectionDetail; constructor(requestId: number, detail: SidecarRejectionDetail) { super( `sidecar rejected request ${requestId}: ${detail.code}: ${detail.message}`, ); this.name = "SidecarRejectedError"; this.requestId = requestId; this.detail = detail; }} export class SidecarProcessExited extends Error { readonly exitCode: number | null; readonly signal: string | null; readonly stderr: string; constructor(options: { exitCode: number | null; signal: string | null; stderr: string; }) { const reason = options.signal !== null ? `signal ${options.signal}` : options.exitCode !== null ? `code ${options.exitCode}` : "disconnect"; super( `sidecar process exited with ${reason}${formatSidecarStderrSuffix(options.stderr)}`, ); this.name = "SidecarProcessExited"; this.exitCode = options.exitCode; this.signal = options.signal; this.stderr = options.stderr; }} /** * The silence watchdog fired: the sidecar produced no protocol frames at all — * not even its 10s liveness heartbeats — for the full silence window, so the * process is dead or wedged (not merely busy: a busy sidecar still heartbeats * from a dedicated thread). The host kills the sidecar and rejects every * in-flight request with this error. */export class SidecarSilenceTimeout extends Error { readonly silenceMs: number; readonly stderr: string; constructor(options: { silenceMs: number; stderr: string }) { super( `sidecar unresponsive: no protocol frames or heartbeats for ${Math.round(options.silenceMs)}ms; killing sidecar${formatSidecarStderrSuffix(options.stderr)}`, ); this.name = "SidecarSilenceTimeout"; this.silenceMs = options.silenceMs; this.stderr = options.stderr; }} export class SidecarProcessError extends Error { readonly childError: Error; readonly stderr: string; constructor(error: Error, stderr: string) { super( `sidecar process error: ${error.message}${formatSidecarStderrSuffix(stderr)}`, ); this.name = "SidecarProcessError"; this.childError = error; this.stderr = stderr; }}
function formatSidecarStderrSuffix(stderr: string): string {
return stderr ? `\nstderr:\n${stderr}` : "";
}
export interface SidecarRejectionDetail {
code: string;
message: string;
limit_name: string | null;
configured_limit: number | null;
current_usage: number | null;
requested: number | null;
unit: string | null;
scope: string | null;
vm_id: string | null;
session_generation: number | null;
capability_id: number | null;
operation: string | null;
configuration_path: string | null;
retryable: boolean | null;
errno: string | null;
}
export class SidecarRejectedError extends Error {
readonly requestId: number;
readonly detail: SidecarRejectionDetail;
constructor(requestId: number, detail: SidecarRejectionDetail) {
super(
`sidecar rejected request ${requestId}: ${detail.code}: ${detail.message}`,
);
this.name = "SidecarRejectedError";
this.requestId = requestId;
this.detail = detail;
}
}
export class SidecarProcessExited extends Error {
readonly exitCode: number | null;
readonly signal: string | null;
readonly stderr: string;
constructor(options: {
exitCode: number | null;
signal: string | null;
stderr: string;
}) {
const reason =
options.signal !== null
? `signal ${options.signal}`
: options.exitCode !== null
? `code ${options.exitCode}`
: "disconnect";
super(
`sidecar process exited with ${reason}${formatSidecarStderrSuffix(options.stderr)}`,
);
this.name = "SidecarProcessExited";
this.exitCode = options.exitCode;
this.signal = options.signal;
this.stderr = options.stderr;
}
}
/**
* The silence watchdog fired: the sidecar produced no protocol frames at all —
* not even its 10s liveness heartbeats — for the full silence window, so the
* process is dead or wedged (not merely busy: a busy sidecar still heartbeats
* from a dedicated thread). The host kills the sidecar and rejects every
* in-flight request with this error.
*/
export class SidecarSilenceTimeout extends Error {
readonly silenceMs: number;
readonly stderr: string;
constructor(options: { silenceMs: number; stderr: string }) {
super(
`sidecar unresponsive: no protocol frames or heartbeats for ${Math.round(options.silenceMs)}ms; killing sidecar${formatSidecarStderrSuffix(options.stderr)}`,
);
this.name = "SidecarSilenceTimeout";
this.silenceMs = options.silenceMs;
this.stderr = options.stderr;
}
}
export class SidecarProcessError extends Error {
readonly childError: Error;
readonly stderr: string;
constructor(error: Error, stderr: string) {
super(
`sidecar process error: ${error.message}${formatSidecarStderrSuffix(stderr)}`,
);
this.name = "SidecarProcessError";
this.childError = error;
this.stderr = stderr;
}
}