chore(lint): enable stricter error rules

This commit is contained in:
Peter Steinberger
2026-06-01 01:12:00 +01:00
parent 0bfba7e26d
commit 27dde7a4d6
458 changed files with 3159 additions and 936 deletions

View File

@@ -82,7 +82,10 @@
"typescript/no-meaningless-void-operator": "error",
"typescript/no-misused-promises": "error",
"typescript/no-inferrable-types": "error",
"typescript/only-throw-error": "error",
"typescript/no-non-null-asserted-nullish-coalescing": "error",
"typescript/prefer-promise-reject-errors": "error",
"typescript/restrict-plus-operands": "error",
"typescript/no-unnecessary-qualifier": "error",
"typescript/no-unnecessary-type-assertion": "error",
"typescript/no-unnecessary-type-arguments": "error",
@@ -109,6 +112,8 @@
"typescript/require-array-sort-compare": "error",
"typescript/restrict-template-expressions": "error",
"typescript/triple-slash-reference": "error",
"typescript/unbound-method": "error",
"typescript/use-unknown-in-catch-callback-variable": "error",
"unicorn/consistent-date-clone": "error",
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-function-scoping": "off",
@@ -128,6 +133,7 @@
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-useless-error-capture-stack-trace": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/no-useless-switch-case": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-text-content": "error",

View File

