refactor(server): add getErrorMessage helper and fix error-related type-aware lint errors (#704)

* refactor(server): add getErrorMessage helper and fix error-related type-aware lint errors in session.ts

* fix build: correct parseClientCapabilities type handling
This commit is contained in:
Mohamed Boudra
2026-05-05 19:57:35 +07:00
parent d359bffed5
commit 8b54d27cbc
2 changed files with 64 additions and 43 deletions
+37 -43
View File
@@ -78,6 +78,7 @@ import { spawnWorkspaceScript } from "./worktree-bootstrap.js";
import type { WorkspaceScriptRuntimeStore } from "./workspace-script-runtime-store.js"; import type { WorkspaceScriptRuntimeStore } from "./workspace-script-runtime-store.js";
import type { DaemonConfigStore } from "./daemon-config-store.js"; import type { DaemonConfigStore } from "./daemon-config-store.js";
import { applyMutableProviderConfigToOverrides } from "./daemon-config-store.js"; import { applyMutableProviderConfigToOverrides } from "./daemon-config-store.js";
import { getErrorMessage, getErrorMessageOr } from "../shared/error-utils.js";
import type { WorkspaceGitRuntimeSnapshot, WorkspaceGitService } from "./workspace-git-service.js"; import type { WorkspaceGitRuntimeSnapshot, WorkspaceGitService } from "./workspace-git-service.js";
import { buildProviderRegistry } from "./agent/provider-registry.js"; import { buildProviderRegistry } from "./agent/provider-registry.js";
@@ -733,11 +734,13 @@ function parseClientCapabilities(
return new Set(); return new Set();
} }
const known = new Set<ClientCapability>(Object.values(CLIENT_CAPS)); const known = new Set<ClientCapability>(Object.values(CLIENT_CAPS));
return new Set( const result: ClientCapability[] = [];
Object.entries(capabilities).flatMap(([key, value]) => for (const [key, value] of Object.entries(capabilities)) {
value === true && known.has(key as ClientCapability) ? [key as ClientCapability] : [], if (value === true && known.has(key as ClientCapability)) {
), result.push(key as ClientCapability);
); }
}
return new Set(result);
} }
/** /**
@@ -1692,7 +1695,8 @@ export class Session {
const err = error instanceof Error ? error : new Error(String(error)); const err = error instanceof Error ? error : new Error(String(error));
this.sessionLogger.error({ err }, "Error handling message"); this.sessionLogger.error({ err }, "Error handling message");
const requestId = (msg as { requestId?: unknown }).requestId; const requestId =
"requestId" in msg && typeof msg.requestId === "string" ? msg.requestId : undefined;
if (typeof requestId === "string") { if (typeof requestId === "string") {
try { try {
this.emit({ this.emit({
@@ -2493,7 +2497,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to update agent: ${(error as Error).message}`, content: `Failed to update agent: ${getErrorMessage(error)}`,
}, },
}); });
this.emit({ this.emit({
@@ -2502,9 +2506,7 @@ export class Session {
requestId, requestId,
agentId, agentId,
accepted: false, accepted: false,
error: (error as Error | undefined)?.message error: getErrorMessageOr(error, "Failed to update agent"),
? String((error as Error).message)
: "Failed to update agent",
}, },
}); });
} }
@@ -3168,7 +3170,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to resume agent: ${(error as Error).message}`, content: `Failed to resume agent: ${getErrorMessage(error)}`,
}, },
}); });
} }
@@ -3321,7 +3323,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to refresh agent: ${(error as Error).message}`, content: `Failed to refresh agent: ${getErrorMessage(error)}`,
}, },
}); });
} }
@@ -3497,7 +3499,7 @@ export class Session {
type: "list_provider_models_response", type: "list_provider_models_response",
payload: { payload: {
provider: msg.provider, provider: msg.provider,
error: (error as Error)?.message ?? String(error), error: getErrorMessage(error),
fetchedAt, fetchedAt,
requestId: msg.requestId, requestId: msg.requestId,
}, },
@@ -3645,7 +3647,7 @@ export class Session {
type: "list_provider_modes_response", type: "list_provider_modes_response",
payload: { payload: {
provider: msg.provider, provider: msg.provider,
error: (error as Error)?.message ?? String(error), error: getErrorMessage(error),
fetchedAt, fetchedAt,
requestId: msg.requestId, requestId: msg.requestId,
}, },
@@ -3722,7 +3724,7 @@ export class Session {
type: "list_provider_features_response", type: "list_provider_features_response",
payload: { payload: {
provider: msg.draftConfig.provider, provider: msg.draftConfig.provider,
error: (error as Error)?.message ?? String(error), error: getErrorMessage(error),
fetchedAt, fetchedAt,
requestId: msg.requestId, requestId: msg.requestId,
}, },
@@ -3753,7 +3755,7 @@ export class Session {
type: "list_available_providers_response", type: "list_available_providers_response",
payload: { payload: {
providers: [], providers: [],
error: (error as Error)?.message ?? String(error), error: getErrorMessage(error),
fetchedAt, fetchedAt,
requestId: msg.requestId, requestId: msg.requestId,
}, },
@@ -3999,7 +4001,7 @@ export class Session {
const snapshot = await this.workspaceGitService.getSnapshot(cwd); const snapshot = await this.workspaceGitService.getSnapshot(cwd);
return snapshot.git.isDirty === true; return snapshot.git.isDirty === true;
} catch (error) { } catch (error) {
throw new Error(`Unable to inspect git status for ${cwd}: ${(error as Error).message}`, { throw new Error(`Unable to inspect git status for ${cwd}: ${getErrorMessage(error)}`, {
cause: error, cause: error,
}); });
} }
@@ -4103,7 +4105,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to set agent mode: ${(error as Error).message}`, content: `Failed to set agent mode: ${getErrorMessage(error)}`,
}, },
}); });
this.emit({ this.emit({
@@ -4112,9 +4114,7 @@ export class Session {
requestId, requestId,
agentId, agentId,
accepted: false, accepted: false,
error: (error as Error | undefined)?.message error: getErrorMessageOr(error, "Failed to set agent mode"),
? String((error as Error).message)
: "Failed to set agent mode",
}, },
}); });
} }
@@ -4148,7 +4148,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to set agent model: ${(error as Error).message}`, content: `Failed to set agent model: ${getErrorMessage(error)}`,
}, },
}); });
this.emit({ this.emit({
@@ -4157,9 +4157,7 @@ export class Session {
requestId, requestId,
agentId, agentId,
accepted: false, accepted: false,
error: (error as Error | undefined)?.message error: getErrorMessageOr(error, "Failed to set agent model"),
? String((error as Error).message)
: "Failed to set agent model",
}, },
}); });
} }
@@ -4197,7 +4195,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to set agent feature: ${(error as Error).message}`, content: `Failed to set agent feature: ${getErrorMessage(error)}`,
}, },
}); });
this.emit({ this.emit({
@@ -4206,9 +4204,7 @@ export class Session {
requestId, requestId,
agentId, agentId,
accepted: false, accepted: false,
error: (error as Error | undefined)?.message error: getErrorMessageOr(error, "Failed to set agent feature"),
? String((error as Error).message)
: "Failed to set agent feature",
}, },
}); });
} }
@@ -4245,7 +4241,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to set agent thinking option: ${(error as Error).message}`, content: `Failed to set agent thinking option: ${getErrorMessage(error)}`,
}, },
}); });
this.emit({ this.emit({
@@ -4254,9 +4250,7 @@ export class Session {
requestId, requestId,
agentId, agentId,
accepted: false, accepted: false,
error: (error as Error | undefined)?.message error: getErrorMessageOr(error, "Failed to set agent thinking option"),
? String((error as Error).message)
: "Failed to set agent thinking option",
}, },
}); });
} }
@@ -4397,7 +4391,7 @@ export class Session {
payload: { payload: {
agentId, agentId,
commands: [], commands: [],
error: (error as Error).message, error: getErrorMessage(error),
requestId, requestId,
}, },
}); });
@@ -4439,7 +4433,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Failed to respond to permission: ${(error as Error).message}`, content: `Failed to respond to permission: ${getErrorMessage(error)}`,
}, },
}); });
throw error; throw error;
@@ -4534,7 +4528,7 @@ export class Session {
return; return;
default: { default: {
const exhaustiveCheck: never = resolution; const exhaustiveCheck: never = resolution;
throw new Error(`Unhandled branch resolution: ${exhaustiveCheck}`); throw new Error(`Unhandled branch resolution: ${getErrorMessage(exhaustiveCheck)}`);
} }
} }
} catch (error) { } catch (error) {
@@ -5563,7 +5557,7 @@ export class Session {
mode, mode,
directory: null, directory: null,
file: null, file: null,
error: (error as Error).message, error: getErrorMessage(error),
requestId, requestId,
}, },
}); });
@@ -5595,7 +5589,7 @@ export class Session {
payload: { payload: {
cwd, cwd,
icon: null, icon: null,
error: (error as Error).message, error: getErrorMessage(error),
requestId, requestId,
}, },
}); });
@@ -5671,7 +5665,7 @@ export class Session {
fileName: null, fileName: null,
mimeType: null, mimeType: null,
size: null, size: null,
error: (error as Error).message, error: getErrorMessage(error),
requestId, requestId,
}, },
}); });
@@ -5966,7 +5960,7 @@ export class Session {
defaultSort: [{ key: "updated_at", direction: "desc" }], defaultSort: [{ key: "updated_at", direction: "desc" }],
label: "fetch_agents", label: "fetch_agents",
getId: (agent) => agent.id, getId: (agent) => agent.id,
getSortValue: (agent, key) => { getSortValue: (agent, key): number | string => {
switch (key) { switch (key) {
case "status_priority": case "status_priority":
return this.getStatusPriority(agent); return this.getStatusPriority(agent);
@@ -6007,7 +6001,7 @@ export class Session {
return { return {
id: workspace.workspaceId, id: workspace.workspaceId,
projectId: workspace.projectId, projectId: workspace.projectId,
projectDisplayName: resolvedProjectRecord?.displayName ?? String(workspace.projectId), projectDisplayName: resolvedProjectRecord?.displayName ?? workspace.projectId,
projectRootPath: resolvedProjectRecord?.rootPath ?? workspace.cwd, projectRootPath: resolvedProjectRecord?.rootPath ?? workspace.cwd,
workspaceDirectory: workspace.cwd, workspaceDirectory: workspace.cwd,
projectKind: (resolvedProjectRecord?.kind ?? "directory") === "git" ? "git" : "non_git", projectKind: (resolvedProjectRecord?.kind ?? "directory") === "git" ? "git" : "non_git",
@@ -6095,7 +6089,7 @@ export class Session {
return { return {
id: result.workspace.workspaceId, id: result.workspace.workspaceId,
projectId: result.workspace.projectId, projectId: result.workspace.projectId,
projectDisplayName: projectRecord?.displayName ?? String(result.workspace.projectId), projectDisplayName: projectRecord?.displayName ?? result.workspace.projectId,
projectRootPath: projectRecord?.rootPath ?? result.repoRoot, projectRootPath: projectRecord?.rootPath ?? result.repoRoot,
workspaceDirectory: result.workspace.cwd, workspaceDirectory: result.workspace.cwd,
projectKind: "git", projectKind: "git",
@@ -7779,7 +7773,7 @@ export class Session {
id: uuidv4(), id: uuidv4(),
timestamp: new Date(), timestamp: new Date(),
type: "error", type: "error",
content: `Transcription error: ${(error as Error).message}`, content: `Transcription error: ${getErrorMessage(error)}`,
}, },
}); });
throw error; throw error;
+27
View File
@@ -0,0 +1,27 @@
/**
* Extracts a human-readable error message from an unknown error value.
* Handles Error instances, string errors, and other types safely.
*/
export function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
if (typeof error === "string") {
return error;
}
return String(error);
}
/**
* Extracts an error message from an unknown error value, with a fallback
* for when no message can be extracted.
*/
export function getErrorMessageOr(error: unknown, fallback: string): string {
if (error instanceof Error) {
return error.message;
}
if (typeof error === "string" && error.length > 0) {
return error;
}
return fallback;
}