@@ -68,7 +68,7 @@ class LegacyRunTurnEventQueue {
return item;
}
if (this.error) {
throw this.error;
throw toLintErrorObject(this.error, "Non-Error thrown");
}
if (this.closed) {
return null;
@@ -178,3 +178,17 @@ export function lazyStartRuntimeTurn(
},
};
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -286,7 +286,7 @@ describe("AcpxRuntime fresh reset wrapper", () => {
})
.then(
() => ({ status: "resolved" as const }),
(error) => ({ status: "rejected" as const, error }),
(error: unknown) => ({ status: "rejected" as const, error }),
);
expect(outcome.status).toBe("rejected");
@@ -298,7 +298,12 @@ describe("AcpxRuntime fresh reset wrapper", () => {
code: "ACP_SESSION_INIT_FAILED",
message: expect.stringContaining("deployment missing"),
});
expect(outcome.error.message).not.toContain("sk-testsecret1234567890");
const error = outcome.error;
expect(error).toBeInstanceOf(AcpRuntimeError);
if (!(error instanceof AcpRuntimeError)) {
throw new Error("expected AcpRuntimeError");
}
expect(error.message).not.toContain("sk-testsecret1234567890");
});
it("adds Codex wrapper stderr tail to generic first-turn failures", async () => {

View File

@@ -218,13 +218,21 @@ describe("active-memory plugin", () => {
};
const waitForAbort = async (abortSignal?: AbortSignal): Promise<never> => {
if (abortSignal?.aborted) {
throw (abortSignal.reason as unknown) ?? new Error("Operation aborted");
throw toLintErrorObject(
(abortSignal.reason as unknown) ?? new Error("Operation aborted"),
"Non-Error thrown",
);
}
return await new Promise<never>((_resolve, reject) => {
abortSignal?.addEventListener(
"abort",
() => {
reject((abortSignal.reason as unknown) ?? new Error("Operation aborted"));
reject(
toLintErrorObject(
(abortSignal.reason as unknown) ?? new Error("Operation aborted"),
"Non-Error rejection",
),
);
},
{ once: true },
);
@@ -4350,3 +4358,17 @@ describe("active-memory plugin", () => {
expect(config.circuitBreakerCooldownMs).toBe(5000);
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -1011,7 +1011,6 @@ function buildPromptStyleLines(style: ActiveMemoryPromptStyle): string[] {
"If relevant memory is mostly a stable user preference or recurring habit, lean toward returning it.",
"If the strongest match is only a one-off historical fact and not a recurring preference or habit, prefer NONE unless the latest user message clearly asks for that fact.",
];
case "balanced":
default:
return [
"Treat the latest user message as the primary query.",
@@ -1982,7 +1981,7 @@ async function waitForSubagentPartialTimeoutData(
(await Promise.race([
subagentPromise.then(
() => undefined,
(error) => readPartialTimeoutData(error),
(error: unknown) => readPartialTimeoutData(error),
),
timeoutPromise,
])) ?? {}

View File

@@ -571,7 +571,7 @@ export async function startGatewayBonjourAdvertiser(
.then(() => {
logger.info(`bonjour: advertised ${serviceSummary(label, svc)}`);
})
.catch((err) => {
.catch((err: unknown) => {
handleAdvertiseFailure(label, svc, err, "failed");
});
} catch (err) {
@@ -747,7 +747,7 @@ export async function startGatewayBonjourAdvertiser(
)})`,
);
try {
void svc.advertise().catch((err) => {
void svc.advertise().catch((err: unknown) => {
logger.warn(
`bonjour: watchdog re-advertise failed (${serviceSummary(label, svc)}): ${formatBonjourError(err)}`,
);

View File

@@ -416,7 +416,8 @@ describe("cdp.helpers internal", () => {
await expect(
withCdpSocket(server.url, async (send) => {
await send("Test.ok");
const rejectRawString = () => Promise.reject("raw-string-from-callback");
const rejectRawString = () =>
Promise.reject(toLintErrorObject("raw-string-from-callback", "Non-Error rejection"));
return rejectRawString();
}),
).rejects.toThrow(/raw-string-from-callback/);
@@ -572,3 +573,17 @@ describe("openCdpWebSocket option handling", () => {
ws.close();
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -258,7 +258,7 @@ function extractJsonMessage(result: ChromeMcpToolResult): unknown {
}
}
if (lastError) {
throw lastError;
throw toLintErrorObject(lastError, "Non-Error thrown");
}
return null;
}
@@ -629,7 +629,7 @@ async function closeChromeMcpClientAndProcess(params: {
return;
}
await params.client.close().catch(() => {});
await terminateChromeMcpProcessTree(rootPid, descendantPids).catch((err) => {
await terminateChromeMcpProcessTree(rootPid, descendantPids).catch((err: unknown) => {
log.trace(
`Unable to fully terminate Chrome MCP subprocess tree for pid ${rootPid}: ${err instanceof Error ? err.message : String(err)}`,
);
@@ -761,7 +761,8 @@ async function waitForChromeMcpReady(
if (signal) {
racers.push(
new Promise<never>((_, reject) => {
abortListener = () => reject(signal.reason ?? new Error("aborted"));
abortListener = () =>
reject(toLintErrorObject(signal.reason ?? new Error("aborted"), "Non-Error rejection"));
signal.addEventListener("abort", abortListener, { once: true });
}),
);
@@ -793,7 +794,8 @@ async function waitForChromeMcpPendingSession(
return await Promise.race([
pending,
new Promise<never>((_, reject) => {
abortListener = () => reject(signal.reason ?? new Error("aborted"));
abortListener = () =>
reject(toLintErrorObject(signal.reason ?? new Error("aborted"), "Non-Error rejection"));
signal.addEventListener("abort", abortListener, { once: true });
}),
]);
@@ -1022,7 +1024,8 @@ async function callTool(
if (signal) {
racers.push(
new Promise<never>((_, reject) => {
abortListener = () => reject(signal.reason ?? new Error("aborted"));
abortListener = () =>
reject(toLintErrorObject(signal.reason ?? new Error("aborted"), "Non-Error rejection"));
signal.addEventListener("abort", abortListener, { once: true });
}),
);
@@ -1540,3 +1543,17 @@ export async function resetChromeMcpSessionsForTest(): Promise<void> {
await stopAllChromeMcpSessions();
chromeMcpProcessCleanupDepsForTest = null;
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -315,9 +315,17 @@ export async function fetchBrowserJson<T>(
let abortListener: (() => void) | undefined;
const abortPromise: Promise<never> = abortCtrl.signal.aborted
? Promise.reject(abortCtrl.signal.reason ?? new Error("aborted"))
? Promise.reject(
toLintErrorObject(abortCtrl.signal.reason ?? new Error("aborted"), "Non-Error rejection"),
)
: new Promise((_, reject) => {
abortListener = () => reject(abortCtrl.signal.reason ?? new Error("aborted"));
abortListener = () =>
reject(
toLintErrorObject(
abortCtrl.signal.reason ?? new Error("aborted"),
"Non-Error rejection",
),
);
abortCtrl.signal.addEventListener("abort", abortListener, { once: true });
});
@@ -382,3 +390,17 @@ export const testApi = {
withLoopbackBrowserAuth: withLoopbackBrowserAuthImpl,
};
export { testApi as __test };
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -1359,12 +1359,12 @@ export async function gotoPageWithNavigationGuard(
try {
const response = await opts.page.goto(opts.url, { timeout: opts.timeoutMs });
if (blockedError) {
throw blockedError;
throw toLintErrorObject(blockedError, "Non-Error thrown");
}
return response;
} catch (err) {
if (blockedError) {
throw blockedError;
throw toLintErrorObject(blockedError, "Non-Error thrown");
}
throw err;
} finally {
@@ -1813,3 +1813,17 @@ export async function focusPageByTargetIdViaPlaywright(opts: {
}
}
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -192,7 +192,7 @@ async function assertObservedDelayedNavigations(opts: {
});
}
if (subframeError) {
throw subframeError;
throw toLintErrorObject(subframeError, "Non-Error thrown");
}
}
@@ -276,7 +276,7 @@ function scheduleDelayedInteractionNavigationGuard(opts: {
const settle = (err?: unknown) => {
cleanup();
if (err) {
reject(err);
reject(toLintErrorObject(err, "Non-Error rejection"));
return;
}
resolve();
@@ -428,11 +428,11 @@ async function assertInteractionNavigationCompletedSafely<T>(opts: {
}
if (subframeError) {
throw subframeError;
throw toLintErrorObject(subframeError, "Non-Error thrown");
}
if (actionError) {
throw actionError;
throw toLintErrorObject(actionError, "Non-Error thrown");
}
return result as T;
}
@@ -478,12 +478,14 @@ function createAbortPromiseWithListener(
const abortPromise: Promise<never> = signal.aborted
? (() => {
onAbort?.(signal.reason);
return Promise.reject(signal.reason ?? new Error("aborted"));
return Promise.reject(
toLintErrorObject(signal.reason ?? new Error("aborted"), "Non-Error rejection"),
);
})()
: new Promise((_, reject) => {
abortListener = () => {
onAbort?.(signal.reason);
reject(signal.reason ?? new Error("aborted"));
reject(toLintErrorObject(signal.reason ?? new Error("aborted"), "Non-Error rejection"));
};
signal.addEventListener("abort", abortListener, { once: true });
});
@@ -1712,3 +1714,17 @@ export async function batchViaPlaywright(opts: {
}
return { results };
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -178,7 +178,7 @@ async function runExistingSessionActionWithNavigationGuard<T>(params: {
}
if (actionError) {
throw actionError;
throw toLintErrorObject(actionError, "Non-Error thrown");
}
return result as T;
@@ -809,3 +809,17 @@ export function registerBrowserAgentActRoutes(
}),
);
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -701,7 +701,7 @@ export function registerBrowserAgentSnapshotRoutes(
const pw = await getPwAiModule();
const snap = plan.wantsRoleSnapshot
? pw
? await pw.snapshotRoleViaPlaywright(roleSnapshotArgs).catch(async (err) => {
? await pw.snapshotRoleViaPlaywright(roleSnapshotArgs).catch(async (err: unknown) => {
const fallback = await cdpRoleSnapshot();
if (fallback) {
return fallback;

View File

@@ -20,10 +20,21 @@ describe("browser route dispatcher (abort)", () => {
const signal = req.signal;
await new Promise<void>((resolve, reject) => {
if (signal?.aborted) {
reject(signal.reason ?? new Error("aborted"));
reject(
toLintErrorObject(
signal.reason ?? new Error("aborted"),
"Non-Error rejection",
),
);
return;
}
const onAbort = () => reject(signal?.reason ?? new Error("aborted"));
const onAbort = () =>
reject(
toLintErrorObject(
signal?.reason ?? new Error("aborted"),
"Non-Error rejection",
),
);
signal?.addEventListener("abort", onAbort, { once: true });
queueMicrotask(() => {
signal?.removeEventListener("abort", onAbort);
@@ -81,3 +92,17 @@ describe("browser route dispatcher (abort)", () => {
expect(body.error).toBe("invalid path parameter encoding: id");
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -66,7 +66,7 @@ export async function normalizeBrowserScreenshot(
}
if (processorUnavailableError) {
throw processorUnavailableError;
throw toLintErrorObject(processorUnavailableError, "Non-Error thrown");
}
const best = smallest?.buffer ?? buffer;
@@ -74,3 +74,17 @@ export async function normalizeBrowserScreenshot(
`Browser screenshot could not be reduced below ${(maxBytes / (1024 * 1024)).toFixed(0)}MB (got ${(best.byteLength / (1024 * 1024)).toFixed(2)}MB)`,
);
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -377,7 +377,7 @@ export function createProfileTabOps({
method: "PUT",
},
getCdpControlPolicy(),
).catch(async (err) => {
).catch(async (err: unknown) => {
if (String(err).includes("HTTP 405")) {
return await fetchJson<CdpTarget>(
endpoint,

View File

@@ -57,7 +57,10 @@ vi.mock("../sdk-node-runtime.js", () => ({
new Promise<never>((_, reject) => {
abortCtrl.signal.addEventListener(
"abort",
() => reject(abortCtrl.signal.reason ?? timeoutError),
() =>
reject(
toLintErrorObject(abortCtrl.signal.reason ?? timeoutError, "Non-Error rejection"),
),
{ once: true },
);
}),
@@ -490,3 +493,17 @@ describe("runBrowserProxyCommand", () => {
expect(dispatcherMocks.dispatch).not.toHaveBeenCalled();
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -45,11 +45,14 @@ function waitForAbort(
cleanup: () => void;
} {
if (signal.aborted) {
return { promise: Promise.reject(signal.reason ?? fallback), cleanup: () => undefined };
return {
promise: Promise.reject(toLintErrorObject(signal.reason ?? fallback, "Non-Error rejection")),
cleanup: () => undefined,
};
}
let listener: (() => void) | undefined;
const promise = new Promise<never>((_, reject) => {
listener = () => reject(signal.reason ?? fallback);
listener = () => reject(toLintErrorObject(signal.reason ?? fallback, "Non-Error rejection"));
signal.addEventListener("abort", listener, { once: true });
});
return {
@@ -82,3 +85,17 @@ export async function withTimeout<T>(
abort.cleanup();
}
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -84,7 +84,7 @@ export async function startBrowserControlServerFromConfig(): Promise<BrowserServ
const server = await new Promise<Server>((resolve, reject) => {
const s = app.listen(port, "127.0.0.1", () => resolve(s));
s.once("error", reject);
}).catch((err) => {
}).catch((err: unknown) => {
logServer.error(`openclaw browser server failed to bind 127.0.0.1:${port}: ${String(err)}`);
return null;
});

View File

@@ -193,8 +193,6 @@ async function pollBytePlusTask(params: {
throw new Error(
readBytePlusErrorMessage(payload.error) || "BytePlus video generation failed",
);
case "queued":
case "running":
default:
await waitProviderOperationPollInterval({ deadline, pollIntervalMs: POLL_INTERVAL_MS });
break;

View File

@@ -222,7 +222,9 @@ async function main() {
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
await main().catch((error) => {
fail(error instanceof Error ? error.message : String(error));
});
await main().catch(
/** @param {unknown} error */ (error) => {
fail(error instanceof Error ? error.message : String(error));
},
);
}

View File

@@ -42,8 +42,10 @@ async function main() {
}
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
main().catch((err) => {
console.error(String(err));
process.exit(1);
});
main().catch(
/** @param {unknown} err */ (err) => {
console.error(String(err));
process.exit(1);
},
);
}

View File

@@ -487,7 +487,7 @@ export async function startCanvasHost(opts: CanvasHostServerOpts): Promise<Canva
res.statusCode = 404;
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end("Not Found");
})().catch((err) => {
})().catch((err: unknown) => {
opts.runtime.error(`Canvas host request failed: ${String(err)}`);
res.statusCode = 500;
res.setHeader("Content-Type", "text/plain; charset=utf-8");

View File

@@ -11,7 +11,7 @@ function formatErrorMessage(error: unknown): string {
}
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
serveCodexSupervisorMcp().catch((err) => {
serveCodexSupervisorMcp().catch((err: unknown) => {
process.stderr.write(`codex-supervisor-serve: ${formatErrorMessage(err)}\n`);
process.exit(1);
});

View File

@@ -556,7 +556,7 @@ export class CodexNativeSubagentMonitor {
childState.transcriptPollTimer = setTimeout(() => {
childState.transcriptPollTimer = undefined;
void this.reconcileChildTranscript(childState.childThreadId)
.catch((error) => {
.catch((error: unknown) => {
embeddedAgentLog.warn("Failed to reconcile Codex native subagent transcript", {
childThreadId: childState.childThreadId,
error: formatErrorMessage(error),
@@ -595,7 +595,7 @@ export class CodexNativeSubagentMonitor {
}
this.taskRowReconcileTimer = setInterval(
() => {
void this.reconcileKnownTaskRows().catch((error) => {
void this.reconcileKnownTaskRows().catch((error: unknown) => {
embeddedAgentLog.warn("Failed to reconcile Codex native subagent task rows", {
error: formatErrorMessage(error),
});

View File

@@ -88,10 +88,10 @@ export async function waitForPluginApprovalDecision(params: {
let onAbort: (() => void) | undefined;
const abortPromise = new Promise<never>((_, reject) => {
if (params.signal!.aborted) {
reject(params.signal!.reason);
reject(toLintErrorObject(params.signal!.reason, "Non-Error rejection"));
return;
}
onAbort = () => reject(params.signal!.reason);
onAbort = () => reject(toLintErrorObject(params.signal!.reason, "Non-Error rejection"));
params.signal!.addEventListener("abort", onAbort, { once: true });
});
try {
@@ -121,3 +121,17 @@ export function mapExecDecisionToOutcome(
function truncateForGateway(value: string, maxLength: number): string {
return value.length <= maxLength ? value : `${value.slice(0, Math.max(0, maxLength - 3))}...`;
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -1037,7 +1037,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
await vi.waitFor(
() => {
if (runError) {
throw runError;
throw toLintErrorObject(runError, "Non-Error thrown");
}
expect(harness.requests.map((request) => request.method)).toContain("turn/start");
},
@@ -1709,3 +1709,17 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
expect(maintain).not.toHaveBeenCalled();
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -696,7 +696,7 @@ describe("runCodexAppServerAttempt", () => {
});
await expect(
client.request("turn/start", turnParams).catch(async (error) => {
client.request("turn/start", turnParams).catch(async (error: unknown) => {
await releaseCodexSandboxExecServerEnvironment(sandbox);
throw error;
}),
@@ -763,7 +763,7 @@ describe("runCodexAppServerAttempt", () => {
nativeCodeModeOnlyEnabled: false,
userMcpServersEnabled: false,
environmentSelection,
}).catch(async (error) => {
}).catch(async (error: unknown) => {
await releaseCodexSandboxExecServerEnvironment(sandbox);
throw error;
}),
@@ -1237,7 +1237,7 @@ describe("runCodexAppServerAttempt", () => {
params.prompt = "already persisted prompt";
params.suppressNextUserMessagePersistence = true;
const readTranscript = async () =>
fs.readFile(sessionFile, "utf8").catch((error) => {
fs.readFile(sessionFile, "utf8").catch((error: unknown) => {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
return "";
}

View File

@@ -94,9 +94,11 @@ export function createCodexUserInputBridge(params: {
resolvePending(emptyUserInputResponse());
return;
}
void deliverUserInputPrompt(params.paramsForRun, requestParams.questions).catch((error) => {
embeddedAgentLog.warn("failed to deliver codex user input prompt", { error });
});
void deliverUserInputPrompt(params.paramsForRun, requestParams.questions).catch(
(error: unknown) => {
embeddedAgentLog.warn("failed to deliver codex user input prompt", { error });
},
);
});
},
handleQueuedMessage(text) {

View File

@@ -388,22 +388,24 @@ async function withPluginMigrationEligibility(params: {
return evaluated;
}
const snapshot = await refreshSourceAppInventory(params.requestOptions).catch((error) => {
const message = error instanceof Error ? error.message : String(error);
for (const { plugin, apps } of pending) {
evaluated.push({
...plugin,
migratable: false,
migrationBlock: {
code: "app_inventory_unavailable",
apps,
error: message,
},
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but source app inventory could not be read: ${message}`,
});
}
return undefined;
});
const snapshot = await refreshSourceAppInventory(params.requestOptions).catch(
(error: unknown) => {
const message = error instanceof Error ? error.message : String(error);
for (const { plugin, apps } of pending) {
evaluated.push({
...plugin,
migratable: false,
migrationBlock: {
code: "app_inventory_unavailable",
apps,
error: message,
},
message: `Codex plugin "${plugin.pluginName ?? plugin.name}" owns apps, but source app inventory could not be read: ${message}`,
});
}
return undefined;
},
);
if (!snapshot) {
return evaluated;
}

View File

@@ -1396,7 +1396,7 @@ describe("runCopilotAttempt", () => {
const sdk = makeFakeSdk();
const pool = makeFakePool(sdk);
pool.release = vi.fn(async () => {
throw "release failed";
throw toLintErrorObject("release failed", "Non-Error thrown");
});
await expect(runCopilotAttempt(makeParams(), { pool })).rejects.toThrow("release failed");
@@ -1414,7 +1414,7 @@ describe("runCopilotAttempt", () => {
});
const pool = makeFakePool(sdk);
pool.release = vi.fn(async () => {
throw "release failed";
throw toLintErrorObject("release failed", "Non-Error thrown");
});
const result = await runCopilotAttempt(makeParams(), { pool });
@@ -2534,3 +2534,17 @@ describe("runCopilotAttempt", () => {
});
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -115,7 +115,7 @@ export function attachEventBridge(
});
deltaChain = deltaQueue.then(() => {
if (firstDeltaError !== undefined) {
throw firstDeltaError;
throw toLintErrorObject(firstDeltaError, "Non-Error thrown");
}
});
void deltaChain.catch(() => undefined);
@@ -354,3 +354,17 @@ function registerListener<K extends SessionEventType>(
session.off?.(eventType, handler as (...args: unknown[]) => void);
});
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -419,7 +419,7 @@ describe("createCopilotClientPool", () => {
it("normalizes non-Error stop failures during dispose", async () => {
const sdk = makeFake({
stop: () => {
throw "stop-string";
throw toLintErrorObject("stop-string", "Non-Error thrown");
},
});
const pool = createCopilotClientPool({ sdkFactory: sdk.fake });
@@ -485,3 +485,17 @@ describe("createCopilotClientPool", () => {
expect(String(sdk.ctorCalls[0]?.baseDirectory)).toBe(normalizedHome);
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -30,7 +30,7 @@ export async function loadCopilotSdk(options: LoadCopilotSdkOptions = {}): Promi
const promise = doLoad(options);
if (useCache) {
cached = promise.catch((err) => {
cached = promise.catch((err: unknown) => {
cached = undefined;
throw err;
});

View File

@@ -204,7 +204,7 @@ describe("createTraceContextProvider", () => {
const onError = vi.fn();
const provider = createTraceContextProvider({
getTraceparent: () => {
throw "string-boom";
throw toLintErrorObject("string-boom", "Non-Error thrown");
},
onError,
});
@@ -236,3 +236,17 @@ describe("createTraceContextProvider", () => {
expect(getTraceparent).not.toHaveBeenCalled();
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -504,11 +504,11 @@ export function createPairingNotifierService(api: OpenClawPluginApi): OpenClawPl
await notifyPendingPairingRequests({ api, statePath });
};
await tick().catch((err) => {
await tick().catch((err: unknown) => {
api.logger.warn(`device-pair: initial notify poll failed: ${formatErrorMessage(err)}`);
});
notifyInterval = setInterval(() => {
tick().catch((err) => {
tick().catch((err: unknown) => {
api.logger.warn(`device-pair: notify poll failed: ${formatErrorMessage(err)}`);
});
}, NOTIFY_POLL_INTERVAL_MS);

View File

@@ -331,7 +331,7 @@ async function resolveBrowserExecutablePath(config: OpenClawConfig): Promise<str
return await executablePathCache.valuePromise;
}
const valuePromise = resolveBrowserExecutablePathUncached(config).catch((error) => {
const valuePromise = resolveBrowserExecutablePathUncached(config).catch((error: unknown) => {
if (executablePathCache?.valuePromise === valuePromise) {
executablePathCache = null;
}
@@ -405,7 +405,7 @@ async function acquireSharedBrowser(params: {
}
return browser;
})
.catch((error) => {
.catch((error: unknown) => {
if (sharedBrowserState?.browserPromise === browserPromise) {
sharedBrowserState = null;
}

View File

@@ -226,7 +226,7 @@ export class DiffArtifactStore {
this.nextCleanupAt = now + this.cleanupIntervalMs;
const cleanupPromise = this.cleanupExpired()
.catch((error) => {
.catch((error: unknown) => {
this.nextCleanupAt = 0;
this.logger?.warn(`Failed to clean expired diff artifacts: ${String(error)}`);
})

View File

@@ -163,7 +163,7 @@ describe("createDiscordRestClient proxy support", () => {
},
})
.catch((err: unknown) => {
reject(err);
reject(toLintErrorObject(err, "Non-Error rejection"));
server.close();
});
});
@@ -175,3 +175,17 @@ describe("createDiscordRestClient proxy support", () => {
expect(received.body).toContain('"attachments":[{"id":0,"filename":"image.png"}]');
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -153,7 +153,6 @@ export function mapButtonStyle(style?: DiscordComponentButtonStyle): ButtonStyle
return ButtonStyle.Danger;
case "link":
return ButtonStyle.Link;
case "primary":
default:
return ButtonStyle.Primary;
}

View File

@@ -48,7 +48,7 @@ export async function waitForDiscordGatewayStop(
gateway?.disconnect?.();
} finally {
cleanup();
reject(err);
reject(toLintErrorObject(err, "Non-Error rejection"));
}
};
const onAbort = () => {
@@ -73,3 +73,17 @@ export async function waitForDiscordGatewayStop(
params.registerForceStop?.(onForceStop);
});
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -59,7 +59,7 @@ export function queueInitialDiscordAckReaction(params: {
if (!params.shouldSendAckReaction || !params.ackReaction) {
return;
}
void params.reactionAdapter.setReaction(params.ackReaction).catch((err) => {
void params.reactionAdapter.setReaction(params.ackReaction).catch((err: unknown) => {
logAckFailure({
log: logVerbose,
channel: "discord",

View File

@@ -239,7 +239,9 @@ function createGatewayPlugin(params: {
info,
usedFallback: false,
}))
.catch((error) => resolveGatewayInfoWithFallback({ runtime: params.runtime, error }));
.catch((error: unknown) =>
resolveGatewayInfoWithFallback({ runtime: params.runtime, error }),
);
this.gatewayInfo = resolved.info;
this.gatewayInfoUsedFallback = resolved.usedFallback;
}

View File

@@ -47,7 +47,7 @@ export class DiscordMessageListener extends MessageCreateListener {
// Per-session ordering is owned by the message run queue.
void Promise.resolve()
.then(() => this.handler(data, client))
.catch((err) => {
.catch((err: unknown) => {
const logger = this.logger ?? discordEventQueueLog;
logger.error(danger(`discord handler failed: ${String(err)}`));
});
@@ -68,7 +68,7 @@ export class DiscordInteractionListener extends InteractionCreateListener {
// or compaction without blocking later gateway events.
void Promise.resolve()
.then(() => client.handleInteraction(data as Parameters<Client["handleInteraction"]>[0], {}))
.catch((err) => {
.catch((err: unknown) => {
const logger = this.logger ?? discordEventQueueLog;
logger.error(danger(`discord interaction handler failed: ${String(err)}`));
});

View File

@@ -113,7 +113,7 @@ function startAcceptedTypingFeedback(params: {
};
activeFeedback.set(dedupeKey, { channelId, feedback: replyTypingFeedback });
ctx.replyTypingFeedback = replyTypingFeedback;
void replyTypingFeedback.onReplyStart().catch((err) => {
void replyTypingFeedback.onReplyStart().catch((err: unknown) => {
logVerbose(`discord accepted typing feedback failed: ${String(err)}`);
});
return replyTypingFeedback;

View File

@@ -267,7 +267,7 @@ async function fetchDiscordMedia(params: {
fallbackContentType: params.fallbackContentType,
originalFilename: params.originalFilename,
...(signal ? { requestInit: { signal } } : {}),
}).catch((error) => {
}).catch((error: unknown) => {
if (timedOut) {
return new Promise<never>(() => {});
}
@@ -365,8 +365,6 @@ function resolveStickerAssetCandidates(sticker: APIStickerItem): DiscordStickerA
fileName: `${baseName}.json`,
},
];
case StickerFormatType.APNG:
case StickerFormatType.PNG:
default:
return [
{ url: `${DISCORD_STICKER_ASSET_BASE_URL}/${sticker.id}.png`, fileName: `${baseName}.png` },

View File

@@ -727,7 +727,9 @@ describe("runDiscordGatewayLifecycle", () => {
waitForDiscordGatewayStopMock.mockImplementationOnce(
(params: WaitForDiscordGatewayStopParams) =>
new Promise<void>((_resolve, reject) => {
params.registerForceStop?.((err) => reject(err));
params.registerForceStop?.((err) =>
reject(toLintErrorObject(err, "Non-Error rejection")),
);
gateway.isConnected = false;
emitter.emit("debug", "Gateway websocket opened");
}),
@@ -755,3 +757,17 @@ describe("runDiscordGatewayLifecycle", () => {
}
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -365,7 +365,7 @@ export async function writeVoiceWavFile(
function scheduleTempCleanup(tempDir: string, delayMs: number = 30 * 60 * 1000): void {
const timer = setTimeout(() => {
fs.rm(tempDir, { recursive: true, force: true }).catch((err) => {
fs.rm(tempDir, { recursive: true, force: true }).catch((err: unknown) => {
if (shouldLogVerbose()) {
logVerbose(`discord voice: temp cleanup failed for ${tempDir}: ${formatErrorMessage(err)}`);
}

View File

@@ -221,7 +221,9 @@ function isUnknownDiscordVoiceStateError(err: unknown): boolean {
function startAutoJoin(manager: Pick<DiscordVoiceManager, "autoJoin">) {
void manager
.autoJoin()
.catch((err) => logger.warn(`discord voice: autoJoin failed: ${formatErrorMessage(err)}`));
.catch((err: unknown) =>
logger.warn(`discord voice: autoJoin failed: ${formatErrorMessage(err)}`),
);
}
function resolveDiscordVoiceAgentRoute(params: {
@@ -782,7 +784,7 @@ export class DiscordVoiceManager {
}
const speakingHandler: ((userId: string) => void) | undefined = (userId: string) => {
void this.handleSpeakingStart(entry, userId).catch((err) => {
void this.handleSpeakingStart(entry, userId).catch((err: unknown) => {
logger.warn(`discord voice: capture failed: ${formatErrorMessage(err)}`);
});
};
@@ -1134,7 +1136,7 @@ export class DiscordVoiceManager {
return;
}
this.followUsersReconcileTimer = setInterval(() => {
void this.reconcileFollowedUsers("interval").catch((err) => {
void this.reconcileFollowedUsers("interval").catch((err: unknown) => {
logger.warn(`discord voice: follow user reconciliation failed: ${formatErrorMessage(err)}`);
});
}, FOLLOW_USERS_RECONCILE_INTERVAL_MS);
@@ -1176,7 +1178,7 @@ export class DiscordVoiceManager {
this.params.client.rest,
plan.guildId,
userId,
).catch((err) => {
).catch((err: unknown) => {
if (!isUnknownDiscordVoiceStateError(err)) {
logger.warn(
`discord voice: follow user reconcile skipped transient voice state error guild=${plan.guildId} user=${userId} reason=${reason}: ${formatErrorMessage(err)}`,
@@ -1415,7 +1417,7 @@ export class DiscordVoiceManager {
this.params.client.rest,
guildId,
this.botUserId,
).catch((err) => {
).catch((err: unknown) => {
if (!isUnknownDiscordVoiceStateError(err)) {
logger.warn(
`discord voice: follow reconcile skipped transient bot voice state error guild=${guildId} reason=${reason}: ${formatErrorMessage(err)}`,
@@ -1473,13 +1475,17 @@ export class DiscordVoiceManager {
private enqueueProcessing(entry: VoiceSessionEntry, task: () => Promise<void>) {
entry.processingQueue = entry.processingQueue
.then(task)
.catch((err) => logger.warn(`discord voice: processing failed: ${formatErrorMessage(err)}`));
.catch((err: unknown) =>
logger.warn(`discord voice: processing failed: ${formatErrorMessage(err)}`),
);
}
private enqueuePlayback(entry: VoiceSessionEntry, task: () => Promise<void>) {
entry.playbackQueue = entry.playbackQueue
.then(task)
.catch((err) => logger.warn(`discord voice: playback failed: ${formatErrorMessage(err)}`));
.catch((err: unknown) =>
logger.warn(`discord voice: playback failed: ${formatErrorMessage(err)}`),
);
}
private clearCaptureFinalizeTimer(entry: VoiceSessionEntry, userId: string, generation?: number) {
@@ -1789,7 +1795,7 @@ export class DiscordVoiceManager {
return;
}
void this.recoverFromDecryptFailures(entry)
.catch((recoverErr) =>
.catch((recoverErr: unknown) =>
logger.warn(`discord voice: decrypt recovery failed: ${formatErrorMessage(recoverErr)}`),
)
.finally(() => {

View File

@@ -15,7 +15,7 @@ async function loadPdfEngine(): Promise<PdfEngine> {
if (!pdfEnginePromise) {
pdfEnginePromise = import("clawpdf")
.then(({ createEngine }) => createEngine())
.catch((err) => {
.catch((err: unknown) => {
pdfEnginePromise = null;
throw new Error("Dependency clawpdf is required for PDF extraction", {
cause: err,

View File

@@ -112,7 +112,6 @@ export function resolveFeishuGroupSession(params: {
})
: buildFeishuConversationId({ chatId, scope: "group_sender", senderOpenId });
break;
case "group":
default:
peerId = chatId;
break;

View File

@@ -918,7 +918,7 @@ export async function handleFeishuMessage(params: {
replyToMessageId: replyTargetMessageId,
replyInThread: isGroup ? (groupSession?.replyInThread ?? false) : false,
accountId: account.accountId,
}).catch((err) => {
}).catch((err: unknown) => {
log(`feishu[${account.accountId}]: failed to send ACP init error reply: ${String(err)}`);
});
return;

View File

@@ -37,7 +37,6 @@ export function buildFeishuConversationId(params: {
return `${chatId}:topic:${topicId}`;
}
return senderOpenId ? `${chatId}:sender:${senderOpenId}` : chatId;
case "group":
default:
return chatId;
}

View File

@@ -272,7 +272,7 @@ function registerEventHandlers(
const error = runtime?.error ?? console.error;
const runFeishuHandler = async (params: { task: () => Promise<void>; errorMessage: string }) => {
if (fireAndForget) {
void params.task().catch((err) => {
void params.task().catch((err: unknown) => {
error(`${params.errorMessage}: ${String(err)}`);
});
return;
@@ -417,7 +417,7 @@ function registerEventHandlers(
accountId,
});
if (fireAndForget) {
promise.catch((err) => {
promise.catch((err: unknown) => {
error(`feishu[${accountId}]: error handling card action: ${String(err)}`);
});
} else {

View File

@@ -138,7 +138,7 @@ export function createFeishuBotMenuHandler(params: {
}
return await handleLegacyMenu();
})
.catch(async (err) => {
.catch(async (err: unknown) => {
if (isFeishuRetryableSyntheticEventError(err)) {
await forgetProcessedFeishuMessage(syntheticMessageId, accountId, log);
} else {
@@ -150,7 +150,7 @@ export function createFeishuBotMenuHandler(params: {
releaseFeishuMessageProcessing(syntheticMessageId, accountId);
});
if (fireAndForget) {
promise.catch((err) => {
promise.catch((err: unknown) => {
error(`feishu[${accountId}]: error handling bot menu event: ${String(err)}`);
});
return;

View File

@@ -35,7 +35,7 @@ export function createFeishuDriveCommentNoticeHandler(params: {
const getBotOpenId = params.getBotOpenId ?? ((id) => botOpenIds.get(id));
const runFeishuHandler = async (task: () => Promise<void>) => {
const promise = task().catch((err) => {
const promise = task().catch((err: unknown) => {
error(`feishu[${accountId}]: error handling drive comment notice: ${String(err)}`);
});
if (!fireAndForget) {

View File

@@ -331,7 +331,7 @@ async function resolveParsedCommentContent(params: {
resolvedObjToken: objToken,
};
})
.catch((error) => {
.catch((error: unknown) => {
params.logger?.(
`feishu[${params.accountId}]: wiki link resolution threw token=${link.wikiNodeToken} error=${formatErrorMessage(error)}`,
);
@@ -485,7 +485,7 @@ async function requestFeishuOpenApi<T>(params: {
{ timeoutMs: params.timeoutMs },
)
.then((resolved) => (resolved.status === "resolved" ? resolved.value : null))
.catch((error) => {
.catch((error: unknown) => {
params.logger?.(`${params.errorLabel}: ${formatErrorDetails(error)}`);
return null;
});

View File

@@ -329,7 +329,7 @@ export function createFeishuMessageReceiveHandler({
await inboundDebouncer.enqueue(event);
};
if (fireAndForget) {
void processMessage().catch((err) => {
void processMessage().catch((err: unknown) => {
releaseFeishuMessageProcessing(messageDedupeKey, accountId);
error(`feishu[${accountId}]: error handling message: ${String(err)}`);
});

View File

@@ -79,7 +79,7 @@ async function waitForSlowBodyTimeoutResponse(
socket.setEncoding("utf8");
socket.on("error", () => {});
socket.on("data", (chunk) => {
response += chunk;
response += chunk.toString();
if (response.includes("Request body timeout")) {
clearTimeout(failTimer);
socket.destroy();
@@ -127,7 +127,7 @@ async function waitForOversizedBodyResponse(url: string): Promise<string> {
socket.setEncoding("utf8");
socket.on("data", (chunk) => {
response += chunk;
response += chunk.toString();
if (response.includes("Payload too large")) {
finish(response);
}

View File

@@ -18,7 +18,6 @@ function resolveFeishuParentConversationCandidates(rawId: string): string[] {
case "group_topic":
case "group_sender":
return [parsed.chatId];
case "group":
default:
return [];
}

View File

@@ -520,7 +520,7 @@ export class FeishuStreamingSession {
.then(async ({ release }) => {
await release();
})
.catch((e) => this.log?.(`Note update failed: ${String(e)}`));
.catch((e: unknown) => this.log?.(`Note update failed: ${String(e)}`));
}
async close(finalText?: string, options?: { note?: string }): Promise<boolean> {
@@ -584,7 +584,7 @@ export class FeishuStreamingSession {
.then(async ({ release }) => {
await release();
})
.catch((e) => this.log?.(`Close failed: ${String(e)}`));
.catch((e: unknown) => this.log?.(`Close failed: ${String(e)}`));
const finalState = this.state;
this.state = null;
this.pendingText = null;

View File

@@ -144,7 +144,7 @@ export function handleGoogleMeetRealtimeConsultToolCall(params: {
});
params.session.submitToolResult(callId, result);
})
.catch((error: Error) => {
.catch((error: unknown) => {
params.onTalkEvent?.({
type: "tool.error",
callId,

View File

@@ -277,7 +277,7 @@ export async function startNodeAgentAudioBridge(params: {
),
);
})
.catch((error) => {
.catch((error: unknown) => {
params.logger.warn(`[google-meet] node agent TTS failed: ${formatErrorMessage(error)}`);
});
};
@@ -557,7 +557,7 @@ export async function startNodeRealtimeAudioBridge(params: {
},
timeoutMs: 5_000,
})
.catch((error) => {
.catch((error: unknown) => {
params.logger.warn(
`[google-meet] node audio output failed: ${formatErrorMessage(error)}`,
);
@@ -580,7 +580,7 @@ export async function startNodeRealtimeAudioBridge(params: {
},
timeoutMs: 5_000,
})
.catch((error) => {
.catch((error: unknown) => {
params.logger.warn(
`[google-meet] node audio clear failed: ${formatErrorMessage(error)}`,
);

View File

@@ -696,7 +696,7 @@ export async function startCommandAgentAudioBridge(params: {
});
endTalkTurn();
})
.catch((error) => {
.catch((error: unknown) => {
params.logger.warn(`[google-meet] agent TTS failed: ${formatErrorMessage(error)}`);
});
};

View File

@@ -68,7 +68,7 @@ async function createConnectedGatewayClient(
reject(new Error("gateway event loop readiness timeout"));
}
})
.catch((err) => {
.catch((err: unknown) => {
clearTimeout(timer);
reject(err instanceof Error ? err : new Error(String(err)));
});

View File

@@ -140,7 +140,7 @@ describeLive("google plugin live", () => {
}
}
if (lastError) {
throw lastError;
throw toLintErrorObject(lastError, "Non-Error thrown");
}
expect(result?.provider).toBe("gemini");
@@ -177,3 +177,17 @@ describeLive("google plugin live", () => {
});
}, 120_000);
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -637,7 +637,12 @@ describe("google transport stream", () => {
(_url: string, init?: RequestInit) =>
new Promise<Response>((_resolve, reject) => {
init?.signal?.addEventListener("abort", () => {
reject(init.signal?.reason ?? new Error("aborted"));
reject(
toLintErrorObject(
init.signal?.reason ?? new Error("aborted"),
"Non-Error rejection",
),
);
});
}),
)
@@ -1984,3 +1989,17 @@ describe("google transport stream", () => {
]);
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -287,7 +287,7 @@ export function createGoogleChatWebhookRequestHandler(params: {
const dispatchTarget = selectedTarget;
dispatchTarget.statusSink?.({ lastInboundAt: Date.now() });
params.processEvent(parsedEvent, dispatchTarget).catch((err) => {
params.processEvent(parsedEvent, dispatchTarget).catch((err: unknown) => {
dispatchTarget.runtime.error?.(
`[${dispatchTarget.account.accountId}] Google Chat webhook failed: ${String(err)}`,
);

View File

@@ -132,7 +132,7 @@ describe("monitorIMessageProvider watch.subscribe startup retry", () => {
const monitorErrorPromise = monitorIMessageProvider({
config: { channels: { imessage: {} } } as never,
runtime: runtime as never,
}).catch((error) => error);
}).catch((error: unknown) => error);
await vi.runAllTimersAsync();
const monitorError = await monitorErrorPromise;

View File

@@ -1036,7 +1036,7 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
runtime,
onNotification: (msg) => {
if (msg.method === "message") {
void handleMessage(msg.params).catch((err) => {
void handleMessage(msg.params).catch((err: unknown) => {
runtime.error?.(`imessage: handler failed: ${String(err)}`);
});
} else if (msg.method === "error") {

View File

@@ -376,7 +376,7 @@ export async function connectIrcClient(options: IrcClientOptions): Promise<IrcCl
text,
rawLine,
}),
).catch((error) => {
).catch((error: unknown) => {
fail(error);
});
}

View File

@@ -615,6 +615,20 @@ export async function handleLineWebhookEvents(
}
}
if (firstError) {
throw firstError;
throw toLintErrorObject(firstError, "Non-Error thrown");
}
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -437,7 +437,7 @@ export async function monitorLineProvider(
logVerbose(`line: received ${body.events.length} webhook events`);
void Promise.resolve()
.then(() => match.target.bot.handleWebhook(body))
.catch((err) => {
.catch((err: unknown) => {
match.target.runtime.error?.(
danger(`line webhook dispatch failed: ${String(err)}`),
);

View File

@@ -224,7 +224,7 @@ async function pushLineMessages(
});
if (behavior.errorContext) {
await pushRequest.catch((err) => {
await pushRequest.catch((err: unknown) => {
logLineHttpError(err, behavior.errorContext!);
throw err;
});
@@ -301,7 +301,6 @@ export async function sendMessageLine(
case "audio":
messages.push(createAudioMessage(mediaUrl, opts.durationMs ?? 60000));
break;
case "image":
default:
// Backward compatibility: keep image as default when media kind is unspecified.
{

View File

@@ -128,7 +128,7 @@ export function createLineNodeWebhookHandler(params: {
logVerbose(`line: received ${body.events.length} webhook events`);
void Promise.resolve()
.then(() => params.bot.handleWebhook(body))
.catch((err) => logLineWebhookDispatchError(params.runtime, err));
.catch((err: unknown) => logLineWebhookDispatchError(params.runtime, err));
}
} catch (err) {
await receiveContext?.nack(err);

View File

@@ -93,7 +93,7 @@ export function createLineWebhookMiddleware(
logVerbose(`line: received ${body.events.length} webhook events`);
void Promise.resolve()
.then(() => onEvents(body))
.catch((err) => logLineWebhookDispatchError(runtime, err));
.catch((err: unknown) => logLineWebhookDispatchError(runtime, err));
}
} catch (err) {
await receiveContext?.nack(err);

View File

@@ -217,7 +217,7 @@ export function wrapLmstudioInferencePreload(ctx: ProviderWrapStreamFnContext):
() => {
recordPreloadSuccess(preloadKey);
},
(error) => {
(error: unknown) => {
const entry = recordPreloadFailure(preloadKey, Date.now());
throw Object.assign(new Error("preload-failed"), {
cause: error,

View File

@@ -583,7 +583,12 @@ describe("createEmbeddedLobsterRunner", () => {
);
ctx?.signal?.addEventListener("abort", () => {
clearTimeout(timeout);
reject(ctx.signal?.reason ?? new Error("aborted"));
reject(
toLintErrorObject(
ctx.signal?.reason ?? new Error("aborted"),
"Non-Error rejection",
),
);
});
}),
),
@@ -605,3 +610,17 @@ describe("createEmbeddedLobsterRunner", () => {
).rejects.toThrow(/timed out|aborted/);
});
});
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -286,9 +286,9 @@ async function withTimeout<T>(
clearTimeout(timer);
resolve(value);
},
(error) => {
(error: unknown) => {
clearTimeout(timer);
reject(error);
reject(toLintErrorObject(error, "Non-Error rejection"));
},
);
});
@@ -392,3 +392,17 @@ export function createEmbeddedLobsterRunner(options?: {
},
};
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -259,7 +259,7 @@ export class FileBackedMatrixSyncStore extends MemoryStore {
}
this.persistTimer = setTimeout(() => {
this.persistTimer = null;
void this.flush().catch((err) => {
void this.flush().catch((err: unknown) => {
LogService.warn("MatrixFileSyncStore", "Failed to persist Matrix sync store:", err);
});
}, PERSIST_DEBOUNCE_MS);

View File

@@ -112,7 +112,7 @@ function createHarness(params?: {
const runDetachedTask = vi.fn((_label: string, task: () => Promise<void>) => {
const promise = Promise.resolve()
.then(task)
.catch((error) => {
.catch((error: unknown) => {
throw error;
})
.finally(() => {

View File

@@ -230,7 +230,7 @@ export function registerMatrixMonitorEvents(params: {
}
return Promise.resolve()
.then(task)
.catch((error) => {
.catch((error: unknown) => {
logVerboseMessage(`matrix: ${label} failed (${String(error)})`);
});
};

View File

@@ -905,12 +905,14 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
if (!isPollEvent) {
return null;
}
pollSnapshotPromise ??= fetchMatrixPollSnapshot(client, roomId, event).catch((err) => {
logVerboseMessage(
`matrix: failed resolving poll snapshot room=${roomId} id=${event.event_id ?? "unknown"}: ${String(err)}`,
);
return null;
});
pollSnapshotPromise ??= fetchMatrixPollSnapshot(client, roomId, event).catch(
(err: unknown) => {
logVerboseMessage(
`matrix: failed resolving poll snapshot room=${roomId} id=${event.event_id ?? "unknown"}: ${String(err)}`,
);
return null;
},
);
return await pollSnapshotPromise;
};
@@ -1481,7 +1483,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
.then(({ reactMatrixMessage }) =>
reactMatrixMessage(roomId, messageId, ackReaction, client),
)
.catch((err) => {
.catch((err: unknown) => {
logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`);
});
}
@@ -1489,7 +1491,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
if (messageId) {
loadMatrixSendModule()
.then(({ sendReadReceiptMatrix }) => sendReadReceiptMatrix(roomId, messageId, client))
.catch((err) => {
.catch((err: unknown) => {
logVerboseMessage(
`matrix: read receipt failed room=${roomId} id=${messageId}: ${String(err)}`,
);

View File

@@ -281,7 +281,7 @@ export async function createMatrixInboundEventDeduper(params: {
},
ttlMs > 0 ? { ttlMs } : undefined,
)
.catch((err) => {
.catch((err: unknown) => {
LogService.warn(
"MatrixInboundDedupe",
"Failed persisting Matrix inbound dedupe entry:",

View File

@@ -494,7 +494,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
auth,
env: process.env,
abortSignal: opts.abortSignal,
}).catch((err) => {
}).catch((err: unknown) => {
logVerboseMessage(`matrix: failed to backfill deviceId after startup (${String(err)})`);
});

View File

@@ -136,12 +136,14 @@ export async function handleInboundMatrixReaction(params: {
return;
}
const targetEvent = await params.client.getEvent(params.roomId, reaction.eventId).catch((err) => {
params.logVerboseMessage(
`matrix: failed resolving reaction target room=${params.roomId} id=${reaction.eventId}: ${String(err)}`,
);
return null;
});
const targetEvent = await params.client
.getEvent(params.roomId, reaction.eventId)
.catch((err: unknown) => {
params.logVerboseMessage(
`matrix: failed resolving reaction target room=${params.roomId} id=${reaction.eventId}: ${String(err)}`,
);
return null;
});
const targetSender =
targetEvent && typeof targetEvent.sender === "string" ? targetEvent.sender.trim() : "";
if (!targetSender) {

View File

@@ -56,12 +56,14 @@ export function createMatrixReplyContextResolver(params: {
return cached;
}
const event = await params.client.getEvent(input.roomId, input.eventId).catch((err) => {
params.logVerboseMessage(
`matrix: failed resolving reply context room=${input.roomId} id=${input.eventId}: ${String(err)}`,
);
return null;
});
const event = await params.client
.getEvent(input.roomId, input.eventId)
.catch((err: unknown) => {
params.logVerboseMessage(
`matrix: failed resolving reply context room=${input.roomId} id=${input.eventId}: ${String(err)}`,
);
return null;
});
if (!event) {
// Do not cache failures so transient errors can be retried on the next
// message that references the same event.

View File

@@ -9,7 +9,7 @@ export function createMatrixMonitorTaskRunner(params: {
const runDetachedTask = (label: string, task: () => Promise<void>): Promise<void> => {
const trackedTask: Promise<void> = Promise.resolve()
.then(task)
.catch((error) => {
.catch((error: unknown) => {
const message = String(error);
params.logVerboseMessage(`matrix: ${label} failed (${message})`);
params.logger.warn("matrix background task failed", {

View File

@@ -74,7 +74,7 @@ export function createMatrixThreadContextResolver(params: {
const rootEvent = await params.client
.getEvent(input.roomId, input.threadRootId)
.catch((err) => {
.catch((err: unknown) => {
params.logVerboseMessage(
`matrix: failed resolving thread root room=${input.roomId} id=${input.threadRootId}: ${String(err)}`,
);

View File

@@ -628,7 +628,7 @@ export function createMatrixVerificationEventRouter(params: {
routeTask,
);
} else {
void routeTask().catch((err) => {
void routeTask().catch((err: unknown) => {
params.logVerboseMessage(`matrix: failed routing verification event: ${String(err)}`);
});
}

View File

@@ -11,7 +11,11 @@ export async function clearAllIndexedDbState(params?: { databasePrefix?: string
new Promise<void>((resolve, reject) => {
const req = indexedDB.deleteDatabase(name);
req.addEventListener("success", () => resolve(), { once: true });
req.addEventListener("error", () => reject(req.error), { once: true });
req.addEventListener(
"error",
() => reject(toLintErrorObject(req.error, "Non-Error rejection")),
{ once: true },
);
req.addEventListener("blocked", () => resolve(), { once: true });
}),
),
@@ -43,9 +47,17 @@ export async function seedDatabase(params: {
db.close();
resolve();
});
tx.addEventListener("error", () => reject(tx.error), { once: true });
tx.addEventListener(
"error",
() => reject(toLintErrorObject(tx.error, "Non-Error rejection")),
{ once: true },
);
});
req.addEventListener("error", () => reject(req.error), { once: true });
req.addEventListener(
"error",
() => reject(toLintErrorObject(req.error, "Non-Error rejection")),
{ once: true },
);
});
}
@@ -82,9 +94,35 @@ export async function readDatabaseRecords(params: {
values = valuesReq.result;
maybeResolve();
});
keysReq.addEventListener("error", () => reject(keysReq.error), { once: true });
valuesReq.addEventListener("error", () => reject(valuesReq.error), { once: true });
keysReq.addEventListener(
"error",
() => reject(toLintErrorObject(keysReq.error, "Non-Error rejection")),
{ once: true },
);
valuesReq.addEventListener(
"error",
() => reject(toLintErrorObject(valuesReq.error, "Non-Error rejection")),
{ once: true },
);
});
req.addEventListener("error", () => reject(req.error), { once: true });
req.addEventListener(
"error",
() => reject(toLintErrorObject(req.error, "Non-Error rejection")),
{ once: true },
);
});
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -97,7 +97,11 @@ function parseSnapshotPayload(data: string): IdbDatabaseSnapshot[] | null {
function idbReq<T>(req: IDBRequest<T>): Promise<T> {
return new Promise((resolve, reject) => {
req.addEventListener("success", () => resolve(req.result), { once: true });
req.addEventListener("error", () => reject(req.error), { once: true });
req.addEventListener(
"error",
() => reject(toLintErrorObject(req.error, "Non-Error rejection")),
{ once: true },
);
});
}
@@ -117,7 +121,9 @@ async function dumpIndexedDatabases(databasePrefix?: string): Promise<IdbDatabas
const db: IDBDatabase = await new Promise((resolve, reject) => {
const r = idb.open(name, version);
r.addEventListener("success", () => resolve(r.result), { once: true });
r.addEventListener("error", () => reject(r.error), { once: true });
r.addEventListener("error", () => reject(toLintErrorObject(r.error, "Non-Error rejection")), {
once: true,
});
});
const stores: IdbStoreSnapshot[] = [];
@@ -203,7 +209,9 @@ async function restoreIndexedDatabases(snapshot: IdbDatabaseSnapshot[]): Promise
},
{ once: true },
);
r.addEventListener("error", () => reject(r.error), { once: true });
r.addEventListener("error", () => reject(toLintErrorObject(r.error, "Non-Error rejection")), {
once: true,
});
});
}
}
@@ -284,3 +292,17 @@ export async function persistIdbToDisk(params?: {
LogService.warn("IdbPersistence", "Failed to persist IndexedDB snapshot:", err);
}
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -394,7 +394,7 @@ export class MatrixVerificationManager {
.then(() => {
this.touchVerificationSession(session);
})
.catch((err) => {
.catch((err: unknown) => {
session.acceptRequested = false;
session.error = formatMatrixErrorMessage(err);
this.touchVerificationSession(session);
@@ -516,7 +516,7 @@ export class MatrixVerificationManager {
.then(() => {
this.touchVerificationSession(session);
})
.catch((err) => {
.catch((err: unknown) => {
session.error = formatMatrixErrorMessage(err);
this.touchVerificationSession(session);
});
@@ -545,7 +545,7 @@ export class MatrixVerificationManager {
.then(() => {
this.touchVerificationSession(session);
})
.catch((err) => {
.catch((err: unknown) => {
session.error = formatMatrixErrorMessage(err);
this.touchVerificationSession(session);
});

View File

@@ -35,10 +35,24 @@ export async function awaitMatrixStartupWithAbort<T>(
abortSignal.removeEventListener("abort", onAbort);
resolve(value);
},
(error) => {
(error: unknown) => {
abortSignal.removeEventListener("abort", onAbort);
reject(error);
reject(toLintErrorObject(error, "Non-Error rejection"));
},
);
});
}
function toLintErrorObject(value: unknown, fallbackMessage: string): Error {
if (value instanceof Error) {
return value;
}
if (typeof value === "string") {
return new Error(value);
}
const error = new Error(fallbackMessage, { cause: value });
if ((typeof value === "object" && value !== null) || typeof value === "function") {
Object.assign(error, value);
}
return error;
}

View File

@@ -368,7 +368,7 @@ export async function createMatrixThreadBindingManager(params: {
};
const persist = async () => await enqueuePersist();
const persistSafely = (reason: string, bindings?: MatrixThreadBindingRecord[]) => {
void enqueuePersist(bindings).catch((err) => {
void enqueuePersist(bindings).catch((err: unknown) => {
params.logVerboseMessage?.(
`matrix: failed persisting thread bindings account=${params.accountId} action=${reason}: ${String(err)}`,
);
@@ -383,7 +383,7 @@ export async function createMatrixThreadBindingManager(params: {
await persist();
}
await migrationStore.register(legacyImportKey, { importedAt: Date.now() });
await fs.rm(legacyFilePath, { force: true }).catch((err) => {
await fs.rm(legacyFilePath, { force: true }).catch((err: unknown) => {
params.logVerboseMessage?.(
`matrix: failed removing migrated legacy thread bindings account=${params.accountId}: ${String(err)}`,
);
@@ -693,7 +693,7 @@ export async function createMatrixThreadBindingManager(params: {
await sendFarewellMessages(removed, (record) =>
reasonByBindingKey.get(resolveBindingKey(record)),
);
})().catch((err) => {
})().catch((err: unknown) => {
params.logVerboseMessage?.(
`matrix: failed auto-unbinding expired bindings account=${params.accountId}: ${String(err)}`,
);

View File

@@ -2165,7 +2165,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
client,
commands,
log: (msg) => runtime.log?.(msg),
}).catch((err) => {
}).catch((err: unknown) => {
runtime.error?.(`mattermost: slash cleanup failed: ${String(err)}`);
});
};

View File

@@ -500,8 +500,8 @@ export function formatBackfillDiaryDate(isoDay: string, _timezone?: string): str
}
async function assertSafeDreamsPath(dreamsPath: string): Promise<void> {
const stat = await fs.lstat(dreamsPath).catch((err: NodeJS.ErrnoException) => {
if (err.code === "ENOENT") {
const stat = await fs.lstat(dreamsPath).catch((err: unknown) => {
if (extractErrorCode(err) === "ENOENT") {
return null;
}
throw err;

View File

@@ -1,6 +1,7 @@
import { randomUUID } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { extractErrorCode } from "openclaw/plugin-sdk/error-runtime";
type DreamingArtifactsAuditIssue = {
severity: "warn" | "error";
@@ -87,8 +88,8 @@ function buildArchiveTimestamp(now: Date): string {
}
async function ensureArchivablePath(targetPath: string): Promise<"file" | "dir" | null> {
const stat = await fs.lstat(targetPath).catch((err: NodeJS.ErrnoException) => {
if (err.code === "ENOENT") {
const stat = await fs.lstat(targetPath).catch((err: unknown) => {
if (extractErrorCode(err) === "ENOENT") {
return null;
}
throw err;

View File

@@ -860,7 +860,7 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
}
scheduleStartupCronRetry();
})
.catch((err) => {
.catch((err: unknown) => {
if (disposed) {
return;
}
@@ -877,7 +877,7 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
return;
}
runtimeCronReconcileTimer = setInterval(() => {
void reconcileManagedDreamingCron({ reason: "runtime" }).catch((err) => {
void reconcileManagedDreamingCron({ reason: "runtime" }).catch((err: unknown) => {
api.logger.error(`memory-core: dreaming cron reconcile failed: ${formatErrorMessage(err)}`);
});
}, RUNTIME_CRON_RECONCILE_INTERVAL_MS);

View File

@@ -8,7 +8,7 @@ export function startAsyncSearchSync(params: {
if (!params.enabled || (!params.dirty && !params.sessionsDirty)) {
return;
}
void params.sync({ reason: "search" }).catch((err) => {
void params.sync({ reason: "search" }).catch((err: unknown) => {
params.onError(err);
});
}

Some files were not shown because too many files have changed in this diff Show More