From f5eca3f84cbf0ce63ae0ca709856242ac9284722 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 31 May 2026 09:32:33 +0100 Subject: [PATCH] chore(lint): enable object and reassignment rules --- .oxlintrc.json | 3 + .../browser/pw-session.connections.test.ts | 6 +- ...ge-for-targetid.extension-fallback.test.ts | 3 +- .../src/browser/pw-tools-core.responses.ts | 3 +- extensions/codex/src/app-server/client.ts | 3 +- .../codex/src/app-server/computer-use.ts | 3 +- .../codex/src/app-server/run-attempt.test.ts | 101 +++++++++--------- .../codex/src/app-server/run-attempt.ts | 58 ++++++---- .../discord/src/approval-handler.runtime.ts | 12 +-- .../discord/src/monitor.gateway.test.ts | 6 +- .../src/monitor/gateway-plugin.test.ts | 2 +- extensions/discord/src/monitor/provider.ts | 2 +- extensions/discord/src/resolve-channels.ts | 4 +- .../discord/src/voice/manager.e2e.test.ts | 5 +- extensions/discord/src/voice/manager.ts | 16 +-- extensions/feishu/src/async.ts | 9 +- extensions/feishu/src/bot.ts | 2 +- .../feishu/src/docx-batch-insert.test.ts | 2 +- extensions/feishu/src/monitor.transport.ts | 3 +- .../file-transfer/src/tools/dir-fetch-tool.ts | 9 +- extensions/google-meet/src/realtime-node.ts | 88 +++++++-------- extensions/google-meet/src/realtime.ts | 90 ++++++++-------- extensions/googlechat/src/actions.ts | 2 +- extensions/googlechat/src/channel.adapters.ts | 8 +- ...nitor.shutdown.unhandled-rejection.test.ts | 2 +- extensions/imessage/src/send.ts | 4 +- extensions/line/src/card-command.ts | 3 +- extensions/matrix/src/matrix/format.ts | 7 +- .../matrix/src/matrix/monitor/events.test.ts | 6 +- .../matrix/src/matrix/monitor/handler.ts | 2 +- .../matrix/src/matrix/monitor/task-runner.ts | 3 +- extensions/memory-core/src/dreaming-phases.ts | 2 +- .../memory-core/src/memory/search-manager.ts | 3 +- .../src/monitor-handler.adaptive-card.test.ts | 6 +- .../src/monitor-handler.test-helpers.ts | 5 +- extensions/msteams/src/session-route.ts | 2 +- .../openai/realtime-voice-provider.test.ts | 3 +- extensions/openai/realtime-voice-provider.ts | 3 +- .../src/engine/gateway/inbound-attachments.ts | 3 +- .../engine/messaging/streaming-media-send.ts | 2 +- .../src/engine/messaging/target-parser.ts | 2 +- extensions/signal/src/client.ts | 6 +- .../message-handler/prepare-thread-context.ts | 12 ++- extensions/slack/src/monitor/provider.ts | 2 +- extensions/slack/src/monitor/slash.test.ts | 2 +- extensions/slack/src/outbound-adapter.test.ts | 3 +- extensions/slack/src/send.upload.test.ts | 7 +- extensions/talk-voice/index.test.ts | 3 +- .../telegram/src/bot-message-context.ts | 6 +- .../telegram/src/bot-message-dispatch.ts | 2 +- .../telegram/src/bot-native-commands.ts | 4 +- extensions/telegram/src/draft-stream.ts | 11 +- extensions/telegram/src/lane-delivery.test.ts | 3 +- extensions/telegram/src/thread-bindings.ts | 2 +- extensions/tlon/src/monitor/index.ts | 12 +-- extensions/tlon/src/settings.ts | 2 +- extensions/twitch/src/probe.ts | 31 +++--- extensions/twitch/src/twitch-client.ts | 3 +- .../voice-call/src/webhook/tailscale.ts | 3 +- extensions/whatsapp/src/inbound/send-api.ts | 3 +- extensions/workboard/src/store.test.ts | 3 +- extensions/zalo/src/actions.ts | 2 +- extensions/zalo/src/setup-core.ts | 4 +- extensions/zalouser/src/channel.adapters.ts | 10 +- extensions/zalouser/src/channel.ts | 6 +- extensions/zalouser/src/monitor.ts | 3 +- extensions/zalouser/src/setup-surface.ts | 4 +- extensions/zalouser/src/text-styles.ts | 2 +- packages/agent-core/src/harness/env/nodejs.ts | 8 +- packages/gateway-client/src/client.ts | 3 +- .../src/host/backend-config.ts | 2 +- packages/speech-core/src/tts.ts | 6 +- scripts/crabbox-wrapper.mjs | 24 +++-- scripts/dev/test-device-pair-telegram.ts | 4 +- scripts/e2e/lib/fixtures/plugins.mjs | 8 +- scripts/e2e/mcp-websocket-open.ts | 3 +- scripts/e2e/telegram-user-crabbox-proof.ts | 3 +- scripts/e2e/telegram-user-credential-io.ts | 3 +- scripts/package-openclaw-for-docker.mjs | 3 +- scripts/run-additional-boundary-checks.mjs | 6 +- scripts/run-node.mjs | 6 +- scripts/test-docker-all.mjs | 3 +- scripts/test-projects.test-support.mjs | 3 +- scripts/update-clawtributors.ts | 2 +- scripts/watch-node.mjs | 6 +- src/acp/translator.stop-reason.test.ts | 3 +- src/agents/acp-spawn.ts | 2 +- src/agents/agent-tools.ts | 3 +- src/agents/bash-process-registry.ts | 3 +- src/agents/bash-tools.process.ts | 6 +- .../context-engine-maintenance.ts | 3 +- src/agents/embedded-agent-runner/run.ts | 3 +- .../attempt.model-diagnostic-events.test.ts | 2 +- .../run/attempt.queue-message.ts | 6 +- .../embedded-agent-runner/run/attempt.ts | 11 +- .../run/auth-controller.ts | 3 +- .../tool-result-context-guard.test.ts | 2 +- ...edded-agent-subscribe.handlers.messages.ts | 4 +- src/agents/harness/native-hook-relay.ts | 12 +-- src/agents/minimax.live.test.ts | 4 +- src/agents/model-provider-auth.ts | 6 +- src/agents/provider-local-service.ts | 6 +- src/agents/sessions/model-registry.test.ts | 2 +- src/agents/sessions/sdk.ts | 4 +- src/agents/sessions/session-manager.ts | 7 +- src/agents/subagent-announce.ts | 2 +- src/agents/tool-display.ts | 4 +- src/agents/tool-loop-detection.ts | 2 +- src/agents/tool-search.ts | 16 ++- src/agents/tools/common.ts | 3 +- src/agents/tools/nodes-utils.ts | 4 +- src/auto-reply/inbound-debounce.ts | 4 +- .../reply/agent-runner-execution.ts | 4 +- src/auto-reply/reply/agent-runner.ts | 3 +- src/auto-reply/reply/commands-diagnostics.ts | 2 +- .../reply/commands-export-trajectory.ts | 2 +- src/auto-reply/reply/get-reply-run.ts | 9 +- src/auto-reply/reply/get-reply.ts | 13 +-- src/auto-reply/reply/route-reply.ts | 8 +- src/auto-reply/reply/session.ts | 3 +- src/channels/plugins/bundled.ts | 4 +- src/cli/command-path-policy.ts | 2 +- src/cli/daemon-cli/install.ts | 4 +- src/cli/gateway-cli/qa-parent-watchdog.ts | 3 +- .../register.option-collisions.test.ts | 2 +- src/cli/nodes-cli.coverage.test.ts | 2 +- src/cli/plugins-cli.runtime.ts | 6 +- src/cli/run-main.ts | 2 +- src/cli/windows-argv.ts | 4 +- src/commands/channels/remove.ts | 3 +- src/commands/configure.channels.ts | 2 +- src/commands/doctor-config-flow.ts | 2 +- src/commands/migrate.test.ts | 2 +- src/commands/models/auth.test.ts | 2 +- .../local/auth-choice.ts | 2 +- src/config/channel-compat-normalization.ts | 2 +- src/config/defaults.ts | 4 +- src/config/redact-snapshot.ts | 2 +- src/config/sessions/store-load.ts | 4 +- src/cron/isolated-agent/delivery-target.ts | 4 +- src/cron/isolated-agent/run.ts | 20 ++-- src/cron/schedule.ts | 4 +- src/cron/service.issue-regressions.test.ts | 4 +- src/cron/service/timer.regression.test.ts | 2 +- src/daemon/systemd.ts | 2 +- src/gateway/call.ts | 9 +- src/gateway/config-reload.ts | 2 +- .../gateway-cli-backend.live-helpers.ts | 3 +- .../gateway-models.profiles.live.test.ts | 16 +-- .../gateway-trajectory-export.live.test.ts | 2 +- src/gateway/openresponses-http.ts | 2 +- src/gateway/server-control-ui-root.ts | 2 +- src/gateway/server-methods/agent-job.ts | 3 +- .../server-methods/agent-wait-dedupe.ts | 12 +-- src/gateway/server-methods/agent.ts | 2 +- src/gateway/server-methods/channels.ts | 2 +- .../server-methods/chat-reply-media.ts | 2 +- src/gateway/server-methods/send.ts | 2 +- src/gateway/server-methods/usage.ts | 2 +- src/gateway/server.cron.test.ts | 2 +- src/gateway/server.preauth-hardening.test.ts | 2 +- .../server.sessions.list-changed.test.ts | 8 +- src/gateway/server.sessions.store-rpc.test.ts | 2 +- .../server/ws-connection/auth-context.ts | 2 +- .../server/ws-connection/message-handler.ts | 18 ++-- src/gateway/sessions-history-http.ts | 10 +- src/gateway/talk-realtime-relay.ts | 15 +-- src/gateway/talk-transcription-relay.ts | 8 +- src/gateway/talk.test-helpers.ts | 2 +- src/gateway/test-helpers.e2e.ts | 3 +- src/gateway/test-helpers.server.ts | 3 +- .../test/server-sessions.test-helpers.ts | 2 +- src/hooks/frontmatter.ts | 2 +- src/hooks/gmail-watcher.ts | 6 +- src/infra/net/ssrf.pinning.test.ts | 8 +- .../account-scoped-conversation-bindings.ts | 4 +- src/llm/providers/azure-openai-responses.ts | 3 +- src/llm/providers/openai-completions.ts | 2 +- src/media-understanding/image.ts | 2 +- src/media/web-media.ts | 3 +- src/node-host/invoke-system-run.ts | 12 +-- .../contracts/plugin-sdk-root-alias.test.ts | 3 +- src/plugins/update.ts | 2 +- src/shared/json-schema-defaults.ts | 3 +- src/skills/loading/frontmatter.ts | 2 +- .../loading/plugin-sandbox-sync.test.ts | 6 +- src/talk/audio-codec.ts | 3 +- src/talk/session-runtime.ts | 17 +-- src/wizard/setup.finalize.ts | 2 +- src/wizard/setup.ts | 6 +- test/scripts/oxlint-config.test.ts | 3 + ui/src/ui/chat/realtime-talk-google-live.ts | 3 +- ui/src/ui/chat/session-controls.ts | 7 +- ui/src/ui/realtime-talk-google-live.test.ts | 2 +- ui/src/ui/tool-display.ts | 4 +- ui/src/ui/views/config.browser.test.ts | 2 +- ui/src/ui/views/dreaming.test.ts | 9 +- 197 files changed, 619 insertions(+), 638 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 35a8368db16..ec120c9fd2d 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -20,6 +20,7 @@ "eslint/no-multi-str": "error", "eslint/no-new": "error", "eslint/no-object-constructor": "error", + "eslint/no-param-reassign": "error", "eslint/no-proto": "error", "eslint/no-regex-spaces": "error", "eslint/no-return-assign": "error", @@ -44,8 +45,10 @@ "eslint/default-case-last": "error", "eslint/default-param-last": "error", "eslint/prefer-exponentiation-operator": "error", + "eslint/prefer-const": "error", "eslint/prefer-numeric-literals": "error", "eslint/prefer-object-has-own": "error", + "eslint/object-shorthand": "error", "eslint/prefer-rest-params": "error", "eslint/prefer-spread": "error", "eslint/radix": "error", diff --git a/extensions/browser/src/browser/pw-session.connections.test.ts b/extensions/browser/src/browser/pw-session.connections.test.ts index f30f7f1d99f..666e6aaec20 100644 --- a/extensions/browser/src/browser/pw-session.connections.test.ts +++ b/extensions/browser/src/browser/pw-session.connections.test.ts @@ -17,7 +17,6 @@ type BrowserMockBundle = { }; function makeBrowser(targetId: string, url: string): BrowserMockBundle { - let context: import("playwright-core").BrowserContext; const browserClose = vi.fn(async () => {}); const page = { on: vi.fn(), @@ -26,7 +25,7 @@ function makeBrowser(targetId: string, url: string): BrowserMockBundle { url: vi.fn(() => url), } as unknown as import("playwright-core").Page; - context = { + const context: import("playwright-core").BrowserContext = { pages: () => [page], on: vi.fn(), newCDPSession: vi.fn(async () => ({ @@ -66,7 +65,6 @@ function makeEmptyBrowser(): BrowserMockBundle { } function makeDisconnectedReadBrowser(): BrowserMockBundle { - let context: import("playwright-core").BrowserContext; const browserClose = vi.fn(async () => {}); const page = { on: vi.fn(), @@ -79,7 +77,7 @@ function makeDisconnectedReadBrowser(): BrowserMockBundle { }), } as unknown as import("playwright-core").Page; - context = { + const context: import("playwright-core").BrowserContext = { pages: () => [page], on: vi.fn(), newCDPSession: vi.fn(async () => { diff --git a/extensions/browser/src/browser/pw-session.get-page-for-targetid.extension-fallback.test.ts b/extensions/browser/src/browser/pw-session.get-page-for-targetid.extension-fallback.test.ts index 7e3b465080a..8dd66783434 100644 --- a/extensions/browser/src/browser/pw-session.get-page-for-targetid.extension-fallback.test.ts +++ b/extensions/browser/src/browser/pw-session.get-page-for-targetid.extension-fallback.test.ts @@ -43,7 +43,6 @@ function requireFetchInit(init: Parameters[1]): FetchInitWithDispa } function makeBrowser(pages: MockPageSpec[]): BrowserMockBundle { - let context: import("playwright-core").BrowserContext; const browserClose = vi.fn(async () => {}); const targetIdByPage = new Map(); @@ -58,7 +57,7 @@ function makeBrowser(pages: MockPageSpec[]): BrowserMockBundle { return page; }); - context = { + const context: import("playwright-core").BrowserContext = { pages: () => pageObjects, on: vi.fn(), newCDPSession: vi.fn(async (page: import("playwright-core").Page) => ({ diff --git a/extensions/browser/src/browser/pw-tools-core.responses.ts b/extensions/browser/src/browser/pw-tools-core.responses.ts index aefd971b502..6e65bbed8a6 100644 --- a/extensions/browser/src/browser/pw-tools-core.responses.ts +++ b/extensions/browser/src/browser/pw-tools-core.responses.ts @@ -32,7 +32,6 @@ export async function responseBodyViaPlaywright(opts: { const promise = new Promise((resolve, reject) => { let done = false; let timer: NodeJS.Timeout | undefined; - let handler: ((resp: unknown) => void) | undefined; const cleanup = () => { if (timer) { @@ -44,7 +43,7 @@ export async function responseBodyViaPlaywright(opts: { } }; - handler = (resp: unknown) => { + const handler: ((resp: unknown) => void) | undefined = (resp: unknown) => { if (done) { return; } diff --git a/extensions/codex/src/app-server/client.ts b/extensions/codex/src/app-server/client.ts index 7e3bd5cd544..3acdc892487 100644 --- a/extensions/codex/src/app-server/client.ts +++ b/extensions/codex/src/app-server/client.ts @@ -202,8 +202,9 @@ export class CodexAppServerClient { request( method: string, params?: unknown, - options?: { timeoutMs?: number; signal?: AbortSignal }, + optionsInput?: { timeoutMs?: number; signal?: AbortSignal }, ): Promise { + let options = optionsInput; options ??= {}; if (this.closed) { return Promise.reject(this.closeError ?? new Error("codex app-server client is closed")); diff --git a/extensions/codex/src/app-server/computer-use.ts b/extensions/codex/src/app-server/computer-use.ts index ff01ce0d5bf..a80695ece15 100644 --- a/extensions/codex/src/app-server/computer-use.ts +++ b/extensions/codex/src/app-server/computer-use.ts @@ -487,13 +487,12 @@ async function delay(ms: number, signal?: AbortSignal): Promise { throw abortError(signal); } await new Promise((resolve, reject) => { - let timer: ReturnType; const onAbort = () => { clearTimeout(timer); signal?.removeEventListener("abort", onAbort); reject(abortError(signal)); }; - timer = setTimeout(() => { + const timer: ReturnType = setTimeout(() => { signal?.removeEventListener("abort", onAbort); resolve(); }, ms); diff --git a/extensions/codex/src/app-server/run-attempt.test.ts b/extensions/codex/src/app-server/run-attempt.test.ts index 195b5c652b7..34e659c14ed 100644 --- a/extensions/codex/src/app-server/run-attempt.test.ts +++ b/extensions/codex/src/app-server/run-attempt.test.ts @@ -2735,17 +2735,18 @@ describe("runCodexAppServerAttempt", () => { }); it("does not drop turn completion notifications emitted while turn/start is in flight", async () => { - let harness: ReturnType; - harness = createAppServerHarness(async (method) => { - if (method === "thread/start") { - return threadStartResult(); - } - if (method === "turn/start") { - await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" }); - return turnStartResult("turn-1", "completed"); - } - return {}; - }); + const harness: ReturnType = createAppServerHarness( + async (method) => { + if (method === "thread/start") { + return threadStartResult(); + } + if (method === "turn/start") { + await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" }); + return turnStartResult("turn-1", "completed"); + } + return {}; + }, + ); const result = await runCodexAppServerAttempt( createParams(path.join(tempDir, "session.jsonl"), path.join(tempDir, "workspace")), @@ -2755,30 +2756,31 @@ describe("runCodexAppServerAttempt", () => { }); it("does not fail when a buffered terminal notification is followed by client close", async () => { - let harness: ReturnType; let resolveBufferedTerminal!: () => void; const bufferedTerminal = new Promise((resolve) => { resolveBufferedTerminal = resolve; }); - harness = createAppServerHarness(async (method) => { - if (method === "thread/start") { - return threadStartResult(); - } - if (method === "turn/start") { - await harness.notify({ - method: "item/started", - params: { - threadId: "thread-1", - turnId: "turn-1", - item: { id: "tool-1", type: "commandExecution" }, - }, - }); - await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" }); - resolveBufferedTerminal(); - return turnStartResult("turn-1", "inProgress"); - } - return {}; - }); + const harness: ReturnType = createAppServerHarness( + async (method) => { + if (method === "thread/start") { + return threadStartResult(); + } + if (method === "turn/start") { + await harness.notify({ + method: "item/started", + params: { + threadId: "thread-1", + turnId: "turn-1", + item: { id: "tool-1", type: "commandExecution" }, + }, + }); + await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" }); + resolveBufferedTerminal(); + return turnStartResult("turn-1", "inProgress"); + } + return {}; + }, + ); const run = runCodexAppServerAttempt( createParams(path.join(tempDir, "session.jsonl"), path.join(tempDir, "workspace")), @@ -2795,24 +2797,25 @@ describe("runCodexAppServerAttempt", () => { }); it("does not time out when turn progress arrives before turn/start returns", async () => { - let harness: ReturnType; - harness = createAppServerHarness(async (method) => { - if (method === "thread/start") { - return threadStartResult(); - } - if (method === "turn/start") { - await harness.notify({ - method: "turn/started", - params: { - threadId: "thread-1", - turnId: "turn-1", - turn: { id: "turn-1", status: "inProgress" }, - }, - }); - return turnStartResult("turn-1", "inProgress"); - } - return {}; - }); + const harness: ReturnType = createAppServerHarness( + async (method) => { + if (method === "thread/start") { + return threadStartResult(); + } + if (method === "turn/start") { + await harness.notify({ + method: "turn/started", + params: { + threadId: "thread-1", + turnId: "turn-1", + turn: { id: "turn-1", status: "inProgress" }, + }, + }); + return turnStartResult("turn-1", "inProgress"); + } + return {}; + }, + ); const params = createParams( path.join(tempDir, "session.jsonl"), path.join(tempDir, "workspace"), diff --git a/extensions/codex/src/app-server/run-attempt.ts b/extensions/codex/src/app-server/run-attempt.ts index ac42afbbab0..76eb203a35b 100644 --- a/extensions/codex/src/app-server/run-attempt.ts +++ b/extensions/codex/src/app-server/run-attempt.ts @@ -475,8 +475,8 @@ export async function runCodexAppServerAttempt( sessionKey: contextSessionKey, ...(startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}), }; - let activeSessionId = params.sessionId; - let activeSessionFile = params.sessionFile; + const activeSessionId = params.sessionId; + const activeSessionFile = params.sessionFile; const buildActiveRunAttemptParams = (): EmbeddedRunAttemptParams => ({ ...runtimeParams, sessionId: activeSessionId, @@ -982,12 +982,7 @@ export async function runCodexAppServerAttempt( prompt: codexTurnPromptText, tools: toolBridge.availableSpecs, }); - - let projector: CodexAppServerEventProjector | undefined; - let turnId: string | undefined; const pendingNotifications: CodexServerNotification[] = []; - let userInputBridge: ReturnType | undefined; - let steeringQueue: ReturnType | undefined; let completed = false; let terminalTurnNotificationQueued = false; let timedOut = false; @@ -1034,6 +1029,14 @@ export async function runCodexAppServerAttempt( | undefined; let terminalDynamicToolReleaseCheckScheduled = false; let currentTurnHadNonTerminalDynamicToolResult = false; + const turnIdRef: { current?: string } = {}; + const projectorRef: { current?: CodexAppServerEventProjector } = {}; + const userInputBridgeRef: { + current?: ReturnType; + } = {}; + const steeringQueueRef: { + current?: ReturnType; + } = {}; const renewNativeHookRelayForTurnProgress = () => { if (!nativeHookRelay || options.nativeHookRelay?.ttlMs !== undefined) { @@ -1060,7 +1063,7 @@ export async function runCodexAppServerAttempt( const turnWatches = createCodexAttemptTurnWatchController({ threadId: thread.threadId, signal: runAbortController.signal, - getTurnId: () => turnId, + getTurnId: () => turnIdRef.current, isCompleted: () => completed, isTerminalTurnNotificationQueued: () => terminalTurnNotificationQueued, getActiveAppServerTurnRequests: () => activeAppServerTurnRequests, @@ -1078,7 +1081,7 @@ export async function runCodexAppServerAttempt( turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed"; }, - onMarkTimedOut: () => projector?.markTimedOut(), + onMarkTimedOut: () => projectorRef.current?.markTimedOut(), onAbort: (reason) => runAbortController.abort(reason), onCompleted: () => { completed = true; @@ -1245,6 +1248,10 @@ export async function runCodexAppServerAttempt( }); const handleNotification = async (notification: CodexServerNotification) => { + const projector = projectorRef.current; + const turnId = turnIdRef.current; + const userInputBridge = userInputBridgeRef.current; + const steeringQueue = steeringQueueRef.current; userInputBridge?.handleNotification(notification); if (!projector || !turnId) { pendingNotifications.push(notification); @@ -1296,6 +1303,9 @@ export async function runCodexAppServerAttempt( } }; const enqueueNotification = (notification: CodexServerNotification): Promise => { + const projector = projectorRef.current; + const turnId = turnIdRef.current; + const userInputBridge = userInputBridgeRef.current; const correlation = describeCodexNotificationCorrelation(notification, { threadId: thread.threadId, ...(turnId ? { turnId } : {}), @@ -1371,6 +1381,9 @@ export async function runCodexAppServerAttempt( }); const notificationCleanup = client.addNotificationHandler(enqueueNotification); const requestCleanup = client.addRequestHandler(async (request) => { + const turnId = turnIdRef.current; + const userInputBridge = userInputBridgeRef.current; + const projector = projectorRef.current; let armCompletionWatchOnResponse = false; let requestCountsAsTurnActivity = false; const markCurrentTurnRequestProgress = () => { @@ -1632,7 +1645,6 @@ export async function runCodexAppServerAttempt( } } }); - let closeCleanup: (() => void) | undefined; const buildLlmInputEvent = () => ({ runId: params.runId, @@ -1880,10 +1892,10 @@ export async function runCodexAppServerAttempt( releaseSharedClientLease = undefined; throw new Error("codex app-server turn/start failed without an error"); } - turnId = turn.turn.id; + turnIdRef.current = turn.turn.id; const activeTurnId = turn.turn.id; emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" }); - userInputBridge = createCodexUserInputBridge({ + userInputBridgeRef.current = createCodexUserInputBridge({ paramsForRun: params, threadId: thread.threadId, turnId: activeTurnId, @@ -1895,7 +1907,7 @@ export async function runCodexAppServerAttempt( prompt: codexTurnPromptText, imagesCount: params.images?.length ?? 0, }); - projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, { + projectorRef.current = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, { nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && nativeHookRelay.shouldRelayEvent("post_tool_use"), @@ -1909,7 +1921,7 @@ export async function runCodexAppServerAttempt( ) { terminalTurnNotificationQueued = true; } - closeCleanup = ( + const closeCleanup: (() => void) | undefined = ( client as { addCloseHandler?: (handler: (client: CodexAppServerClient) => void) => () => void; } @@ -1933,7 +1945,10 @@ export async function runCodexAppServerAttempt( resolveCompletion?.(); }); emitLifecycleStart(); - const activeProjector = projector; + const activeProjector = projectorRef.current; + if (!activeProjector) { + throw new Error("codex app-server projector was not initialized"); + } turnWatches.armTerminalIdleWatch(); turnWatches.touchActivity("turn:start", { arm: true }); turnWatches.armAttemptIdleWatch(); @@ -1956,16 +1971,17 @@ export async function runCodexAppServerAttempt( client, threadId: thread.threadId, turnId: activeTurnId, - answerPendingUserInput: (text) => userInputBridge?.handleQueuedMessage(text) ?? false, + answerPendingUserInput: (text) => + userInputBridgeRef.current?.handleQueuedMessage(text) ?? false, signal: runAbortController.signal, }); - steeringQueue = activeSteeringQueue; + steeringQueueRef.current = activeSteeringQueue; const handle = { kind: "embedded" as const, queueMessage: async (text: string, options?: CodexSteeringQueueOptions) => activeSteeringQueue.queue(text, options), isStreaming: () => !completed, - isCompacting: () => projector?.isCompacting() ?? false, + isCompacting: () => projectorRef.current?.isCompacting() ?? false, sourceReplyDeliveryMode: params.sourceReplyDeliveryMode, cancel: () => runAbortController.abort("cancelled"), abort: () => runAbortController.abort("aborted"), @@ -2276,7 +2292,7 @@ export async function runCodexAppServerAttempt( }, }); if (!timedOut && !runAbortController.signal.aborted) { - await steeringQueue?.flushPending(); + await steeringQueueRef.current?.flushPending(); } if (!timedOut) { await unsubscribeCodexThreadBestEffort(client, { @@ -2284,7 +2300,7 @@ export async function runCodexAppServerAttempt( timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, }); } - userInputBridge?.cancelPending(); + userInputBridgeRef.current?.cancelPending(); turnWatches.clearAllTimers(); notificationCleanup(); requestCleanup(); @@ -2306,7 +2322,7 @@ export async function runCodexAppServerAttempt( await releaseSandboxExecEnvironment(); runAbortController.signal.removeEventListener("abort", abortListener); params.abortSignal?.removeEventListener("abort", abortFromUpstream); - steeringQueue?.cancel(); + steeringQueueRef.current?.cancel(); clearActiveEmbeddedRun(params.sessionId, handle, params.sessionKey); } } diff --git a/extensions/discord/src/approval-handler.runtime.ts b/extensions/discord/src/approval-handler.runtime.ts index 7dd7be134db..41fcc3a9dc0 100644 --- a/extensions/discord/src/approval-handler.runtime.ts +++ b/extensions/discord/src/approval-handler.runtime.ts @@ -452,13 +452,13 @@ export const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAd const container = view.approvalKind === "plugin" ? createPluginApprovalRequestContainer({ - view: view, + view, cfg, accountId: resolved.accountId, actionRow, }) : createExecApprovalRequestContainer({ - view: view, + view, cfg, accountId: resolved.accountId, actionRow, @@ -475,12 +475,12 @@ export const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAd const container = view.approvalKind === "plugin" ? createPluginResolvedContainer({ - view: view, + view, cfg, accountId: resolvedContext.accountId, }) : createExecResolvedContainer({ - view: view, + view, cfg, accountId: resolvedContext.accountId, }); @@ -494,12 +494,12 @@ export const discordApprovalNativeRuntime = createChannelApprovalNativeRuntimeAd const container = view.approvalKind === "plugin" ? createPluginExpiredContainer({ - view: view, + view, cfg, accountId: resolvedContext.accountId, }) : createExecExpiredContainer({ - view: view, + view, cfg, accountId: resolvedContext.accountId, }); diff --git a/extensions/discord/src/monitor.gateway.test.ts b/extensions/discord/src/monitor.gateway.test.ts index 424165fd27b..5e4cc5b04be 100644 --- a/extensions/discord/src/monitor.gateway.test.ts +++ b/extensions/discord/src/monitor.gateway.test.ts @@ -143,14 +143,13 @@ describe("waitForDiscordGatewayStop", () => { it("keeps the lifecycle handler active until disconnect returns on abort", async () => { const onGatewayEvent = vi.fn(() => "stop" as const); const fatalEvent = createGatewayEvent("fatal", "disconnect emitted error"); - let emitFromDisconnect: ((event: DiscordGatewayEvent) => void) | undefined; const { abort, detachLifecycle, disconnect, emitGatewayEvent, promise } = startGatewayWait({ onGatewayEvent, disconnect: () => { emitFromDisconnect?.(fatalEvent); }, }); - emitFromDisconnect = emitGatewayEvent; + const emitFromDisconnect: ((event: DiscordGatewayEvent) => void) | undefined = emitGatewayEvent; abort.abort(); @@ -164,7 +163,6 @@ describe("waitForDiscordGatewayStop", () => { const firstEvent = createGatewayEvent("fatal", "first failure"); const secondEvent = createGatewayEvent("fatal", "second failure"); const seenEvents: DiscordGatewayEvent[] = []; - let emitFromDisconnect: ((event: DiscordGatewayEvent) => void) | undefined; const { emitGatewayEvent, promise } = startGatewayWait({ onGatewayEvent: (event) => { seenEvents.push(event); @@ -174,7 +172,7 @@ describe("waitForDiscordGatewayStop", () => { emitFromDisconnect?.(secondEvent); }, }); - emitFromDisconnect = emitGatewayEvent; + const emitFromDisconnect: ((event: DiscordGatewayEvent) => void) | undefined = emitGatewayEvent; emitGatewayEvent(firstEvent); diff --git a/extensions/discord/src/monitor/gateway-plugin.test.ts b/extensions/discord/src/monitor/gateway-plugin.test.ts index 51d1124373d..23c86cc74b6 100644 --- a/extensions/discord/src/monitor/gateway-plugin.test.ts +++ b/extensions/discord/src/monitor/gateway-plugin.test.ts @@ -94,7 +94,7 @@ describe("createDiscordGatewayPlugin", () => { error: vi.fn(), exit: vi.fn(), }, - ...(testing ? { testing: testing } : {}), + ...(testing ? { testing } : {}), }); } diff --git a/extensions/discord/src/monitor/provider.ts b/extensions/discord/src/monitor/provider.ts index 39d68832ede..0d872f47b7e 100644 --- a/extensions/discord/src/monitor/provider.ts +++ b/extensions/discord/src/monitor/provider.ts @@ -480,7 +480,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) { string, import("openclaw/plugin-sdk/reply-history").HistoryEntry[] >(); - let { botUserId, botUserName } = await fetchDiscordBotIdentity({ + const { botUserId, botUserName } = await fetchDiscordBotIdentity({ client, token, runtime, diff --git a/extensions/discord/src/resolve-channels.ts b/extensions/discord/src/resolve-channels.ts index b881a73b8b1..ac51020aafc 100644 --- a/extensions/discord/src/resolve-channels.ts +++ b/extensions/discord/src/resolve-channels.ts @@ -326,7 +326,7 @@ export async function resolveDiscordChannelAllowlist(params: { results.push({ input, resolved: false, - channelName: channelName, + channelName, }); continue; } @@ -361,7 +361,7 @@ export async function resolveDiscordChannelAllowlist(params: { results.push({ input, resolved: false, - channelName: channelName, + channelName, }); } diff --git a/extensions/discord/src/voice/manager.e2e.test.ts b/extensions/discord/src/voice/manager.e2e.test.ts index 607b353fa53..fb9ec67c3d4 100644 --- a/extensions/discord/src/voice/manager.e2e.test.ts +++ b/extensions/discord/src/voice/manager.e2e.test.ts @@ -76,7 +76,7 @@ const { on: vi.fn(), off: vi.fn(), destroy: vi.fn(), - [Symbol.asyncIterator]: async function* () {}, + async *[Symbol.asyncIterator]() {}, })), }, state: { @@ -2088,12 +2088,11 @@ describe("DiscordVoiceManager", () => { const firstConnection = createConnectionMock(); const secondConnection = createConnectionMock(); joinVoiceChannelMock.mockReturnValueOnce(firstConnection).mockReturnValueOnce(secondConnection); - let manager!: InstanceType; entersStateMock.mockImplementationOnce(async () => { await manager.destroy(); throw new Error("The operation was aborted"); }); - manager = createManager(); + const manager: InstanceType = createManager(); const result = await manager.join({ guildId: "g1", channelId: "1001" }); diff --git a/extensions/discord/src/voice/manager.ts b/extensions/discord/src/voice/manager.ts index a9cb1db18dc..bced89f9e4d 100644 --- a/extensions/discord/src/voice/manager.ts +++ b/extensions/discord/src/voice/manager.ts @@ -674,12 +674,6 @@ export class DiscordVoiceManager { const player = voiceSdk.createAudioPlayer(); connection.subscribe(player); - - let speakingHandler: ((userId: string) => void) | undefined; - let speakingEndHandler: ((userId: string) => void) | undefined; - let disconnectedHandler: (() => Promise) | undefined; - let destroyedHandler: (() => void) | undefined; - let playerErrorHandler: ((err: Error) => void) | undefined; let stopped = false; const clearSessionIfCurrent = () => { const active = this.sessions.get(guildId); @@ -787,16 +781,16 @@ export class DiscordVoiceManager { }; } - speakingHandler = (userId: string) => { + const speakingHandler: ((userId: string) => void) | undefined = (userId: string) => { void this.handleSpeakingStart(entry, userId).catch((err) => { logger.warn(`discord voice: capture failed: ${formatErrorMessage(err)}`); }); }; - speakingEndHandler = (userId: string) => { + const speakingEndHandler: ((userId: string) => void) | undefined = (userId: string) => { this.scheduleCaptureFinalize(entry, userId, "speaker end"); }; - disconnectedHandler = async () => { + const disconnectedHandler: (() => Promise) | undefined = async () => { try { logVoiceVerbose( `disconnected: attempting recovery guild ${guildId} channel ${channelId} grace=${reconnectGraceMs}ms`, @@ -825,14 +819,14 @@ export class DiscordVoiceManager { }); } }; - destroyedHandler = () => { + const destroyedHandler: (() => void) | undefined = () => { clearSessionIfCurrent(); stopEntry(entry, { destroyConnection: false, reason: `destroyed guild ${guildId} channel ${channelId}`, }); }; - playerErrorHandler = (err: Error) => { + const playerErrorHandler: ((err: Error) => void) | undefined = (err: Error) => { logger.warn(`discord voice: playback error: ${formatErrorMessage(err)}`); }; diff --git a/extensions/feishu/src/async.ts b/extensions/feishu/src/async.ts index 6b138083085..b37e30f1970 100644 --- a/extensions/feishu/src/async.ts +++ b/extensions/feishu/src/async.ts @@ -74,8 +74,6 @@ export function waitForAbortableDelay( return new Promise((resolve) => { let settled = false; - let timer: ReturnType | undefined; - let handleAbort: (() => void) | undefined; const finish = (value: boolean) => { if (settled) { @@ -91,7 +89,7 @@ export function waitForAbortableDelay( resolve(value); }; - handleAbort = () => { + const handleAbort: (() => void) | undefined = () => { finish(false); }; @@ -101,7 +99,10 @@ export function waitForAbortableDelay( return; } - timer = setTimeout(() => finish(true), resolveTimerTimeoutMs(delayMs, 1)); + const timer: ReturnType | undefined = setTimeout( + () => finish(true), + resolveTimerTimeoutMs(delayMs, 1), + ); timer.unref?.(); }); } diff --git a/extensions/feishu/src/bot.ts b/extensions/feishu/src/bot.ts index 45253f3f95c..40aba4629f3 100644 --- a/extensions/feishu/src/bot.ts +++ b/extensions/feishu/src/bot.ts @@ -1203,7 +1203,7 @@ export async function handleFeishuMessage(params: { } const rootMsg = await getRootMessageInfo(); - let feishuThreadId = ctx.threadId ?? rootMessageThreadId ?? rootMsg?.threadId; + const feishuThreadId = ctx.threadId ?? rootMessageThreadId ?? rootMsg?.threadId; if (feishuThreadId) { log(`feishu[${account.accountId}]: resolved thread ID: ${feishuThreadId}`); } diff --git a/extensions/feishu/src/docx-batch-insert.test.ts b/extensions/feishu/src/docx-batch-insert.test.ts index 5f642cbd106..605ffccdcc4 100644 --- a/extensions/feishu/src/docx-batch-insert.test.ts +++ b/extensions/feishu/src/docx-batch-insert.test.ts @@ -25,7 +25,7 @@ function createCountingIterable(values: T[]) { let iterations = 0; return { values: { - [Symbol.iterator]: function* () { + *[Symbol.iterator]() { iterations += 1; yield* values; }, diff --git a/extensions/feishu/src/monitor.transport.ts b/extensions/feishu/src/monitor.transport.ts index 0aa8774bca4..438066e393a 100644 --- a/extensions/feishu/src/monitor.transport.ts +++ b/extensions/feishu/src/monitor.transport.ts @@ -187,7 +187,6 @@ function waitForFeishuWsCycleEnd(params: { return new Promise((resolve) => { let settled = false; - let handleAbort: (() => void) | undefined; const finish = (result: "abort" | Error) => { if (settled) { @@ -200,7 +199,7 @@ function waitForFeishuWsCycleEnd(params: { resolve(result); }; - handleAbort = () => finish("abort"); + const handleAbort: (() => void) | undefined = () => finish("abort"); params.abortSignal?.addEventListener("abort", handleAbort, { once: true }); if (params.abortSignal?.aborted) { finish("abort"); diff --git a/extensions/file-transfer/src/tools/dir-fetch-tool.ts b/extensions/file-transfer/src/tools/dir-fetch-tool.ts index 8058f5f8e65..4597813806e 100644 --- a/extensions/file-transfer/src/tools/dir-fetch-tool.ts +++ b/extensions/file-transfer/src/tools/dir-fetch-tool.ts @@ -58,7 +58,6 @@ async function listTarOutputLines(input: { let outputChars = 0; let stderr = ""; let settled = false; - let watchdog: ReturnType; const finish = (result: { ok: true; values: T[] } | { ok: false; reason: string }): void => { if (settled) { @@ -110,7 +109,7 @@ async function listTarOutputLines(input: { } }; - watchdog = setTimeout(() => { + const watchdog: ReturnType = setTimeout(() => { stopChild(); finish({ ok: false, reason: `${input.label} timed out` }); }, 30_000); @@ -274,7 +273,6 @@ export async function validateTarUncompressedBudget( let totalBytes = 0; let stderr = ""; let settled = false; - let watchdog: ReturnType; const finish = (result: { ok: true } | { ok: false; reason: string }): void => { if (settled) { return; @@ -283,7 +281,7 @@ export async function validateTarUncompressedBudget( clearTimeout(watchdog); resolve(result); }; - watchdog = setTimeout(() => { + const watchdog: ReturnType = setTimeout(() => { try { child.kill("SIGKILL"); } catch { @@ -388,7 +386,6 @@ async function unpackTar(tarBuffer: Buffer, destDir: string): Promise { ); let stderrOut = ""; let settled = false; - let watchdog: ReturnType; const fail = (error: Error): void => { if (settled) { return; @@ -405,7 +402,7 @@ async function unpackTar(tarBuffer: Buffer, destDir: string): Promise { clearTimeout(watchdog); resolve(); }; - watchdog = setTimeout(() => { + const watchdog: ReturnType = setTimeout(() => { try { child.kill("SIGKILL"); } catch { diff --git a/extensions/google-meet/src/realtime-node.ts b/extensions/google-meet/src/realtime-node.ts index c768b283728..a6cc28dbaa7 100644 --- a/extensions/google-meet/src/realtime-node.ts +++ b/extensions/google-meet/src/realtime-node.ts @@ -191,7 +191,6 @@ export async function startNodeAgentAudioBridge(params: { }), ); const transcript: GoogleMeetRealtimeTranscriptEntry[] = []; - let agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined; let ttsQueue = Promise.resolve(); const stop = async () => { @@ -281,26 +280,27 @@ export async function startNodeAgentAudioBridge(params: { }); }; - agentTalkback = createRealtimeVoiceAgentTalkbackQueue({ - debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, - isStopped: () => stopped, - logger: params.logger, - logPrefix: "[google-meet] node agent", - responseStyle: "Brief, natural spoken answer for a live meeting.", - fallbackText: "I hit an error while checking that. Please try again.", - consult: ({ question, responseStyle }) => - consultOpenClawAgentForGoogleMeet({ - config: params.config, - fullConfig: params.fullConfig, - runtime: params.runtime, - logger: params.logger, - meetingSessionId: params.meetingSessionId, - requesterSessionKey: params.requesterSessionKey, - args: { question, responseStyle }, - transcript, - }), - deliver: enqueueSpeakText, - }); + const agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined = + createRealtimeVoiceAgentTalkbackQueue({ + debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, + isStopped: () => stopped, + logger: params.logger, + logPrefix: "[google-meet] node agent", + responseStyle: "Brief, natural spoken answer for a live meeting.", + fallbackText: "I hit an error while checking that. Please try again.", + consult: ({ question, responseStyle }) => + consultOpenClawAgentForGoogleMeet({ + config: params.config, + fullConfig: params.fullConfig, + runtime: params.runtime, + logger: params.logger, + meetingSessionId: params.meetingSessionId, + requesterSessionKey: params.requesterSessionKey, + args: { question, responseStyle }, + transcript, + }), + deliver: enqueueSpeakText, + }); sttSession = resolved.provider.createSession({ cfg: params.fullConfig, @@ -455,29 +455,29 @@ export async function startNodeRealtimeAudioBridge(params: { audioFormat: params.config.chrome.audioFormat, }), ); - let agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined; - agentTalkback = createRealtimeVoiceAgentTalkbackQueue({ - debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, - isStopped: () => stopped, - logger: params.logger, - logPrefix: "[google-meet] node realtime agent", - responseStyle: "Brief, natural spoken answer for a live meeting.", - fallbackText: "I hit an error while checking that. Please try again.", - consult: ({ question, responseStyle }) => - consultOpenClawAgentForGoogleMeet({ - config: params.config, - fullConfig: params.fullConfig, - runtime: params.runtime, - logger: params.logger, - meetingSessionId: params.meetingSessionId, - requesterSessionKey: params.requesterSessionKey, - args: { question, responseStyle }, - transcript, - }), - deliver: (text) => { - bridge?.sendUserMessage(buildGoogleMeetSpeakExactUserMessage(text)); - }, - }); + const agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined = + createRealtimeVoiceAgentTalkbackQueue({ + debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, + isStopped: () => stopped, + logger: params.logger, + logPrefix: "[google-meet] node realtime agent", + responseStyle: "Brief, natural spoken answer for a live meeting.", + fallbackText: "I hit an error while checking that. Please try again.", + consult: ({ question, responseStyle }) => + consultOpenClawAgentForGoogleMeet({ + config: params.config, + fullConfig: params.fullConfig, + runtime: params.runtime, + logger: params.logger, + meetingSessionId: params.meetingSessionId, + requesterSessionKey: params.requesterSessionKey, + args: { question, responseStyle }, + transcript, + }), + deliver: (text) => { + bridge?.sendUserMessage(buildGoogleMeetSpeakExactUserMessage(text)); + }, + }); const stop = async () => { if (stopped) { diff --git a/extensions/google-meet/src/realtime.ts b/extensions/google-meet/src/realtime.ts index bfc2725128b..2610f0c14d7 100644 --- a/extensions/google-meet/src/realtime.ts +++ b/extensions/google-meet/src/realtime.ts @@ -279,7 +279,7 @@ function alawByteToLinear(value: number): number { const sign = aLaw & 0x80; const exponent = (aLaw & 0x70) >> 4; const mantissa = aLaw & 0x0f; - let sample = exponent === 0 ? (mantissa << 4) + 8 : ((mantissa << 4) + 0x108) << (exponent - 1); + const sample = exponent === 0 ? (mantissa << 4) + 8 : ((mantissa << 4) + 0x108) << (exponent - 1); return sign ? sample : -sample; } @@ -502,7 +502,6 @@ export async function startCommandAgentAudioBridge(params: { let lastSuppressedInputAt: string | undefined; let suppressInputUntil = 0; let lastOutputPlayableUntilMs = 0; - let agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined; let ttsQueue = Promise.resolve(); const transcript: GoogleMeetRealtimeTranscriptEntry[] = []; const resolved = resolveGoogleMeetRealtimeTranscriptionProvider({ @@ -702,26 +701,27 @@ export async function startCommandAgentAudioBridge(params: { }); }; - agentTalkback = createRealtimeVoiceAgentTalkbackQueue({ - debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, - isStopped: () => stopped, - logger: params.logger, - logPrefix: "[google-meet] agent", - responseStyle: "Brief, natural spoken answer for a live meeting.", - fallbackText: "I hit an error while checking that. Please try again.", - consult: ({ question, responseStyle }) => - consultOpenClawAgentForGoogleMeet({ - config: params.config, - fullConfig: params.fullConfig, - runtime: params.runtime, - logger: params.logger, - meetingSessionId: params.meetingSessionId, - requesterSessionKey: params.requesterSessionKey, - args: { question, responseStyle }, - transcript, - }), - deliver: enqueueSpeakText, - }); + const agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined = + createRealtimeVoiceAgentTalkbackQueue({ + debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, + isStopped: () => stopped, + logger: params.logger, + logPrefix: "[google-meet] agent", + responseStyle: "Brief, natural spoken answer for a live meeting.", + fallbackText: "I hit an error while checking that. Please try again.", + consult: ({ question, responseStyle }) => + consultOpenClawAgentForGoogleMeet({ + config: params.config, + fullConfig: params.fullConfig, + runtime: params.runtime, + logger: params.logger, + meetingSessionId: params.meetingSessionId, + requesterSessionKey: params.requesterSessionKey, + args: { question, responseStyle }, + transcript, + }), + deliver: enqueueSpeakText, + }); sttSession = resolved.provider.createSession({ cfg: params.fullConfig, @@ -861,7 +861,6 @@ export async function startCommandRealtimeAudioBridge(params: { let suppressInputUntil = 0; let lastOutputPlayableUntilMs = 0; let bargeInInputProcess: BridgeProcess | undefined; - let agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined; const suppressInputForOutput = (audio: Buffer) => { const suppression = recordGoogleMeetOutputActivity({ @@ -1113,28 +1112,29 @@ export async function startCommandRealtimeAudioBridge(params: { type: "session.started", payload: { meetingSessionId: params.meetingSessionId }, }); - agentTalkback = createRealtimeVoiceAgentTalkbackQueue({ - debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, - isStopped: () => stopped, - logger: params.logger, - logPrefix: "[google-meet] realtime agent", - responseStyle: "Brief, natural spoken answer for a live meeting.", - fallbackText: "I hit an error while checking that. Please try again.", - consult: ({ question, responseStyle }) => - consultOpenClawAgentForGoogleMeet({ - config: params.config, - fullConfig: params.fullConfig, - runtime: params.runtime, - logger: params.logger, - meetingSessionId: params.meetingSessionId, - requesterSessionKey: params.requesterSessionKey, - args: { question, responseStyle }, - transcript, - }), - deliver: (text) => { - bridge?.sendUserMessage(buildGoogleMeetSpeakExactUserMessage(text)); - }, - }); + const agentTalkback: RealtimeVoiceAgentTalkbackQueue | undefined = + createRealtimeVoiceAgentTalkbackQueue({ + debounceMs: GOOGLE_MEET_AGENT_TRANSCRIPT_DEBOUNCE_MS, + isStopped: () => stopped, + logger: params.logger, + logPrefix: "[google-meet] realtime agent", + responseStyle: "Brief, natural spoken answer for a live meeting.", + fallbackText: "I hit an error while checking that. Please try again.", + consult: ({ question, responseStyle }) => + consultOpenClawAgentForGoogleMeet({ + config: params.config, + fullConfig: params.fullConfig, + runtime: params.runtime, + logger: params.logger, + meetingSessionId: params.meetingSessionId, + requesterSessionKey: params.requesterSessionKey, + args: { question, responseStyle }, + transcript, + }), + deliver: (text) => { + bridge?.sendUserMessage(buildGoogleMeetSpeakExactUserMessage(text)); + }, + }); bridge = createRealtimeVoiceBridgeSession({ provider: resolved.provider, cfg: params.fullConfig, diff --git a/extensions/googlechat/src/actions.ts b/extensions/googlechat/src/actions.ts index 604fce0dfa0..e7d257d4d17 100644 --- a/extensions/googlechat/src/actions.ts +++ b/extensions/googlechat/src/actions.ts @@ -101,7 +101,7 @@ export const googlechatMessageActions: ChannelMessageActionAdapter = { mediaReadFile, }) => { const account = resolveGoogleChatAccount({ - cfg: cfg, + cfg, accountId, }); if (account.credentialSource === "none") { diff --git a/extensions/googlechat/src/channel.adapters.ts b/extensions/googlechat/src/channel.adapters.ts index 0b8b6ecf2e9..b203ce98a58 100644 --- a/extensions/googlechat/src/channel.adapters.ts +++ b/extensions/googlechat/src/channel.adapters.ts @@ -144,7 +144,7 @@ export const googlechatPairingTextAdapter = { message: string; accountId?: string | null; }) => { - const account = resolveGoogleChatAccount({ cfg: cfg, accountId }); + const account = resolveGoogleChatAccount({ cfg, accountId }); if (account.credentialSource === "none") { return; } @@ -205,7 +205,7 @@ export const googlechatOutboundAdapter = { threadId?: string | number | null; }) => { const account = resolveGoogleChatAccount({ - cfg: cfg, + cfg, accountId, }); const space = await resolveGoogleChatOutboundSpace({ account, target: to }); @@ -252,14 +252,14 @@ export const googlechatOutboundAdapter = { throw new Error("Google Chat mediaUrl is required."); } const account = resolveGoogleChatAccount({ - cfg: cfg, + cfg, accountId, }); const space = await resolveGoogleChatOutboundSpace({ account, target: to }); const thread = typeof threadId === "number" ? String(threadId) : (threadId ?? replyToId ?? undefined); const maxBytes = resolveChannelMediaMaxBytes({ - cfg: cfg, + cfg, resolveChannelLimitMb: ({ cfg, accountId }) => ( cfg.channels?.googlechat as diff --git a/extensions/imessage/src/monitor.shutdown.unhandled-rejection.test.ts b/extensions/imessage/src/monitor.shutdown.unhandled-rejection.test.ts index e2a6c0c5760..3f5f1765ebb 100644 --- a/extensions/imessage/src/monitor.shutdown.unhandled-rejection.test.ts +++ b/extensions/imessage/src/monitor.shutdown.unhandled-rejection.test.ts @@ -4,7 +4,7 @@ import { attachIMessageMonitorAbortHandler } from "./monitor/abort-handler.js"; describe("monitorIMessageProvider", () => { it("does not trigger unhandledRejection when aborting during shutdown", async () => { const abortController = new AbortController(); - let subscriptionId: number | null = 1; + const subscriptionId: number | null = 1; const requestMock = vi.fn((method: string, _params?: Record) => { if (method === "watch.unsubscribe") { return Promise.reject(new Error("imsg rpc closed")); diff --git a/extensions/imessage/src/send.ts b/extensions/imessage/src/send.ts index 5b8d37e931e..afb068131e9 100644 --- a/extensions/imessage/src/send.ts +++ b/extensions/imessage/src/send.ts @@ -909,9 +909,9 @@ export async function sendMessageIMessage( (opts.createClient ? await opts.createClient({ cliPath, dbPath }) : await createIMessageRpcClient({ cliPath, dbPath })); - let shouldClose = !opts.client; + const shouldClose = !opts.client; let result: Record; - let sendStartedAtMs = Date.now(); + const sendStartedAtMs = Date.now(); try { try { result = await client.request>("send", params, { diff --git a/extensions/line/src/card-command.ts b/extensions/line/src/card-command.ts index 83b8d0100fa..86d5aff7c77 100644 --- a/extensions/line/src/card-command.ts +++ b/extensions/line/src/card-command.ts @@ -123,11 +123,12 @@ function parseReceiptItems(itemsStr: string): Array<{ name: string; value: strin * Parse quoted arguments from command string * Supports: /card type "arg1" "arg2" "arg3" --flag value */ -function parseCardArgs(argsStr: string): { +function parseCardArgs(argsStrInput: string): { type: string; args: string[]; flags: Record; } { + let argsStr = argsStrInput; const result: { type: string; args: string[]; flags: Record } = { type: "", args: [], diff --git a/extensions/matrix/src/matrix/format.ts b/extensions/matrix/src/matrix/format.ts index fe943bb1fce..233651bce1e 100644 --- a/extensions/matrix/src/matrix/format.ts +++ b/extensions/matrix/src/matrix/format.ts @@ -128,7 +128,12 @@ function isMentionStartBoundary(charBefore: string | undefined): boolean { return !charBefore || !/[A-Za-z0-9_]/.test(charBefore); } -function trimMentionSuffix(raw: string, end: number): { raw: string; end: number } | null { +function trimMentionSuffix( + rawInput: string, + endInput: number, +): { raw: string; end: number } | null { + let raw = rawInput; + let end = endInput; while (raw.length > 1 && TRIMMABLE_MENTION_SUFFIX.test(raw.at(-1) ?? "")) { if (raw.at(-1) === "]" && /\[[0-9A-Fa-f:.]+\](?::\d+)?$/i.test(raw)) { break; diff --git a/extensions/matrix/src/matrix/monitor/events.test.ts b/extensions/matrix/src/matrix/monitor/events.test.ts index 1103bd850f7..6840c5f4fea 100644 --- a/extensions/matrix/src/matrix/monitor/events.test.ts +++ b/extensions/matrix/src/matrix/monitor/events.test.ts @@ -1623,10 +1623,10 @@ describe("registerMatrixMonitorEvents verification routing", () => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-04-10T16:21:00.000Z")); try { - let healthySyncSinceMs: number | undefined; + const healthySync = { sinceMs: undefined as number | undefined }; const { logger, failedDecryptListener } = createHarness({ accountId: "ops", - getHealthySyncSinceMs: () => healthySyncSinceMs, + getHealthySyncSinceMs: () => healthySync.sinceMs, }); if (!failedDecryptListener) { throw new Error("room.failed_decryption listener was not registered"); @@ -1650,7 +1650,7 @@ describe("registerMatrixMonitorEvents verification routing", () => { freshAfterHealthySync: false, }); - healthySyncSinceMs = Date.now(); + healthySync.sinceMs = Date.now(); await failedDecryptListener( "!room:example.org", diff --git a/extensions/matrix/src/matrix/monitor/handler.ts b/extensions/matrix/src/matrix/monitor/handler.ts index 29a3b4113c0..736e69b6a7f 100644 --- a/extensions/matrix/src/matrix/monitor/handler.ts +++ b/extensions/matrix/src/matrix/monitor/handler.ts @@ -637,7 +637,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam } } - let content = event.content as RoomMessageEventContent; + const content = event.content as RoomMessageEventContent; if ( eventType === EventType.RoomMessage && diff --git a/extensions/matrix/src/matrix/monitor/task-runner.ts b/extensions/matrix/src/matrix/monitor/task-runner.ts index eee678f0cf0..31c31662838 100644 --- a/extensions/matrix/src/matrix/monitor/task-runner.ts +++ b/extensions/matrix/src/matrix/monitor/task-runner.ts @@ -7,8 +7,7 @@ export function createMatrixMonitorTaskRunner(params: { const inFlight = new Set>(); const runDetachedTask = (label: string, task: () => Promise): Promise => { - let trackedTask!: Promise; - trackedTask = Promise.resolve() + const trackedTask: Promise = Promise.resolve() .then(task) .catch((error) => { const message = String(error); diff --git a/extensions/memory-core/src/dreaming-phases.ts b/extensions/memory-core/src/dreaming-phases.ts index dd9fd19cc4f..c54dd29eedf 100644 --- a/extensions/memory-core/src/dreaming-phases.ts +++ b/extensions/memory-core/src/dreaming-phases.ts @@ -909,7 +909,7 @@ async function collectSessionIngestionBatches(params: { const sessionScope = buildSessionScopeKey(file.agentId, file.absolutePath); const previousSeen = nextSeenMessages[sessionScope] ?? []; - let seenSet = new Set(previousSeen); + const seenSet = new Set(previousSeen); const newSeenHashes: string[] = []; const lines = entry.content.length > 0 ? entry.content.split("\n") : []; diff --git a/extensions/memory-core/src/memory/search-manager.ts b/extensions/memory-core/src/memory/search-manager.ts index 9285cba1ab7..ed96cf6a07e 100644 --- a/extensions/memory-core/src/memory/search-manager.ts +++ b/extensions/memory-core/src/memory/search-manager.ts @@ -224,7 +224,6 @@ export async function getMemorySearchManager(params: { if (!primary) { return { entry: null, failureReason }; } - let cacheEntry!: CachedQmdManagerEntry; const wrapper = new FallbackMemoryManager( { primary, @@ -240,7 +239,7 @@ export async function getMemorySearchManager(params: { } }, ); - cacheEntry = { + const cacheEntry: CachedQmdManagerEntry = { identityKey: expectedIdentityKey, manager: wrapper, }; diff --git a/extensions/msteams/src/monitor-handler.adaptive-card.test.ts b/extensions/msteams/src/monitor-handler.adaptive-card.test.ts index 5f7b70ddbe9..2b6e71ec1d7 100644 --- a/extensions/msteams/src/monitor-handler.adaptive-card.test.ts +++ b/extensions/msteams/src/monitor-handler.adaptive-card.test.ts @@ -77,11 +77,9 @@ function createActivityHandler() { await handler(context, async () => {}); } }); - - let handler: MSTeamsActivityHandler & { + const handler: MSTeamsActivityHandler & { run: NonNullable; - }; - handler = { + } = { onMessage: (nextHandler) => { messageHandlers.push(nextHandler); return handler; diff --git a/extensions/msteams/src/monitor-handler.test-helpers.ts b/extensions/msteams/src/monitor-handler.test-helpers.ts index 36b17d57324..03e143f3501 100644 --- a/extensions/msteams/src/monitor-handler.test-helpers.ts +++ b/extensions/msteams/src/monitor-handler.test-helpers.ts @@ -137,10 +137,9 @@ export function createActivityHandler( ): MSTeamsActivityHandler & { run: NonNullable; } { - let handler: MSTeamsActivityHandler & { + const handler: MSTeamsActivityHandler & { run: NonNullable; - }; - handler = { + } = { onMessage: () => handler, onMembersAdded: () => handler, onReactionsAdded: () => handler, diff --git a/extensions/msteams/src/session-route.ts b/extensions/msteams/src/session-route.ts index 1b5478b76e2..80c95cc5d6f 100644 --- a/extensions/msteams/src/session-route.ts +++ b/extensions/msteams/src/session-route.ts @@ -7,7 +7,7 @@ import { import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime"; export function resolveMSTeamsOutboundSessionRoute(params: ChannelOutboundSessionRouteParams) { - let trimmed = stripChannelTargetPrefix(params.target, "msteams", "teams"); + const trimmed = stripChannelTargetPrefix(params.target, "msteams", "teams"); if (!trimmed) { return null; } diff --git a/extensions/openai/realtime-voice-provider.test.ts b/extensions/openai/realtime-voice-provider.test.ts index 063a0ab5f9e..54e60b9c27d 100644 --- a/extensions/openai/realtime-voice-provider.test.ts +++ b/extensions/openai/realtime-voice-provider.test.ts @@ -1231,8 +1231,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => { const provider = buildOpenAIRealtimeVoiceProvider(); const onAudio = vi.fn(); const onClearAudio = vi.fn(); - let bridge: ReturnType; - bridge = provider.createBridge({ + const bridge: ReturnType = provider.createBridge({ providerConfig: { apiKey: "sk-test" }, // pragma: allowlist secret onAudio, onClearAudio, diff --git a/extensions/openai/realtime-voice-provider.ts b/extensions/openai/realtime-voice-provider.ts index d0f4776be83..449a1845da4 100644 --- a/extensions/openai/realtime-voice-provider.ts +++ b/extensions/openai/realtime-voice-provider.ts @@ -538,7 +538,6 @@ class OpenAIRealtimeVoiceBridge implements RealtimeVoiceBridge { private async doConnect(): Promise { await new Promise((resolve, reject) => { - let connectTimeout: ReturnType; let settled = false; const settleResolve = () => { if (settled) { @@ -556,7 +555,7 @@ class OpenAIRealtimeVoiceBridge implements RealtimeVoiceBridge { clearTimeout(connectTimeout); reject(error); }; - connectTimeout = setTimeout(() => { + const connectTimeout: ReturnType = setTimeout(() => { if (!this.sessionConfigured && !this.intentionallyClosed) { this.ws?.terminate(); settleReject(new Error("OpenAI realtime connection timeout")); diff --git a/extensions/qqbot/src/engine/gateway/inbound-attachments.ts b/extensions/qqbot/src/engine/gateway/inbound-attachments.ts index 0a6ee8dc39e..1b6734de365 100644 --- a/extensions/qqbot/src/engine/gateway/inbound-attachments.ts +++ b/extensions/qqbot/src/engine/gateway/inbound-attachments.ts @@ -249,7 +249,7 @@ type VoiceResult = async function processVoiceAttachment( localPath: string, - audioPath: string | null, + audioPathInput: string | null, att: RawAttachment, asrReferText: string, cfg: unknown, @@ -257,6 +257,7 @@ async function processVoiceAttachment( audioConvert: AudioConvertPort, log: ProcessContext["log"], ): Promise { + let audioPath = audioPathInput; const wavUrl = att.voice_wav_url ? att.voice_wav_url.startsWith("//") ? `https:${att.voice_wav_url}` diff --git a/extensions/qqbot/src/engine/messaging/streaming-media-send.ts b/extensions/qqbot/src/engine/messaging/streaming-media-send.ts index 9c56881dcd4..111c1ca7da4 100644 --- a/extensions/qqbot/src/engine/messaging/streaming-media-send.ts +++ b/extensions/qqbot/src/engine/messaging/streaming-media-send.ts @@ -90,7 +90,7 @@ function fixPathEncoding( log?.debug?.(`Decoding path with mixed encoding: ${result}`); // Step 1: 将八进制转义转换为字节 - let decoded = result.replace(/\\([0-7]{1,3})/g, (_: string, octal: string) => + const decoded = result.replace(/\\([0-7]{1,3})/g, (_: string, octal: string) => String.fromCharCode(Number.parseInt(octal, 8)), ); diff --git a/extensions/qqbot/src/engine/messaging/target-parser.ts b/extensions/qqbot/src/engine/messaging/target-parser.ts index ed888f8e512..d256fa92a13 100644 --- a/extensions/qqbot/src/engine/messaging/target-parser.ts +++ b/extensions/qqbot/src/engine/messaging/target-parser.ts @@ -32,7 +32,7 @@ interface ParsedTarget { * @throws {Error} When the target format is invalid. */ export function parseTarget(to: string): ParsedTarget { - let id = to.replace(/^qqbot:/i, ""); + const id = to.replace(/^qqbot:/i, ""); if (id.startsWith("c2c:")) { const userId = id.slice(4); diff --git a/extensions/signal/src/client.ts b/extensions/signal/src/client.ts index e98a75a3ac7..5c80b54bec6 100644 --- a/extensions/signal/src/client.ts +++ b/extensions/signal/src/client.ts @@ -125,7 +125,6 @@ function requestSignalHttpText( const client = url.protocol === "https:" ? https : http; return new Promise((resolve, reject) => { let settled = false; - let request: ClientRequest | undefined; const deadline = setTimeout(() => { request?.destroy(new Error(`Signal HTTP exceeded deadline after ${timeoutMs}ms`)); }, timeoutMs); @@ -151,7 +150,7 @@ function requestSignalHttpText( resolve(response); }; const maxResponseBytes = normalizeSignalHttpResponseMaxBytes(options.maxResponseBytes); - request = client.request( + const request: ClientRequest | undefined = client.request( url, { method: options.method, @@ -267,7 +266,6 @@ function openSignalEventStream( let settled = false; let response: IncomingMessage | undefined; let onAbort: () => void = () => {}; - let request: ClientRequest; const effectiveTimeoutMs = normalizeSignalSseTimeoutMs(timeoutMs); const headerDeadline = effectiveTimeoutMs === null @@ -295,7 +293,7 @@ function openSignalEventStream( cleanup(); reject(error); }; - request = client.request( + const request: ClientRequest = client.request( url, { method: "GET", diff --git a/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts b/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts index e3e2b42d3ed..a25941be199 100644 --- a/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts +++ b/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts @@ -122,9 +122,15 @@ export async function resolveSlackThreadContextData(params: { let threadStarterBody: string | undefined; let threadHistoryBody: string | undefined; - let threadSessionPreviousTimestamp: number | undefined; let threadLabel: string | undefined; let threadStarterMedia: SlackMediaResult[] | null = null; + const threadSessionPreviousTimestamp = + params.isThreadReply && params.threadTs + ? readSessionUpdatedAt({ + storePath: params.storePath, + sessionKey: params.sessionKey, + }) + : undefined; if (!params.isThreadReply || !params.threadTs) { return { @@ -188,10 +194,6 @@ export async function resolveSlackThreadContextData(params: { threadLabel = `Slack thread ${params.roomLabel}`; } - threadSessionPreviousTimestamp = readSessionUpdatedAt({ - storePath: params.storePath, - sessionKey: params.sessionKey, - }); const isNewThreadSession = !threadSessionPreviousTimestamp; const includeBotStarterAsRootContext = shouldIncludeBotThreadStarterContext({ starterIsCurrentBot, diff --git a/extensions/slack/src/monitor/provider.ts b/extensions/slack/src/monitor/provider.ts index 8aaa33ebcd6..6a45c4fdef6 100644 --- a/extensions/slack/src/monitor/provider.ts +++ b/extensions/slack/src/monitor/provider.ts @@ -153,7 +153,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) { const cfg = opts.config ?? getRuntimeConfig(); const runtime: RuntimeEnv = opts.runtime ?? createNonExitingRuntime(); - let account = resolveSlackAccount({ + const account = resolveSlackAccount({ cfg, accountId: opts.accountId, }); diff --git a/extensions/slack/src/monitor/slash.test.ts b/extensions/slack/src/monitor/slash.test.ts index 4b9b7b2747c..7639dad765a 100644 --- a/extensions/slack/src/monitor/slash.test.ts +++ b/extensions/slack/src/monitor/slash.test.ts @@ -312,7 +312,7 @@ function createArgMenusHarness() { action: (id: string | RegExp, handler: (args: unknown) => Promise) => { actions.set(id, handler); }, - options: function (this: unknown, id: string, handler: (args: unknown) => Promise) { + options(this: unknown, id: string, handler: (args: unknown) => Promise) { optionsReceiverContexts.push(this); options.set(id, handler); }, diff --git a/extensions/slack/src/outbound-adapter.test.ts b/extensions/slack/src/outbound-adapter.test.ts index db83ae88d18..fb343ce0271 100644 --- a/extensions/slack/src/outbound-adapter.test.ts +++ b/extensions/slack/src/outbound-adapter.test.ts @@ -6,8 +6,7 @@ vi.mock("./send.js", () => ({ sendMessageSlack: (...args: unknown[]) => sendMessageSlackMock(...args), })); -let slackOutbound: typeof import("./outbound-adapter.js").slackOutbound; -({ slackOutbound } = await import("./outbound-adapter.js")); +const { slackOutbound } = await import("./outbound-adapter.js"); describe("slackOutbound", () => { const cfg = { diff --git a/extensions/slack/src/send.upload.test.ts b/extensions/slack/src/send.upload.test.ts index 3db8493720f..bda7b20457a 100644 --- a/extensions/slack/src/send.upload.test.ts +++ b/extensions/slack/src/send.upload.test.ts @@ -54,11 +54,8 @@ vi.mock("./runtime-api.js", async () => { }; }); -let sendMessageSlack: typeof import("./send.js").sendMessageSlack; -let clearSlackDmChannelCache: typeof import("./send.js").clearSlackDmChannelCache; -let clearSlackSendQueuesForTest: typeof import("./send.js").clearSlackSendQueuesForTest; -({ sendMessageSlack, clearSlackDmChannelCache, clearSlackSendQueuesForTest } = - await import("./send.js")); +const { sendMessageSlack, clearSlackDmChannelCache, clearSlackSendQueuesForTest } = + await import("./send.js"); const SLACK_TEST_CFG = { channels: { slack: { botToken: "xoxb-test" } } }; type UploadTestClient = WebClient & { diff --git a/extensions/talk-voice/index.test.ts b/extensions/talk-voice/index.test.ts index 5b30985a77f..9e4063744b2 100644 --- a/extensions/talk-voice/index.test.ts +++ b/extensions/talk-voice/index.test.ts @@ -3,7 +3,8 @@ import { describe, expect, it, vi } from "vitest"; import type { PluginRuntime } from "./api.js"; import register from "./index.js"; -function createHarness(config: Record) { +function createHarness(initialConfig: Record) { + let config = initialConfig; let command: OpenClawPluginCommandDefinition | undefined; const runtime = { config: { diff --git a/extensions/telegram/src/bot-message-context.ts b/extensions/telegram/src/bot-message-context.ts index 9d5a81cd3ac..9ae4b60d3d3 100644 --- a/extensions/telegram/src/bot-message-context.ts +++ b/extensions/telegram/src/bot-message-context.ts @@ -242,7 +242,7 @@ export const buildTelegramMessageContext = async ({ const freshCfg = loadFreshConfig?.() ?? (runtime?.getRuntimeConfig ?? (await loadTelegramMessageContextRuntime()).getRuntimeConfig)(); - let { route, bindingMode } = resolveTelegramConversationRoute({ + const conversationRoute = resolveTelegramConversationRoute({ cfg: freshCfg, accountId: account.accountId, chatId, @@ -252,6 +252,8 @@ export const buildTelegramMessageContext = async ({ senderId, topicAgentId: topicConfig?.agentId, }); + const { bindingMode } = conversationRoute; + let { route } = conversationRoute; const requiresExplicitAccountBinding = ( candidate: ReturnType["route"], ): boolean => @@ -426,7 +428,7 @@ export const buildTelegramMessageContext = async ({ const activationOverride = resolveGroupActivation({ chatId, messageThreadId: resolvedThreadId, - sessionKey: sessionKey, + sessionKey, agentId: route.agentId, }); const baseRequireMention = resolveGroupRequireMention(chatId); diff --git a/extensions/telegram/src/bot-message-dispatch.ts b/extensions/telegram/src/bot-message-dispatch.ts index 127f5cfb4b7..ea5d6b8454c 100644 --- a/extensions/telegram/src/bot-message-dispatch.ts +++ b/extensions/telegram/src/bot-message-dispatch.ts @@ -1546,7 +1546,7 @@ export const dispatchTelegramMessage = async ({ draftMaxChars, applyTextToPayload, applyTextToFollowUpPayload, - splitFinalTextForStream: splitFinalTextForStream, + splitFinalTextForStream, sendPayload, flushDraftLane, stopDraftLane: async (lane) => { diff --git a/extensions/telegram/src/bot-native-commands.ts b/extensions/telegram/src/bot-native-commands.ts index 33b467716c9..0aee5db5631 100644 --- a/extensions/telegram/src/bot-native-commands.ts +++ b/extensions/telegram/src/bot-native-commands.ts @@ -741,7 +741,7 @@ export const registerTelegramNativeCommands = ({ "nativeSkillsEnabled is true but no agent route is bound for this Telegram account; skill commands will not appear in the native menu.", ); } - let skillCommands = + const skillCommands = nativeEnabled && nativeSkillsEnabled && boundRoute ? telegramDeps.listSkillCommandsForAgents({ cfg, @@ -920,7 +920,7 @@ export const registerTelegramNativeCommands = ({ isForum, messageThreadId: resolvedThreadId ?? messageThreadId, }); - let { route, bindingMode } = resolveTelegramConversationRoute({ + const { route, bindingMode } = resolveTelegramConversationRoute({ cfg: runtimeCfg, accountId, chatId, diff --git a/extensions/telegram/src/draft-stream.ts b/extensions/telegram/src/draft-stream.ts index eef79aa9aa1..1a314aa7549 100644 --- a/extensions/telegram/src/draft-stream.ts +++ b/extensions/telegram/src/draft-stream.ts @@ -117,11 +117,6 @@ export function createTelegramDraftStream(params: { let previewRevision = 0; let generation = 0; let deliveredTextOffset = 0; - let resetStreamToNewMessage: (options?: { - keepFinal?: boolean; - keepPending?: boolean; - resetOffset?: boolean; - }) => void; type PreviewSendParams = { renderedText: string; renderedParseMode: "HTML" | undefined; @@ -316,7 +311,11 @@ export function createTelegramDraftStream(params: { streamState.final = true; }; - resetStreamToNewMessage = (options) => { + const resetStreamToNewMessage: (options?: { + keepFinal?: boolean; + keepPending?: boolean; + resetOffset?: boolean; + }) => void = (options) => { streamState.stopped = false; streamState.final = options?.keepFinal === true; generation += 1; diff --git a/extensions/telegram/src/lane-delivery.test.ts b/extensions/telegram/src/lane-delivery.test.ts index 8c9390e9f9c..df9ff08f02c 100644 --- a/extensions/telegram/src/lane-delivery.test.ts +++ b/extensions/telegram/src/lane-delivery.test.ts @@ -235,9 +235,8 @@ describe("createLaneTextDeliverer", () => { "Ja. Hier nochmal sauber Schritt fuer Schritt. Einen API Key kopiert man aus der Google Cloud Console. Danach pruefst du die Projekt- und API-Einstellungen."; const truncatedFinal = "Ja. Hier nochmal sauber Schritt fuer Schritt. Einen API Key kopiert man..."; - let answer: ReturnType; let deliveredText = ""; - answer = createTestDraftStream({ + const answer: ReturnType = createTestDraftStream({ onStop: () => { answer.setMessageId(999); deliveredText = fullAnswer; diff --git a/extensions/telegram/src/thread-bindings.ts b/extensions/telegram/src/thread-bindings.ts index d0d750e39a1..7f6fc96f0b6 100644 --- a/extensions/telegram/src/thread-bindings.ts +++ b/extensions/telegram/src/thread-bindings.ts @@ -729,7 +729,7 @@ export function createTelegramThreadBindingManager(params: { if (placement === "child") { const rawConversationId = input.conversation.conversationId?.trim() ?? ""; const rawParent = input.conversation.parentConversationId?.trim() ?? ""; - let chatId = rawParent || rawConversationId; + const chatId = rawParent || rawConversationId; if (!chatId) { logVerbose( `telegram: child bind failed: could not resolve group chat ID from conversationId=${rawConversationId}`, diff --git a/extensions/tlon/src/monitor/index.ts b/extensions/tlon/src/monitor/index.ts index 0610e2a8daa..11f1bd37327 100644 --- a/extensions/tlon/src/monitor/index.ts +++ b/extensions/tlon/src/monitor/index.ts @@ -371,7 +371,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise { ... }); */ export function createSettingsManager(api: UrbitSSEClient, logger?: SettingsLogger) { - let state: TlonSettingsState = { + const state: TlonSettingsState = { current: {}, loaded: false, }; diff --git a/extensions/twitch/src/probe.ts b/extensions/twitch/src/probe.ts index dca89114e71..4a78c95ffb5 100644 --- a/extensions/twitch/src/probe.ts +++ b/extensions/twitch/src/probe.ts @@ -50,9 +50,6 @@ export async function probeTwitch( // Create a promise that resolves when connected const connectionPromise = new Promise((resolve, reject) => { let settled = false; - let connectListener: ReturnType | undefined; - let disconnectListener: ReturnType | undefined; - let authFailListener: ReturnType | undefined; const cleanup = () => { if (settled) { @@ -65,22 +62,26 @@ export async function probeTwitch( }; // Success: connection established - connectListener = client?.onConnect(() => { - cleanup(); - resolve(); - }); + const connectListener: ReturnType | undefined = client?.onConnect( + () => { + cleanup(); + resolve(); + }, + ); // Failure: disconnected (e.g., auth failed) - disconnectListener = client?.onDisconnect((_manually, reason) => { - cleanup(); - reject(reason || new Error("Disconnected")); - }); + const disconnectListener: ReturnType | undefined = + client?.onDisconnect((_manually, reason) => { + cleanup(); + reject(reason || new Error("Disconnected")); + }); // Failure: authentication failed - authFailListener = client?.onAuthenticationFailure(() => { - cleanup(); - reject(new Error("Authentication failed")); - }); + const authFailListener: ReturnType | undefined = + client?.onAuthenticationFailure(() => { + cleanup(); + reject(new Error("Authentication failed")); + }); }); let timeoutHandle: ReturnType | undefined; diff --git a/extensions/twitch/src/twitch-client.ts b/extensions/twitch/src/twitch-client.ts index e8e92ea8e4d..cfa1ac285a6 100644 --- a/extensions/twitch/src/twitch-client.ts +++ b/extensions/twitch/src/twitch-client.ts @@ -200,7 +200,6 @@ export class TwitchClientManager { let settled = false; let authRetryPending = false; const listeners: Array<{ unbind: () => void }> = []; - let timeout: NodeJS.Timeout | undefined; const finish = (error?: Error) => { if (settled) { return; @@ -248,7 +247,7 @@ export class TwitchClientManager { ); }), ); - timeout = setTimeout( + const timeout: NodeJS.Timeout | undefined = setTimeout( () => finish(new Error(`Timed out connecting to Twitch as ${account.username}`)), connectTimeoutMs, ); diff --git a/extensions/voice-call/src/webhook/tailscale.ts b/extensions/voice-call/src/webhook/tailscale.ts index b1751f653dc..cbff1e7b57d 100644 --- a/extensions/voice-call/src/webhook/tailscale.ts +++ b/extensions/voice-call/src/webhook/tailscale.ts @@ -41,7 +41,6 @@ function runTailscaleCommand( let stdout: TailscaleCommandStdout = { bytes: 0, exceeded: false, text: "" }; let settled = false; - let timer: ReturnType; const finish = (result: { code: number; stdout: string }) => { if (settled) { return; @@ -59,7 +58,7 @@ function runTailscaleCommand( } }); - timer = setTimeout(() => { + const timer: ReturnType = setTimeout(() => { proc.kill("SIGKILL"); finish({ code: -1, stdout: "" }); }, timeoutMs); diff --git a/extensions/whatsapp/src/inbound/send-api.ts b/extensions/whatsapp/src/inbound/send-api.ts index 69627b0aaee..c5caee6803c 100644 --- a/extensions/whatsapp/src/inbound/send-api.ts +++ b/extensions/whatsapp/src/inbound/send-api.ts @@ -70,9 +70,10 @@ export function createWebSendApi(params: { to: string, text: string, mediaBuffer?: Buffer, - mediaType?: string, + mediaTypeInput?: string, sendOptions?: ActiveWebSendOptions, ): Promise => { + let mediaType = mediaTypeInput; const jid = resolveOutboundJid(to); let payload: AnyMessageContent; if (mediaBuffer) { diff --git a/extensions/workboard/src/store.test.ts b/extensions/workboard/src/store.test.ts index 3c238cdedc6..b38f7d8bf38 100644 --- a/extensions/workboard/src/store.test.ts +++ b/extensions/workboard/src/store.test.ts @@ -1633,7 +1633,6 @@ describe("WorkboardStore", () => { }); it("does not drop concurrent updates while refreshing diagnostics", async () => { - let store!: WorkboardStore; let proofPromise: Promise | undefined; let triggered = false; const keyed = createMemoryStore({ @@ -1646,7 +1645,7 @@ describe("WorkboardStore", () => { await new Promise((resolve) => setTimeout(resolve, 0)); }, }); - store = new WorkboardStore(keyed); + const store: WorkboardStore = new WorkboardStore(keyed); const card = await store.create({ title: "Ready too long", agentId: "main" }); await store.refreshDiagnostics(Date.now() + 2 * 24 * 60 * 60 * 1000); diff --git a/extensions/zalo/src/actions.ts b/extensions/zalo/src/actions.ts index 0f24576c86f..ee28ec984f3 100644 --- a/extensions/zalo/src/actions.ts +++ b/extensions/zalo/src/actions.ts @@ -44,7 +44,7 @@ export const zaloMessageActions: ChannelMessageActionAdapter = { const result = await sendMessageZalo(to ?? "", content ?? "", { accountId: accountId ?? undefined, mediaUrl: mediaUrl ?? undefined, - cfg: cfg, + cfg, }); if (!result.ok) { diff --git a/extensions/zalo/src/setup-core.ts b/extensions/zalo/src/setup-core.ts index cc723003a3d..aade1281cac 100644 --- a/extensions/zalo/src/setup-core.ts +++ b/extensions/zalo/src/setup-core.ts @@ -60,7 +60,7 @@ export const zaloDmPolicy: ChannelSetupDmPolicy = { }, getCurrent: (cfg, accountId) => resolveZaloAccount({ - cfg: cfg, + cfg, accountId: accountId ?? resolveDefaultZaloAccountId(cfg), }).config.dmPolicy ?? "pairing", setPolicy: (cfg, policy, accountId) => { @@ -69,7 +69,7 @@ export const zaloDmPolicy: ChannelSetupDmPolicy = { ? (normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID) : resolveDefaultZaloAccountId(cfg); const resolved = resolveZaloAccount({ - cfg: cfg, + cfg, accountId: resolvedAccountId, }); if (resolvedAccountId === DEFAULT_ACCOUNT_ID) { diff --git a/extensions/zalouser/src/channel.adapters.ts b/extensions/zalouser/src/channel.adapters.ts index 59650dd7cab..73cb1a28380 100644 --- a/extensions/zalouser/src/channel.adapters.ts +++ b/extensions/zalouser/src/channel.adapters.ts @@ -108,7 +108,7 @@ function resolveZalouserRequireMention(params: ChannelGroupContext): boolean { async function sendZalouserTextFromContext({ to, text, accountId, cfg }: ZalouserSendTextContext) { const { sendMessageZalouser } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const account = resolveZalouserAccountSync({ cfg, accountId }); const target = parseZalouserOutboundTarget(to); return await sendMessageZalouser(target.threadId, text, { profile: account.profile, @@ -129,7 +129,7 @@ async function sendZalouserMediaFromContext({ mediaReadFile, }: ZalouserSendMediaContext) { const { sendMessageZalouser } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const account = resolveZalouserAccountSync({ cfg, accountId }); const target = parseZalouserOutboundTarget(to); return await sendMessageZalouser(target.threadId, text, { profile: account.profile, @@ -279,7 +279,7 @@ export const zalouserResolverAdapter = { try { const runtimeModule = await loadZalouserChannelRuntime(); const account = resolveZalouserAccountSync({ - cfg: cfg, + cfg, accountId: accountId ?? resolveDefaultZalouserAccountId(cfg), }); if (kind === "user") { @@ -329,7 +329,7 @@ export const zalouserAuthAdapter = { }) => { const { startZaloQrLogin, waitForZaloQrLogin } = await loadZalouserChannelRuntime(); const account = resolveZalouserAccountSync({ - cfg: cfg, + cfg, accountId: accountId ?? resolveDefaultZalouserAccountId(cfg), }); @@ -381,7 +381,7 @@ export const zalouserPairingTextAdapter = { normalizeAllowEntry: createPairingPrefixStripper(/^(zalouser|zlu):/i), notify: async ({ cfg, id, message }: { cfg: OpenClawConfig; id: string; message: string }) => { const { sendMessageZalouser } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg }); + const account = resolveZalouserAccountSync({ cfg }); const authenticated = await checkZcaAuthenticated(account.profile); if (!authenticated) { throw new Error("Zalouser not authenticated"); diff --git a/extensions/zalouser/src/channel.ts b/extensions/zalouser/src/channel.ts index 7d733341f66..0362878bbea 100644 --- a/extensions/zalouser/src/channel.ts +++ b/extensions/zalouser/src/channel.ts @@ -78,7 +78,7 @@ export const zalouserPlugin: ChannelPlugin { const { getZaloUserInfo } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const account = resolveZalouserAccountSync({ cfg, accountId }); const parsed = await getZaloUserInfo(account.profile); if (!parsed?.userId) { return null; @@ -92,7 +92,7 @@ export const zalouserPlugin: ChannelPlugin { const { listZaloFriendsMatching } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const account = resolveZalouserAccountSync({ cfg, accountId }); const friends = await listZaloFriendsMatching(account.profile, query); const rows = friends.map((friend) => mapUser({ @@ -106,7 +106,7 @@ export const zalouserPlugin: ChannelPlugin { const { listZaloGroupsMatching } = await loadZalouserChannelRuntime(); - const account = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const account = resolveZalouserAccountSync({ cfg, accountId }); const groups = await listZaloGroupsMatching(account.profile, query); const rows = groups.map((group) => mapGroup({ diff --git a/extensions/zalouser/src/monitor.ts b/extensions/zalouser/src/monitor.ts index 4a0c461778e..c33efde1973 100644 --- a/extensions/zalouser/src/monitor.ts +++ b/extensions/zalouser/src/monitor.ts @@ -816,7 +816,8 @@ async function deliverZalouserReply(params: { export async function monitorZalouserProvider( options: ZalouserMonitorOptions, ): Promise { - let { account, config } = options; + const { config } = options; + let { account } = options; const { abortSignal, statusSink, runtime } = options; const core = getZalouserRuntime(); diff --git a/extensions/zalouser/src/setup-surface.ts b/extensions/zalouser/src/setup-surface.ts index 4f781e3a1f4..aa64bc93e53 100644 --- a/extensions/zalouser/src/setup-surface.ts +++ b/extensions/zalouser/src/setup-surface.ts @@ -236,7 +236,7 @@ const zalouserDmPolicy: ChannelSetupDmPolicy = { ? (normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID) : resolveDefaultZalouserAccountId(cfg); return await promptZalouserAllowFrom({ - cfg: cfg, + cfg, prompter, accountId: id, }); @@ -438,7 +438,7 @@ export const zalouserSetupWizard: ChannelSetupWizard = { ); return []; } - const updatedAccount = resolveZalouserAccountSync({ cfg: cfg, accountId }); + const updatedAccount = resolveZalouserAccountSync({ cfg, accountId }); try { const resolved = await resolveZaloGroupsByEntries({ profile: updatedAccount.profile, diff --git a/extensions/zalouser/src/text-styles.ts b/extensions/zalouser/src/text-styles.ts index a7c1557a6c2..f01e9bd4542 100644 --- a/extensions/zalouser/src/text-styles.ts +++ b/extensions/zalouser/src/text-styles.ts @@ -133,7 +133,7 @@ export function parseZalouserTextStyles(input: string): { text: string; styles: continue; } - let line = unquotedLine; + const line = unquotedLine; const openingFence = resolveOpeningFence(rawLine); if (openingFence) { const fenceLine = openingFence.quoteIndent > 0 ? unquotedLine : rawLine; diff --git a/packages/agent-core/src/harness/env/nodejs.ts b/packages/agent-core/src/harness/env/nodejs.ts index c42f205a00e..5ba6fd0dcca 100644 --- a/packages/agent-core/src/harness/env/nodejs.ts +++ b/packages/agent-core/src/harness/env/nodejs.ts @@ -288,7 +288,7 @@ export class NodeExecutionEnv implements ExecutionEnv { let timedOut = false; let callbackError: ExecutionError | undefined; let child: ReturnType | undefined; - let timeoutId: ReturnType | undefined; + const timeoutRef: { current?: ReturnType } = {}; const onAbort = () => { if (child?.pid) { @@ -299,8 +299,8 @@ export class NodeExecutionEnv implements ExecutionEnv { const settle = ( result: Result<{ stdout: string; stderr: string; exitCode: number }, ExecutionError>, ) => { - if (timeoutId) { - clearTimeout(timeoutId); + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); } if (options?.abortSignal) { options.abortSignal.removeEventListener("abort", onAbort); @@ -327,7 +327,7 @@ export class NodeExecutionEnv implements ExecutionEnv { } const timeoutMs = resolveExecTimeoutMs(options?.timeout); - timeoutId = + timeoutRef.current = timeoutMs === undefined ? undefined : setTimeout(() => { diff --git a/packages/gateway-client/src/client.ts b/packages/gateway-client/src/client.ts index 6181e18d95d..2ffac5259c3 100644 --- a/packages/gateway-client/src/client.ts +++ b/packages/gateway-client/src/client.ts @@ -1470,7 +1470,6 @@ export class GatewayClient { : this.requestTimeoutMs; const signal = opts?.signal; const p = new Promise((resolve, reject) => { - let abortHandler: (() => void) | undefined; const timeout = timeoutMs === null ? null @@ -1488,7 +1487,7 @@ export class GatewayClient { signal.removeEventListener("abort", abortHandler); } }; - abortHandler = () => { + const abortHandler: (() => void) | undefined = () => { const pending = this.pending.get(id); this.pending.delete(id); pending?.cleanup?.(); diff --git a/packages/memory-host-sdk/src/host/backend-config.ts b/packages/memory-host-sdk/src/host/backend-config.ts index 19202ede579..42e84d0bc5e 100644 --- a/packages/memory-host-sdk/src/host/backend-config.ts +++ b/packages/memory-host-sdk/src/host/backend-config.ts @@ -159,7 +159,7 @@ function isPathInsideRoot(candidatePath: string, rootPath: string): boolean { } function ensureUniqueName(base: string, existing: Set): string { - let name = sanitizeName(base); + const name = sanitizeName(base); if (!existing.has(name)) { existing.add(name); return name; diff --git a/packages/speech-core/src/tts.ts b/packages/speech-core/src/tts.ts index 0a99a6fd077..1d391024b4a 100644 --- a/packages/speech-core/src/tts.ts +++ b/packages/speech-core/src/tts.ts @@ -598,9 +598,10 @@ function getResolvedSpeechProviderConfigForVoiceModel(params: { } export function resolveTtsConfig( - cfg: OpenClawConfig, + cfgInput: OpenClawConfig, contextOrAgentId?: string | TtsConfigResolutionContext, ): ResolvedTtsConfig { + let cfg = cfgInput; cfg = resolveTtsRuntimeConfig(cfg); const raw: TtsConfig = resolveEffectiveTtsConfig(cfg, contextOrAgentId); const providerSource = raw.provider ? "config" : "default"; @@ -691,9 +692,10 @@ function resolveEffectiveTtsAutoState(params: { } export function buildTtsSystemPromptHint( - cfg: OpenClawConfig, + cfgInput: OpenClawConfig, agentId?: string, ): string | undefined { + let cfg = cfgInput; cfg = resolveTtsRuntimeConfig(cfg); const { autoMode, prefsPath } = resolveEffectiveTtsAutoState({ cfg, agentId }); if (autoMode === "off") { diff --git a/scripts/crabbox-wrapper.mjs b/scripts/crabbox-wrapper.mjs index 0f62d0f2940..a9496a07996 100755 --- a/scripts/crabbox-wrapper.mjs +++ b/scripts/crabbox-wrapper.mjs @@ -428,7 +428,8 @@ function crabboxOptionArgs(commandArgs) { return delimiter >= 0 ? commandArgs.slice(0, delimiter) : commandArgs; } -function commandProvider(commandArgs) { +function commandProvider(commandArgsInput) { + let commandArgs = commandArgsInput; commandArgs = crabboxOptionArgs(commandArgs); for (let index = 0; index < commandArgs.length; index += 1) { const arg = commandArgs[index]; @@ -495,7 +496,8 @@ function enforceBrokeredAws(commandArgs, providerName) { process.exit(2); } -function optionValue(commandArgs, name) { +function optionValue(commandArgsInput, name) { + let commandArgs = commandArgsInput; commandArgs = crabboxOptionArgs(commandArgs); for (let index = 0; index < commandArgs.length; index += 1) { const arg = commandArgs[index]; @@ -509,7 +511,8 @@ function optionValue(commandArgs, name) { return ""; } -function hasOption(commandArgs, name) { +function hasOption(commandArgsInput, name) { + let commandArgs = commandArgsInput; commandArgs = crabboxOptionArgs(commandArgs); const shortName = name.replace(/^--/u, "-"); for (const arg of commandArgs) { @@ -716,7 +719,8 @@ function commandRuntimeEntrypoint(commandArgs) { return ""; } -function commandWordsRuntimeEntrypoint(words) { +function commandWordsRuntimeEntrypoint(wordsInput) { + let words = wordsInput; words = normalizeExecutableWords(words); const first = (words[0] ?? "").split("/").pop(); if (jsRuntimeEntrypoints.has(first)) { @@ -746,7 +750,8 @@ function commandNeedsAwsMacosPackageManager(commandArgs) { return commandWordsNeedAwsMacosPackageManager(normalizedCommandWords(commandArgs)); } -function commandWordsNeedAwsMacosPackageManager(words) { +function commandWordsNeedAwsMacosPackageManager(wordsInput) { + let words = wordsInput; words = normalizeExecutableWords(words); const first = (words[0] ?? "").split("/").pop(); if (awsMacosCorepackEntrypoints.has(first)) { @@ -768,7 +773,8 @@ function isChangedGateCommand(commandArgs) { return isChangedGateCommandWords(words); } -function isChangedGateCommandWords(words) { +function isChangedGateCommandWords(wordsInput) { + let words = wordsInput; words = normalizeExecutableWords(words); if (isChangedGateWords(words)) { return true; @@ -780,7 +786,8 @@ function isChangedGateCommandWords(words) { : false; } -function isChangedGateWords(words) { +function isChangedGateWords(wordsInput) { + let words = wordsInput; words = normalizeExecutableWords(words); if (words[0] === "corepack") { words.shift(); @@ -848,7 +855,8 @@ function normalizeExecutableWords(words) { return normalizedCommandWords(stripShellExecutionPrefixes(words)); } -function stripShellExecutionPrefixes(words) { +function stripShellExecutionPrefixes(wordsInput) { + let words = wordsInput; words = [...words]; for (;;) { const first = shellWordBasename(words[0]); diff --git a/scripts/dev/test-device-pair-telegram.ts b/scripts/dev/test-device-pair-telegram.ts index 730f6e73a8a..98da8baff4c 100644 --- a/scripts/dev/test-device-pair-telegram.ts +++ b/scripts/dev/test-device-pair-telegram.ts @@ -55,12 +55,12 @@ const result = await executePluginCommand({ config: cfg, from: `telegram:${chatId}`, to: `telegram:${chatId}`, - accountId: accountId, + accountId, }); if (result.text) { await sendMessageTelegram(chatId, result.text, { - accountId: accountId, + accountId, }); } diff --git a/scripts/e2e/lib/fixtures/plugins.mjs b/scripts/e2e/lib/fixtures/plugins.mjs index b61b53b9928..0217d7e6c43 100644 --- a/scripts/e2e/lib/fixtures/plugins.mjs +++ b/scripts/e2e/lib/fixtures/plugins.mjs @@ -121,8 +121,8 @@ function writePluginWithCliRegistryDependency([ writePluginManifest(path.join(dir, "openclaw.plugin.json"), id); } -function writeClaudeBundle([root]) { - root = requireArg(root, "root"); +function writeClaudeBundle(args) { + const root = requireArg(args[0], "root"); writeJson(path.join(root, ".claude-plugin", "plugin.json"), { name: "claude-bundle-e2e" }); write( path.join(root, "commands", "office-hours.md"), @@ -130,8 +130,8 @@ function writeClaudeBundle([root]) { ); } -function writePluginMarketplace([root]) { - root = requireArg(root, "root"); +function writePluginMarketplace(args) { + const root = requireArg(args[0], "root"); writeJson(path.join(root, ".claude-plugin", "marketplace.json"), { name: "Fixture Marketplace", version: "1.0.0", diff --git a/scripts/e2e/mcp-websocket-open.ts b/scripts/e2e/mcp-websocket-open.ts index 166765d29fd..2702d87ede7 100644 --- a/scripts/e2e/mcp-websocket-open.ts +++ b/scripts/e2e/mcp-websocket-open.ts @@ -29,7 +29,6 @@ export function waitForWebSocketOpen( ): Promise { return new Promise((resolve, reject) => { let settled = false; - let timer: ReturnType; const cleanup = () => { clearTimeout(timer); @@ -62,7 +61,7 @@ export function waitForWebSocketOpen( const suffix = closeDetails ? `: ${closeDetails}` : ""; rejectOpen(new Error(`closed before open${suffix}`)); }; - timer = setTimeout(() => { + const timer: ReturnType = setTimeout(() => { const consumeAbortError = () => {}; const removeAbortErrorConsumer = () => { ws.off?.("error", consumeAbortError); diff --git a/scripts/e2e/telegram-user-crabbox-proof.ts b/scripts/e2e/telegram-user-crabbox-proof.ts index cd0a97de7c3..b49bf45a8b7 100644 --- a/scripts/e2e/telegram-user-crabbox-proof.ts +++ b/scripts/e2e/telegram-user-crabbox-proof.ts @@ -231,7 +231,8 @@ function parsePositiveInteger(value: string, label: string) { return parsed; } -function parseArgs(argv: string[]): Options { +function parseArgs(argvInput: string[]): Options { + let argv = argvInput; argv = argv[0] === "--" ? argv.slice(1) : argv; const commands = new Set([ "finish", diff --git a/scripts/e2e/telegram-user-credential-io.ts b/scripts/e2e/telegram-user-credential-io.ts index cb4031de912..df35832dfaa 100644 --- a/scripts/e2e/telegram-user-credential-io.ts +++ b/scripts/e2e/telegram-user-credential-io.ts @@ -78,7 +78,6 @@ export function runCommand( let stdout = ""; let stderr = ""; let settled = false; - let timeout: NodeJS.Timeout; let killTimer: NodeJS.Timeout | undefined; let timedOutError: Error | undefined; const timeoutMs = Math.max(1, options.timeoutMs); @@ -97,7 +96,7 @@ export function runCommand( clearTimers(); reject(error); }; - timeout = setTimeout(() => { + const timeout: NodeJS.Timeout = setTimeout(() => { if (settled) { return; } diff --git a/scripts/package-openclaw-for-docker.mjs b/scripts/package-openclaw-for-docker.mjs index 4183a6eb5d3..4b04e17ed6d 100644 --- a/scripts/package-openclaw-for-docker.mjs +++ b/scripts/package-openclaw-for-docker.mjs @@ -104,7 +104,6 @@ function run(command, args, cwd, options = {}) { let stdout = ""; let stdoutBytes = 0; let settled = false; - let timeout; let forceKillTimeout; const maxCapturedStdoutBytes = Math.max( 1, @@ -152,7 +151,7 @@ function run(command, args, cwd, options = {}) { forceKillTimeout.unref?.(); }; ACTIVE_CHILD_KILLERS.add(killChild); - timeout = + const timeout = options.timeoutMs === undefined ? undefined : setTimeout(() => { diff --git a/scripts/run-additional-boundary-checks.mjs b/scripts/run-additional-boundary-checks.mjs index d318bca56a3..1124f8b4ace 100644 --- a/scripts/run-additional-boundary-checks.mjs +++ b/scripts/run-additional-boundary-checks.mjs @@ -150,7 +150,7 @@ export function createBoundedOutputBuffer(maxBytes = DEFAULT_OUTPUT_MAX_BYTES) { const append = (value) => { const text = String(value); - let textBytes = Buffer.byteLength(text); + const textBytes = Buffer.byteLength(text); if (textBytes >= limit) { const buffer = Buffer.from(text); const tail = buffer.subarray(buffer.length - limit).toString("utf8"); @@ -185,9 +185,7 @@ export function createBoundedOutputBuffer(maxBytes = DEFAULT_OUTPUT_MAX_BYTES) { append, read() { const output = chunks.join(""); - return truncated - ? `[output truncated to last ${limit} bytes]\n${output}` - : output; + return truncated ? `[output truncated to last ${limit} bytes]\n${output}` : output; }, }; } diff --git a/scripts/run-node.mjs b/scripts/run-node.mjs index 2cd193a883f..d99d05cc731 100644 --- a/scripts/run-node.mjs +++ b/scripts/run-node.mjs @@ -910,8 +910,6 @@ const resolveRunNodeDiagnosticArgs = (deps) => { const waitForSpawnedProcess = async (childProcess, deps) => { let forwardedSignal = null; - let onSigInt; - let onSigTerm; const cleanupSignals = () => { if (onSigInt) { @@ -934,10 +932,10 @@ const waitForSpawnedProcess = async (childProcess, deps) => { } }; - onSigInt = () => { + const onSigInt = () => { forwardSignal("SIGINT"); }; - onSigTerm = () => { + const onSigTerm = () => { forwardSignal("SIGTERM"); }; diff --git a/scripts/test-docker-all.mjs b/scripts/test-docker-all.mjs index 18fa3f9c9b5..b5c9daa4f7e 100644 --- a/scripts/test-docker-all.mjs +++ b/scripts/test-docker-all.mjs @@ -1013,8 +1013,7 @@ async function runLanePool(poolLanes, baseEnv, logDir, parallelism, options) { await waitForLaneStartSlot(); reserve(poolLane); activeLanes.set(poolLane.name, { name: poolLane.name, startedAt: Date.now() }); - let promise; - promise = runLane(poolLane, baseEnv, logDir, options.timeoutMs) + const promise = runLane(poolLane, baseEnv, logDir, options.timeoutMs) .then((result) => ({ lane: poolLane, promise, result })) .finally(() => { activeLanes.delete(poolLane.name); diff --git a/scripts/test-projects.test-support.mjs b/scripts/test-projects.test-support.mjs index 937071c19f6..5f3195899f0 100644 --- a/scripts/test-projects.test-support.mjs +++ b/scripts/test-projects.test-support.mjs @@ -2303,7 +2303,8 @@ function hasConservativeVitestWorkerBudget(env) { return workerBudget !== null && workerBudget <= 1; } -export function resolveParallelFullSuiteConcurrency(specCount, env, hostInfo) { +export function resolveParallelFullSuiteConcurrency(specCount, envInput, hostInfo) { + let env = envInput; env ??= process.env; const override = parsePositiveInt(env.OPENCLAW_TEST_PROJECTS_PARALLEL); if (override !== null) { diff --git a/scripts/update-clawtributors.ts b/scripts/update-clawtributors.ts index ef266151d20..b0837fe6155 100644 --- a/scripts/update-clawtributors.ts +++ b/scripts/update-clawtributors.ts @@ -109,7 +109,7 @@ for (const line of log.split("\n")) { continue; } - let login = resolveLogin(currentName, currentEmail, apiByLogin, nameToLogin, emailToLogin); + const login = resolveLogin(currentName, currentEmail, apiByLogin, nameToLogin, emailToLogin); if (!login) { continue; } diff --git a/scripts/watch-node.mjs b/scripts/watch-node.mjs index 6cb65d6dbc9..bed025f9653 100644 --- a/scripts/watch-node.mjs +++ b/scripts/watch-node.mjs @@ -289,8 +289,6 @@ export async function runWatchMain(params = {}) { let watcher = null; let lockHandle = null; let autoDoctorAttempted = false; - let onSigInt; - let onSigTerm; const settle = (code) => { if (settled) { @@ -448,14 +446,14 @@ export async function runWatchMain(params = {}) { void resolveCreateWatcher().then(attachWatcher).catch(rejectWatcherStartupError); }; - onSigInt = () => { + const onSigInt = () => { shuttingDown = true; if (watchProcess && typeof watchProcess.kill === "function") { watchProcess.kill(WATCH_RESTART_SIGNAL); } settle(130); }; - onSigTerm = () => { + const onSigTerm = () => { shuttingDown = true; if (watchProcess && typeof watchProcess.kill === "function") { watchProcess.kill(WATCH_RESTART_SIGNAL); diff --git a/src/acp/translator.stop-reason.test.ts b/src/acp/translator.stop-reason.test.ts index ae94e055f04..b474284e554 100644 --- a/src/acp/translator.stop-reason.test.ts +++ b/src/acp/translator.stop-reason.test.ts @@ -473,7 +473,6 @@ describe("acp translator stop reason mapping", () => { it("finishes terminal prompts while rejecting stale pre-ack prompts", async () => { vi.useFakeTimers(); try { - let acceptedRunId: string | undefined; let acceptedWaitCount = 0; const requestMock = vi.fn(async (method: string, params?: Record) => { if (method === "chat.send") { @@ -520,7 +519,7 @@ describe("acp translator stop reason mapping", () => { void preAckPrompt.catch(() => {}); await Promise.resolve(); - acceptedRunId = requestMock.mock.calls.find((call) => { + const acceptedRunId: string | undefined = requestMock.mock.calls.find((call) => { const [method, requestParams] = call; return method === "chat.send" && requestParams?.sessionKey === "agent:main:first"; })?.[1]?.idempotencyKey as string | undefined; diff --git a/src/agents/acp-spawn.ts b/src/agents/acp-spawn.ts index 60560d23d50..9992b572b50 100644 --- a/src/agents/acp-spawn.ts +++ b/src/agents/acp-spawn.ts @@ -1211,7 +1211,7 @@ export async function spawnAcpDirect( }); } - let requestThreadBinding = params.thread === true; + const requestThreadBinding = params.thread === true; const runtimePolicyError = resolveAcpSpawnRuntimePolicyError({ cfg, requesterSessionKey: ctx.agentSessionKey, diff --git a/src/agents/agent-tools.ts b/src/agents/agent-tools.ts index 19d2fe78800..6228f2c74cc 100644 --- a/src/agents/agent-tools.ts +++ b/src/agents/agent-tools.ts @@ -234,7 +234,7 @@ export function resolveProcessToolScopeKey(params: { } function applyModelProviderToolPolicy( - tools: AnyAgentTool[], + toolsInput: AnyAgentTool[], params?: { config?: OpenClawConfig; modelProvider?: string; @@ -247,6 +247,7 @@ function applyModelProviderToolPolicy( suppressManagedWebSearch?: boolean; }, ): AnyAgentTool[] { + let tools = toolsInput; tools = filterLocalModelLeanTools({ tools, config: params?.config, diff --git a/src/agents/bash-process-registry.ts b/src/agents/bash-process-registry.ts index 70790d6dde5..8e8ebf5103c 100644 --- a/src/agents/bash-process-registry.ts +++ b/src/agents/bash-process-registry.ts @@ -255,7 +255,8 @@ function sumPendingChars(buffer: string[]) { return total; } -function capPendingBuffer(buffer: string[], pendingChars: number, cap: number) { +function capPendingBuffer(buffer: string[], pendingCharsInput: number, cap: number) { + let pendingChars = pendingCharsInput; if (pendingChars <= cap) { return pendingChars; } diff --git a/src/agents/bash-tools.process.ts b/src/agents/bash-tools.process.ts index 6c3bf9ead74..a2509296d57 100644 --- a/src/agents/bash-tools.process.ts +++ b/src/agents/bash-tools.process.ts @@ -149,8 +149,6 @@ async function sleepPollInterval(ms: number, signal?: AbortSignal): Promise((resolve, reject) => { - let timer: ReturnType | undefined; - let onAbort: (() => void) | undefined; const cleanup = () => { if (timer) { clearTimeout(timer); @@ -163,11 +161,11 @@ async function sleepPollInterval(ms: number, signal?: AbortSignal): Promise { + const onAbort: (() => void) | undefined = () => { cleanup(); reject(createAbortError(signal?.reason)); }; - timer = setTimeout(onResolve, ms); + const timer: ReturnType | undefined = setTimeout(onResolve, ms); timer.unref?.(); signal?.addEventListener("abort", onAbort, { once: true }); }); diff --git a/src/agents/embedded-agent-runner/context-engine-maintenance.ts b/src/agents/embedded-agent-runner/context-engine-maintenance.ts index d0f41b6fd77..2e51b291742 100644 --- a/src/agents/embedded-agent-runner/context-engine-maintenance.ts +++ b/src/agents/embedded-agent-runner/context-engine-maintenance.ts @@ -642,7 +642,6 @@ function scheduleDeferredTurnMaintenance( }); return undefined; } - let state!: DeferredTurnMaintenanceRunState; const trackedPromise = runPromise .catch((err) => { params.onScheduleFailure?.(err); @@ -670,7 +669,7 @@ function scheduleDeferredTurnMaintenance( await disposeDeferredMaintenanceContextEngine(discardedRerunParams.contextEngine); } }); - state = { + const state: DeferredTurnMaintenanceRunState = { promise: trackedPromise, rerunRequested: false, latestParams: { ...params, sessionKey }, diff --git a/src/agents/embedded-agent-runner/run.ts b/src/agents/embedded-agent-runner/run.ts index ec49cffd233..e56ca01156a 100644 --- a/src/agents/embedded-agent-runner/run.ts +++ b/src/agents/embedded-agent-runner/run.ts @@ -456,8 +456,9 @@ function buildHandledReplyPayloads(reply?: ReplyPayload) { } export async function runEmbeddedAgent( - params: RunEmbeddedAgentParams, + paramsInput: RunEmbeddedAgentParams, ): Promise { + let params = paramsInput; // Resolve sessionKey early so all downstream consumers (hooks, LCM, compaction) // receive a non-null key even when callers omit it. See #60552. const effectiveSessionKey = backfillSessionKey({ diff --git a/src/agents/embedded-agent-runner/run/attempt.model-diagnostic-events.test.ts b/src/agents/embedded-agent-runner/run/attempt.model-diagnostic-events.test.ts index f9fad48c174..0fc79dcebd1 100644 --- a/src/agents/embedded-agent-runner/run/attempt.model-diagnostic-events.test.ts +++ b/src/agents/embedded-agent-runner/run/attempt.model-diagnostic-events.test.ts @@ -553,7 +553,7 @@ describe("wrapStreamFnWithDiagnosticModelCallEvents", () => { const stream = {}; Object.defineProperty(stream, Symbol.asyncIterator, { configurable: false, - value: async function* () { + async *value() { yield { type: "text", text: "ok" }; }, }); diff --git a/src/agents/embedded-agent-runner/run/attempt.queue-message.ts b/src/agents/embedded-agent-runner/run/attempt.queue-message.ts index 426148b7109..16b30f3875b 100644 --- a/src/agents/embedded-agent-runner/run/attempt.queue-message.ts +++ b/src/agents/embedded-agent-runner/run/attempt.queue-message.ts @@ -110,8 +110,6 @@ export async function steerAndWaitForTranscriptCommit( ): Promise { await new Promise((resolve, reject) => { let settled = false; - let unsubscribe: (() => void) | undefined; - let timer: ReturnType | undefined; let terminalTimer: ReturnType | undefined; const finish = (err?: unknown) => { if (settled) { @@ -157,7 +155,7 @@ export async function steerAndWaitForTranscriptCommit( }, 0); terminalTimer.unref?.(); }; - timer = setTimeout( + const timer: ReturnType | undefined = setTimeout( () => { rejectAfterCancellation( "queued steering message was not committed to the transcript before timeout", @@ -166,7 +164,7 @@ export async function steerAndWaitForTranscriptCommit( Math.max(1, timeoutMs), ); timer.unref?.(); - unsubscribe = activeSession.subscribe((event) => { + const unsubscribe: (() => void) | undefined = activeSession.subscribe((event) => { if (isAutoRetryStartEvent(event) || isCompactionStartEvent(event)) { if (terminalTimer) { clearTimeout(terminalTimer); diff --git a/src/agents/embedded-agent-runner/run/attempt.ts b/src/agents/embedded-agent-runner/run/attempt.ts index 06c5ec48dd2..b77325293f7 100644 --- a/src/agents/embedded-agent-runner/run/attempt.ts +++ b/src/agents/embedded-agent-runner/run/attempt.ts @@ -852,7 +852,7 @@ export async function runEmbeddedAttempt( let bundleLspRuntime: Awaited> | undefined; let toolSearchCatalogRef: ToolSearchCatalogRef | undefined; let toolSearchCatalogApplied = false; - let sessionCleanupOwnsEmbeddedResources = false; + const sessionCleanupOwnsEmbeddedResources = false; let abortActiveSessionForExternalSignal: (() => Promise) | undefined; let abortRunForExternalSignal: ((isTimeout?: boolean, reason?: unknown) => void) | undefined; let isCompactionPendingForExternalSignal: (() => boolean) | undefined; @@ -2659,8 +2659,6 @@ export async function runEmbeddedAttempt( activeSession.agent.streamFn, ); - let idleTimeoutTrigger: ((error: Error) => void) | undefined; - // Wrap stream with idle timeout detection. // // Prefer the caller's explicit `runTimeoutOverrideMs` when provided — @@ -2922,7 +2920,6 @@ export async function runEmbeddedAttempt( } } }; - let queueHandleForAbandonment: EmbeddedAgentQueueHandle | undefined; const abortRun = (isTimeout = false, reason?: unknown) => { aborted = true; if (isTimeout) { @@ -2954,7 +2951,7 @@ export async function runEmbeddedAttempt( } }; abortRunForExternalSignal = abortRun; - idleTimeoutTrigger = (error) => { + const idleTimeoutTrigger: ((error: Error) => void) | undefined = (error) => { idleTimedOut = true; abortRun(true, error); }; @@ -3131,7 +3128,7 @@ export async function runEmbeddedAttempt( if (params.replyOperation) { params.replyOperation.attachBackend(queueHandle); } - queueHandleForAbandonment = queueHandle; + const queueHandleForAbandonment: EmbeddedAgentQueueHandle | undefined = queueHandle; setActiveEmbeddedRun(params.sessionId, queueHandle, params.sessionKey, params.sessionFile); let abortWarnTimer: NodeJS.Timeout | undefined; @@ -3844,7 +3841,7 @@ export async function runEmbeddedAttempt( prompt: promptForModel, historyMessages: cloneHookMessages(hookMessagesForCurrentPrompt), imagesCount: imageResult.images.length, - tools: tools, + tools, }, { runId: params.runId, diff --git a/src/agents/embedded-agent-runner/run/auth-controller.ts b/src/agents/embedded-agent-runner/run/auth-controller.ts index c48dbde433c..2341dbff83d 100644 --- a/src/agents/embedded-agent-runner/run/auth-controller.ts +++ b/src/agents/embedded-agent-runner/run/auth-controller.ts @@ -172,8 +172,7 @@ export function createEmbeddedRunAuthController(params: { } const refreshGeneration = runtimeAuthState.generation; const refreshProfileId = runtimeAuthState.profileId; - let refreshPromise: Promise; - refreshPromise = (async () => { + const refreshPromise: Promise = (async () => { const currentRuntimeAuthState = params.getRuntimeAuthState(); const sourceApiKey = currentRuntimeAuthState?.sourceApiKey.trim() ?? ""; if (!sourceApiKey) { diff --git a/src/agents/embedded-agent-runner/tool-result-context-guard.test.ts b/src/agents/embedded-agent-runner/tool-result-context-guard.test.ts index 2f7a0c9ebe1..78f19732ba6 100644 --- a/src/agents/embedded-agent-runner/tool-result-context-guard.test.ts +++ b/src/agents/embedded-agent-runner/tool-result-context-guard.test.ts @@ -628,7 +628,7 @@ describe("installContextEngineLoopHook", () => { const engine = makeMockEngine(); installHook(agent, engine, 1, () => ({ provider: "anthropic", - modelId: modelId, + modelId, promptCache: { retention: "short", lastCacheTouchAt: 123, diff --git a/src/agents/embedded-agent-subscribe.handlers.messages.ts b/src/agents/embedded-agent-subscribe.handlers.messages.ts index 94597bc3623..594c2cac2b7 100644 --- a/src/agents/embedded-agent-subscribe.handlers.messages.ts +++ b/src/agents/embedded-agent-subscribe.handlers.messages.ts @@ -813,8 +813,8 @@ export function handleMessageEnd( const parsedText = trimmedText ? parseReplyDirectives(splitTrailingDirective(trimmedText, { final: true }).text) : null; - let cleanedText = parsedText?.text ?? ""; - let { mediaUrls, hasMedia } = resolveSendableOutboundReplyParts(parsedText ?? {}); + const cleanedText = parsedText?.text ?? ""; + const { mediaUrls, hasMedia } = resolveSendableOutboundReplyParts(parsedText ?? {}); const finalizeMessageEnd = () => { ctx.state.deltaBuffer = ""; diff --git a/src/agents/harness/native-hook-relay.ts b/src/agents/harness/native-hook-relay.ts index 0c60cff9f8c..de83b1e6025 100644 --- a/src/agents/harness/native-hook-relay.ts +++ b/src/agents/harness/native-hook-relay.ts @@ -1521,12 +1521,12 @@ async function startNativeHookRelayPermissionApprovalWithBudget(params: { ); return "defer"; } - let approval!: Promise; - approval = nativeHookRelayPermissionApprovalRequester(params.request).finally(() => { - if (pendingPermissionApprovals.get(params.approvalKey) === approval) { - pendingPermissionApprovals.delete(params.approvalKey); - } - }); + const approval: Promise = + nativeHookRelayPermissionApprovalRequester(params.request).finally(() => { + if (pendingPermissionApprovals.get(params.approvalKey) === approval) { + pendingPermissionApprovals.delete(params.approvalKey); + } + }); pendingPermissionApprovals.set(params.approvalKey, approval); return approval; } diff --git a/src/agents/minimax.live.test.ts b/src/agents/minimax.live.test.ts index fdc64816f42..990f6876a9f 100644 --- a/src/agents/minimax.live.test.ts +++ b/src/agents/minimax.live.test.ts @@ -42,7 +42,9 @@ describeLive("minimax live", () => { contextWindow: 200000, maxTokens: 8192, }; - let { res, text } = await runMinimaxTextProbe(model, 128); + const probeResult = await runMinimaxTextProbe(model, 128); + const { res } = probeResult; + let { text } = probeResult; // MiniMax can spend a small token budget in hidden thinking before it emits // the visible answer. Give this smoke probe one larger retry. if (text.length === 0 && res.stopReason === "length") { diff --git a/src/agents/model-provider-auth.ts b/src/agents/model-provider-auth.ts index 6f5e6decda6..240f801757b 100644 --- a/src/agents/model-provider-auth.ts +++ b/src/agents/model-provider-auth.ts @@ -585,8 +585,6 @@ function runProviderAuthWarmWorker(params: { currentProviderAuthWarmWorker = handle; return new Promise((resolve, reject) => { let settled = false; - let timer: ReturnType | undefined; - let cancelTimer: ReturnType | undefined; const finish = (complete: () => void) => { if (settled) { return; @@ -608,13 +606,13 @@ function runProviderAuthWarmWorker(params: { void worker.terminate(); finish(() => resolve({ agents: [] })); }; - timer = setTimeout(() => { + const timer: ReturnType | undefined = setTimeout(() => { handle.cancelled = true; void worker.terminate(); finish(() => reject(new Error("provider auth warm worker timed out"))); }, params.timeoutMs); timer.unref?.(); - cancelTimer = setInterval(() => { + const cancelTimer: ReturnType | undefined = setInterval(() => { if (params.isCancelled()) { cancelWorker(); } diff --git a/src/agents/provider-local-service.ts b/src/agents/provider-local-service.ts index 565e7163b9a..239678fb036 100644 --- a/src/agents/provider-local-service.ts +++ b/src/agents/provider-local-service.ts @@ -420,7 +420,6 @@ function waitForAbort(promise: Promise, signal?: AbortSignal | null): Prom function sleep(ms: number, signal?: AbortSignal): Promise { throwIfAborted(signal); return new Promise((resolve, reject) => { - let timeout: NodeJS.Timeout; const cleanup = () => signal?.removeEventListener("abort", onAbort); const onDone = () => { cleanup(); @@ -431,7 +430,7 @@ function sleep(ms: number, signal?: AbortSignal): Promise { cleanup(); reject(toAbortError(signal)); }; - timeout = setTimeout(onDone, ms); + const timeout: NodeJS.Timeout = setTimeout(onDone, ms); timeout.unref?.(); signal?.addEventListener("abort", onAbort, { once: true }); }); @@ -478,7 +477,6 @@ function waitForChildExit( } throwIfAborted(signal); return new Promise((resolve, reject) => { - let timeout: NodeJS.Timeout; const cleanup = () => { clearTimeout(timeout); child.off("exit", onExit); @@ -493,7 +491,7 @@ function waitForChildExit( cleanup(); reject(toAbortError(signal)); }; - timeout = setTimeout(finish, timeoutMs); + const timeout: NodeJS.Timeout = setTimeout(finish, timeoutMs); timeout.unref?.(); child.once("exit", onExit); signal.addEventListener("abort", onAbort, { once: true }); diff --git a/src/agents/sessions/model-registry.test.ts b/src/agents/sessions/model-registry.test.ts index ca133047dcb..61c9a102453 100644 --- a/src/agents/sessions/model-registry.test.ts +++ b/src/agents/sessions/model-registry.test.ts @@ -9,7 +9,7 @@ import { import { AuthStorage } from "./auth-storage.js"; import { ModelRegistry } from "./model-registry.js"; -let tempDirs: string[] = []; +const tempDirs: string[] = []; function writeModelsJson(contents: unknown): string { const dir = mkdtempSync(join(tmpdir(), "openclaw-model-registry-")); diff --git a/src/agents/sessions/sdk.ts b/src/agents/sessions/sdk.ts index 73b700449a5..b1f48a859b1 100644 --- a/src/agents/sessions/sdk.ts +++ b/src/agents/sessions/sdk.ts @@ -294,8 +294,6 @@ export async function createAgentSession( ? customToolNames : defaultActiveToolNames; - let agent: Agent; - // Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth) const convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => { const converted = convertToLlm(messages); @@ -340,7 +338,7 @@ export async function createAgentSession( const runWithSessionWriteLock = async (run: () => Promise | T): Promise => options.withSessionWriteLock ? await options.withSessionWriteLock(run) : await run(); - agent = new Agent({ + const agent: Agent = new Agent({ initialState: { systemPrompt: "", model, diff --git a/src/agents/sessions/session-manager.ts b/src/agents/sessions/session-manager.ts index 932afcf3236..03ccc6008c1 100644 --- a/src/agents/sessions/session-manager.ts +++ b/src/agents/sessions/session-manager.ts @@ -327,8 +327,9 @@ export function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEnt export function buildSessionContext( entries: SessionEntry[], leafId?: string | null, - byId?: Map, + byIdInput?: Map, ): SessionContext { + let byId = byIdInput; // Build uuid index if not available if (!byId) { byId = new Map(); @@ -612,9 +613,7 @@ async function buildSessionInfosWithConcurrency( if (!file) { return; } - - let task: Promise; - task = buildSessionInfo(file) + const task: Promise = buildSessionInfo(file) .then((info) => { results[index] = info; }) diff --git a/src/agents/subagent-announce.ts b/src/agents/subagent-announce.ts index acb22bca884..e9ecd22fc2d 100644 --- a/src/agents/subagent-announce.ts +++ b/src/agents/subagent-announce.ts @@ -568,7 +568,7 @@ export async function runSubagentAnnounceFlow(params: { sourceTool: "subagent_announce", targetRequesterSessionKey, requesterIsSubagent, - expectsCompletionMessage: expectsCompletionMessage, + expectsCompletionMessage, bestEffortDeliver: params.bestEffortDeliver, directIdempotencyKey, signal: params.signal, diff --git a/src/agents/tool-display.ts b/src/agents/tool-display.ts index 4dba454f381..aba86d6fbc8 100644 --- a/src/agents/tool-display.ts +++ b/src/agents/tool-display.ts @@ -54,7 +54,7 @@ export function resolveToolDisplay(params: { const emoji = spec?.emoji ?? FALLBACK.emoji ?? "🧩"; const title = spec?.title ?? defaultTitle(name); const label = spec?.label ?? title; - let { verb, detail } = resolveToolVerbAndDetailForArgs({ + const toolDisplayParts = resolveToolVerbAndDetailForArgs({ toolKey: key, args: params.args, meta: params.meta, @@ -65,6 +65,8 @@ export function resolveToolDisplay(params: { detailMaxEntries: MAX_DETAIL_ENTRIES, detailFormatKey: (raw) => formatDetailKey(raw, DETAIL_LABEL_OVERRIDES), }); + const { verb } = toolDisplayParts; + let { detail } = toolDisplayParts; if (detail) { detail = shortenHomeInString(detail); diff --git a/src/agents/tool-loop-detection.ts b/src/agents/tool-loop-detection.ts index 0069ee8de49..ce7a8e1e53c 100644 --- a/src/agents/tool-loop-detection.ts +++ b/src/agents/tool-loop-detection.ts @@ -83,7 +83,7 @@ function asPositiveInt(value: number | undefined, fallback: number): number { } function resolveLoopDetectionConfig(config?: ToolLoopDetectionConfig): ResolvedLoopDetectionConfig { - let warningThreshold = asPositiveInt( + const warningThreshold = asPositiveInt( config?.warningThreshold, DEFAULT_LOOP_DETECTION_CONFIG.warningThreshold, ); diff --git a/src/agents/tool-search.ts b/src/agents/tool-search.ts index 34ec714e0c5..93d2536b709 100644 --- a/src/agents/tool-search.ts +++ b/src/agents/tool-search.ts @@ -1464,10 +1464,8 @@ function runCodeModeChild(params: { const stderr: string[] = []; let settled = false; let timedOut = false; - let timer: ReturnType | undefined; let exitRejectionTimer: ReturnType | undefined; const bridgeAbortController = new AbortController(); - let abortFromParent: () => void; const settle = (callback: () => void) => { if (settled) { return; @@ -1483,22 +1481,22 @@ function runCodeModeChild(params: { child.kill(); callback(); }; - abortFromParent = () => { + const abortFromParent: () => void = () => { bridgeAbortController.abort(params.signal?.reason); child.kill("SIGKILL"); settle(() => reject(new Error("tool_search_code aborted"))); }; - if (params.signal?.aborted) { - abortFromParent(); - return; - } - params.signal?.addEventListener("abort", abortFromParent, { once: true }); - timer = setTimeout(() => { + const timer: ReturnType | undefined = setTimeout(() => { timedOut = true; bridgeAbortController.abort(new Error("tool_search_code timed out")); child.kill("SIGKILL"); settle(() => reject(new Error("tool_search_code timed out"))); }, params.config.codeTimeoutMs); + params.signal?.addEventListener("abort", abortFromParent, { once: true }); + if (params.signal?.aborted) { + abortFromParent(); + return; + } child.stderr?.setEncoding("utf8"); child.stderr?.on("data", (chunk: string) => { diff --git a/src/agents/tools/common.ts b/src/agents/tools/common.ts index 97690210421..1d3c77bfeb5 100644 --- a/src/agents/tools/common.ts +++ b/src/agents/tools/common.ts @@ -444,7 +444,6 @@ export function scheduleToolProgress( return () => {}; } let cleared = false; - let timer: ReturnType; const clear = () => { if (cleared) { return; @@ -453,7 +452,7 @@ export function scheduleToolProgress( clearTimeout(timer); options.signal?.removeEventListener("abort", clear); }; - timer = setTimeout(() => { + const timer: ReturnType = setTimeout(() => { clear(); emitToolProgress(onUpdate, progress); }, delayMs); diff --git a/src/agents/tools/nodes-utils.ts b/src/agents/tools/nodes-utils.ts index 2a0a0032d12..cc54ff627f3 100644 --- a/src/agents/tools/nodes-utils.ts +++ b/src/agents/tools/nodes-utils.ts @@ -145,7 +145,7 @@ export function resolveNodeIdFromList( ): string { return resolveNodeIdFromNodeList(nodes, query, { allowDefault, - pickDefaultNode: pickDefaultNode, + pickDefaultNode, }); } @@ -165,6 +165,6 @@ export async function resolveNode( const nodes = await loadNodes(opts); return resolveNodeFromNodeList(nodes, query, { allowDefault, - pickDefaultNode: pickDefaultNode, + pickDefaultNode, }); } diff --git a/src/auto-reply/inbound-debounce.ts b/src/auto-reply/inbound-debounce.ts index ac17b2a50af..1fa8a52e64b 100644 --- a/src/auto-reply/inbound-debounce.ts +++ b/src/auto-reply/inbound-debounce.ts @@ -267,15 +267,13 @@ export function createInboundDebouncer(params: InboundDebounceCreateParams }); return; } - - let buffer!: DebounceBuffer; const reservedTask = enqueueReservedKeyTask(key, async () => { if (buffer.items.length === 0) { return; } await runFlush(buffer.items); }); - buffer = { + const buffer: DebounceBuffer = { items: [item], timeout: null, debounceMs, diff --git a/src/auto-reply/reply/agent-runner-execution.ts b/src/auto-reply/reply/agent-runner-execution.ts index 358d8ca1f38..360e3f03f30 100644 --- a/src/auto-reply/reply/agent-runner-execution.ts +++ b/src/auto-reply/reply/agent-runner-execution.ts @@ -1419,7 +1419,7 @@ export async function runAgentTurnWithFallback(params: { let autoCompactionCount = 0; // Track payloads sent directly (not via pipeline) during tool flush to avoid duplicates. const directlySentBlockKeys = new Set(); - let runnableRun = resolveRunAfterAutoFallbackPrimaryProbeRecheck({ + const runnableRun = resolveRunAfterAutoFallbackPrimaryProbeRecheck({ run: params.followupRun.run, entry: params.activeSessionStore?.[params.sessionKey ?? ""] ?? params.getActiveSessionEntry(), sessionKey: params.sessionKey, @@ -1428,7 +1428,7 @@ export async function runAgentTurnWithFallback(params: { params.followupRun.run = runnableRun; } const runtimeConfig = resolveQueuedReplyRuntimeConfig(runnableRun.config); - let effectiveRun = + const effectiveRun = runtimeConfig === runnableRun.config ? runnableRun : { diff --git a/src/auto-reply/reply/agent-runner.ts b/src/auto-reply/reply/agent-runner.ts index 43866984744..34956f2827b 100644 --- a/src/auto-reply/reply/agent-runner.ts +++ b/src/auto-reply/reply/agent-runner.ts @@ -1646,7 +1646,8 @@ export async function runReplyAgent(params: { fallbackAttempts, directlySentBlockKeys, } = runOutcome; - let { didLogHeartbeatStrip, autoCompactionCount } = runOutcome; + const { autoCompactionCount } = runOutcome; + let { didLogHeartbeatStrip } = runOutcome; if ( shouldInjectGroupIntro && diff --git a/src/auto-reply/reply/commands-diagnostics.ts b/src/auto-reply/reply/commands-diagnostics.ts index 09bb989f0fd..b21579c426b 100644 --- a/src/auto-reply/reply/commands-diagnostics.ts +++ b/src/auto-reply/reply/commands-diagnostics.ts @@ -55,7 +55,7 @@ type CodexDiagnosticsApprovalIntegration = { const defaultDiagnosticsCommandDeps: DiagnosticsCommandDeps = { createExecTool, resolvePrivateDiagnosticsTargets: resolvePrivateDiagnosticsTargetsForCommand, - deliverPrivateDiagnosticsReply: deliverPrivateDiagnosticsReply, + deliverPrivateDiagnosticsReply, }; export function createDiagnosticsCommandHandler( diff --git a/src/auto-reply/reply/commands-export-trajectory.ts b/src/auto-reply/reply/commands-export-trajectory.ts index 88da5231a99..2da58c3f623 100644 --- a/src/auto-reply/reply/commands-export-trajectory.ts +++ b/src/auto-reply/reply/commands-export-trajectory.ts @@ -54,7 +54,7 @@ type ExportTrajectoryCommandDeps = { const defaultExportTrajectoryCommandDeps: ExportTrajectoryCommandDeps = { createExecTool, resolvePrivateTrajectoryTargets: resolvePrivateTrajectoryTargetsForCommand, - deliverPrivateTrajectoryReply: deliverPrivateTrajectoryReply, + deliverPrivateTrajectoryReply, }; export async function buildExportTrajectoryCommandReply( diff --git a/src/auto-reply/reply/get-reply-run.ts b/src/auto-reply/reply/get-reply-run.ts index d553de248ee..5762fb526dd 100644 --- a/src/auto-reply/reply/get-reply-run.ts +++ b/src/auto-reply/reply/get-reply-run.ts @@ -480,15 +480,14 @@ export async function runPreparedReply( ctx, sessionKey, }); - let { - sessionEntry, - resolvedThinkLevel, + const { resolvedVerboseLevel, resolvedReasoningLevel, resolvedElevatedLevel, execOverrides, abortedLastRun, } = params; + let { sessionEntry, resolvedThinkLevel } = params; const isHeartbeat = opts?.isHeartbeat === true; const traceAttributes = { provider, @@ -745,7 +744,7 @@ export async function runPreparedReply( startupContextPrelude, softResetTail, isHeartbeat, - inboundEventKind: inboundEventKind, + inboundEventKind, sourceReplyDeliveryMode, }); const effectiveBaseBody = promptEnvelopeBase.effectiveBaseBody; @@ -819,7 +818,7 @@ export async function runPreparedReply( startupContextPrelude, softResetTail, isHeartbeat, - inboundEventKind: inboundEventKind, + inboundEventKind, sourceReplyDeliveryMode, threadContextNote, systemEventBlocks: drainedSystemEventBlocks, diff --git a/src/auto-reply/reply/get-reply.ts b/src/auto-reply/reply/get-reply.ts index 89adb25abfe..8032fa63ba2 100644 --- a/src/auto-reply/reply/get-reply.ts +++ b/src/auto-reply/reply/get-reply.ts @@ -474,7 +474,7 @@ export async function getReplyFromConfig( commandAuthorized, }), ); - let { + const { sessionCtx, sessionEntry, previousSessionEntry, @@ -484,7 +484,6 @@ export async function getReplyFromConfig( isNewSession, resetTriggered, systemSent, - abortedLastRun, storePath, sessionScope, groupResolution, @@ -492,6 +491,7 @@ export async function getReplyFromConfig( triggerBodyNormalized, bodyStripped, } = sessionState; + let { abortedLastRun } = sessionState; resolverTimingSessionKey = sessionKey ?? resolverTimingSessionKey; if (sessionEntry?.pendingFinalDelivery && sessionEntry.pendingFinalDeliveryText) { @@ -754,21 +754,16 @@ export async function getReplyFromConfig( logResolverTiming("completed", "directive_reply"); return directiveResult.reply; } - - let { + const { commandSource, command, allowTextCommands, skillCommands, - directives, - cleanedBody, elevatedEnabled, elevatedAllowed, elevatedFailures, defaultActivation, - resolvedThinkLevel, resolvedVerboseLevel, - resolvedReasoningLevel, resolvedElevatedLevel, execOverrides, blockStreamingEnabled, @@ -783,6 +778,8 @@ export async function getReplyFromConfig( perMessageQueueMode, perMessageQueueOptions, } = directiveResult.result; + let { directives, cleanedBody, resolvedThinkLevel, resolvedReasoningLevel } = + directiveResult.result; provider = resolvedProvider; model = resolvedModel; diff --git a/src/auto-reply/reply/route-reply.ts b/src/auto-reply/reply/route-reply.ts index 7345b6d5023..9a526ba8601 100644 --- a/src/auto-reply/reply/route-reply.ts +++ b/src/auto-reply/reply/route-reply.ts @@ -142,12 +142,12 @@ export async function routeReply(params: RouteReplyParams): Promise | undefined; let existingServiceCommand: GatewayServiceCommandConfig | null = null; try { loaded = await service.isLoaded({ env: process.env }); @@ -167,7 +166,8 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) { } } existingServiceCommand = await service.readCommand(process.env).catch(() => null); - existingServiceEnv = existingServiceCommand?.environment; + const existingServiceEnv: Record | undefined = + existingServiceCommand?.environment; const installEnv = mergeInstallInvocationEnv({ env: process.env, existingServiceEnv, diff --git a/src/cli/gateway-cli/qa-parent-watchdog.ts b/src/cli/gateway-cli/qa-parent-watchdog.ts index 24bc277a962..85e14dd8ae7 100644 --- a/src/cli/gateway-cli/qa-parent-watchdog.ts +++ b/src/cli/gateway-cli/qa-parent-watchdog.ts @@ -108,7 +108,6 @@ export function installQaParentWatchdog( ((callback: () => void, ms: number) => setInterval(callback, ms) as QaParentWatchdogTimer); let stopped = false; let exiting = false; - let timer: QaParentWatchdogTimer; const stop = () => { if (stopped) { @@ -118,7 +117,7 @@ export function installQaParentWatchdog( clearIntervalFn(timer); }; - timer = setIntervalFn(() => { + const timer: QaParentWatchdogTimer = setIntervalFn(() => { if (stopped || exiting) { return; } diff --git a/src/cli/gateway-cli/register.option-collisions.test.ts b/src/cli/gateway-cli/register.option-collisions.test.ts index 372479dfc3e..a9cf90c25a9 100644 --- a/src/cli/gateway-cli/register.option-collisions.test.ts +++ b/src/cli/gateway-cli/register.option-collisions.test.ts @@ -131,7 +131,7 @@ function firstGatewayStatusCall() { } describe("gateway register option collisions", () => { - let sharedProgram: Command = new Command(); + const sharedProgram: Command = new Command(); if (sharedProgram.commands.length === 0) { sharedProgram.exitOverride(); diff --git a/src/cli/nodes-cli.coverage.test.ts b/src/cli/nodes-cli.coverage.test.ts index 6f16ac3a4b6..cbdf1911409 100644 --- a/src/cli/nodes-cli.coverage.test.ts +++ b/src/cli/nodes-cli.coverage.test.ts @@ -64,7 +64,7 @@ vi.mock("../runtime.js", async () => ({ })); describe("nodes-cli coverage", () => { - let sharedProgram: Command = new Command(); + const sharedProgram: Command = new Command(); const withSuppressedStderr = async (run: () => Promise) => { const stderrSpy = vi diff --git a/src/cli/plugins-cli.runtime.ts b/src/cli/plugins-cli.runtime.ts index e00a9557814..cc74103d04a 100644 --- a/src/cli/plugins-cli.runtime.ts +++ b/src/cli/plugins-cli.runtime.ts @@ -176,7 +176,8 @@ function collectConfiguredRuntimePluginWarnings(params: { }); } -export async function runPluginsEnableCommand(id: string): Promise { +export async function runPluginsEnableCommand(idInput: string): Promise { + let id = idInput; assertConfigWriteAllowedInCurrentMode(); const { enablePluginInConfig } = await import("../plugins/enable.js"); @@ -219,7 +220,8 @@ export async function runPluginsEnableCommand(id: string): Promise { ); } -export async function runPluginsDisableCommand(id: string): Promise { +export async function runPluginsDisableCommand(idInput: string): Promise { + let id = idInput; assertConfigWriteAllowedInCurrentMode(); const { normalizePluginId } = await loadPluginsConfigState(); diff --git a/src/cli/run-main.ts b/src/cli/run-main.ts index 247a557d32e..5aeb2a2d948 100644 --- a/src/cli/run-main.ts +++ b/src/cli/run-main.ts @@ -493,7 +493,7 @@ export async function runCli(argv: string[] = process.argv) { } return; } - let normalizedArgv = normalizeRootHelpTargetArgv(parsedProfile.argv); + const normalizedArgv = normalizeRootHelpTargetArgv(parsedProfile.argv); const normalizedInvocation = resolveCliArgvInvocation(normalizedArgv); const isHelpOrVersionInvocation = normalizedInvocation.hasHelpOrVersion; startupTrace.mark("argv"); diff --git a/src/cli/windows-argv.ts b/src/cli/windows-argv.ts index 5f11c9e54c1..30f0b4abac9 100644 --- a/src/cli/windows-argv.ts +++ b/src/cli/windows-argv.ts @@ -59,7 +59,7 @@ export function normalizeWindowsArgv( const argv0IsExecPath = isExecPath(argv[0]); const next = [...argv]; let removedLauncherPrefix = false; - for (let i = 1; i < next.length; ) { + for (const i = 1; i < next.length; ) { if (isExecPath(next[i])) { next.splice(i, 1); removedLauncherPrefix = true; @@ -71,7 +71,7 @@ export function normalizeWindowsArgv( return next; } const cleaned = [...next]; - for (let i = 2; i < cleaned.length; ) { + for (const i = 2; i < cleaned.length; ) { const arg = cleaned[i]; if (!arg || arg.startsWith("-")) { break; diff --git a/src/commands/channels/remove.ts b/src/commands/channels/remove.ts index 244a43c87a7..75c87c90e7a 100644 --- a/src/commands/channels/remove.ts +++ b/src/commands/channels/remove.ts @@ -29,8 +29,9 @@ export type ChannelsRemoveOptions = { function listAccountIds( cfg: OpenClawConfig, channel: ChatChannel, - plugin?: ChannelPlugin, + pluginInput?: ChannelPlugin, ): string[] { + let plugin = pluginInput; plugin ??= getChannelPlugin(channel); if (!plugin) { return []; diff --git a/src/commands/configure.channels.ts b/src/commands/configure.channels.ts index 4001c38f673..9ba4eb0bca0 100644 --- a/src/commands/configure.channels.ts +++ b/src/commands/configure.channels.ts @@ -70,7 +70,7 @@ export async function removeChannelConfigWizard( cfg: OpenClawConfig, runtime: RuntimeEnv, ): Promise { - let next = { ...cfg }; + const next = { ...cfg }; while (true) { const configured = listConfiguredChannelRemovalChoices(next); diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts index fca20b5be28..4f9f981d2ed 100644 --- a/src/commands/doctor-config-flow.ts +++ b/src/commands/doctor-config-flow.ts @@ -88,7 +88,7 @@ export async function loadAndMaybeMigrateDoctorConfig(params: { }) { const shouldRepair = params.options.repair === true || params.options.yes === true; const preflight = await runDoctorConfigPreflight({ repairPrefixedConfig: shouldRepair }); - let snapshot = preflight.snapshot; + const snapshot = preflight.snapshot; const baseCfg = preflight.baseConfig; let cfg: OpenClawConfig = baseCfg; let candidate = structuredClone(baseCfg); diff --git a/src/commands/migrate.test.ts b/src/commands/migrate.test.ts index ec3839b8980..480d3957d39 100644 --- a/src/commands/migrate.test.ts +++ b/src/commands/migrate.test.ts @@ -1055,7 +1055,7 @@ describe("migrateApplyCommand", () => { await migrateDefaultCommand(runtime, { provider: "codex" }); - let appliedPlan = firstAppliedPlan(); + const appliedPlan = firstAppliedPlan(); expect(appliedPlan.summary.planned).toBe(3); expect(appliedPlan.summary.skipped).toBe(0); expect(appliedPlan.summary.conflicts).toBe(0); diff --git a/src/commands/models/auth.test.ts b/src/commands/models/auth.test.ts index 884a4309860..d74eb6ac927 100644 --- a/src/commands/models/auth.test.ts +++ b/src/commands/models/auth.test.ts @@ -304,7 +304,7 @@ function withPipedStdin(input: string) { }); Object.defineProperty(stdin, Symbol.asyncIterator, { configurable: true, - value: async function* () { + async *value() { yield input; }, }); diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 7201475b6ac..2009972bdb4 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -41,7 +41,7 @@ export async function applyNonInteractiveAuthChoice(params: { config: params.nextConfig, env: process.env, }); - let nextConfig = params.nextConfig; + const nextConfig = params.nextConfig; const requestedSecretInputMode = normalizeSecretInputModeInput(opts.secretInputMode); if (opts.secretInputMode && !requestedSecretInputMode) { runtime.error( diff --git a/src/config/channel-compat-normalization.ts b/src/config/channel-compat-normalization.ts index 69068cc1e55..876113af281 100644 --- a/src/config/channel-compat-normalization.ts +++ b/src/config/channel-compat-normalization.ts @@ -69,7 +69,7 @@ export function normalizeLegacyStreamingAliases( return { entry: params.entry, changed: false }; } - let updated = { ...params.entry }; + const updated = { ...params.entry }; let changed = false; const streaming = ensureNestedRecord(updated, "streaming"); const block = ensureNestedRecord(streaming, "block"); diff --git a/src/config/defaults.ts b/src/config/defaults.ts index b84605c00b8..c3d4eeb2991 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -27,7 +27,7 @@ type ProviderPolicyDefaultsOptions = { loadManifestRegistry?: () => Pick | undefined; }; -let defaultWarnState: WarnState = { warned: false }; +const defaultWarnState: WarnState = { warned: false }; const DEFAULT_MODEL_ALIASES: Readonly> = { // Anthropic (shared model runtime catalog uses "latest" ids without date suffix) @@ -179,7 +179,7 @@ export function applyModelDefaults( continue; } const providerApi = normalizedProvider.api; - let nextProvider = normalizedProvider; + const nextProvider = normalizedProvider; if (nextProvider !== provider) { mutated = true; } diff --git a/src/config/redact-snapshot.ts b/src/config/redact-snapshot.ts index 498a23479fc..cdeed112735 100644 --- a/src/config/redact-snapshot.ts +++ b/src/config/redact-snapshot.ts @@ -103,7 +103,7 @@ function isSecretRefWithProvider( // the Set, as their first lookup is done before the code knows it's // an array. function buildRedactionLookup(hints: ConfigUiHints): Set { - let result = new Set(); + const result = new Set(); for (const [path, hint] of Object.entries(hints)) { if (!hint.sensitive) { diff --git a/src/config/sessions/store-load.ts b/src/config/sessions/store-load.ts index c9ed4a031b0..02cabcbaf90 100644 --- a/src/config/sessions/store-load.ts +++ b/src/config/sessions/store-load.ts @@ -392,8 +392,8 @@ export function loadSessionStore( // Retry a few times on Windows because readers can briefly observe empty or // transiently invalid content while another process is swapping the file. let store: Record = {}; - let fileStat = getFileStatSnapshot(storePath); - let mtimeMs = fileStat?.mtimeMs; + const fileStat = getFileStatSnapshot(storePath); + const mtimeMs = fileStat?.mtimeMs; let serializedFromDisk: string | undefined; const maxReadAttempts = process.platform === "win32" ? 3 : 1; const retryBuf = maxReadAttempts > 1 ? new Int32Array(new SharedArrayBuffer(4)) : undefined; diff --git a/src/cron/isolated-agent/delivery-target.ts b/src/cron/isolated-agent/delivery-target.ts index f1a9ce6903c..68e389feb0c 100644 --- a/src/cron/isolated-agent/delivery-target.ts +++ b/src/cron/isolated-agent/delivery-target.ts @@ -310,8 +310,6 @@ export async function resolveDeliveryTarget( }; } toCandidate = docked.to; - - let resolvedTarget: ResolvedMessagingTarget | undefined; const targetResolution = await deliveryTargetRuntime.resolveChannelTargetForDelivery({ cfg, channel, @@ -329,7 +327,7 @@ export async function resolveDeliveryTarget( error: targetResolution.error, }; } - resolvedTarget = targetResolution.target; + const resolvedTarget: ResolvedMessagingTarget | undefined = targetResolution.target; const routeTargetCandidate = resolvedTarget.source === "directory" ? resolvedTarget.to diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index 1d4eff3ae7d..70cbdc79082 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -1014,17 +1014,7 @@ async function finalizeCronRun(params: { ...telemetry, }); } - let { - summary, - outputText, - synthesizedText, - deliveryPayloads, - deliveryPayloadHasStructuredContent, - hasFatalErrorPayload, - hasFatalStructuredErrorPayload, - embeddedRunError, - pendingPresentationWarningError, - } = resolveCronPayloadOutcome({ + const cronPayloadOutcome = resolveCronPayloadOutcome({ payloads, runLevelError: finalRunResult.meta?.error, failureSignal: finalRunResult.meta?.failureSignal, @@ -1033,6 +1023,14 @@ async function finalizeCronRun(params: { await resolveCronChannelOutputPolicy(prepared.resolvedDelivery.channel) ).preferFinalAssistantVisibleText, }); + const { + synthesizedText, + deliveryPayloads, + deliveryPayloadHasStructuredContent, + hasFatalStructuredErrorPayload, + pendingPresentationWarningError, + } = cronPayloadOutcome; + let { summary, outputText, hasFatalErrorPayload, embeddedRunError } = cronPayloadOutcome; const agentDiagnostics = createCronRunDiagnosticsFromAgentResult(finalRunResult, { finalStatus: hasFatalErrorPayload ? "error" : "ok", }); diff --git a/src/cron/schedule.ts b/src/cron/schedule.ts index 303b0307365..b6811e30f42 100644 --- a/src/cron/schedule.ts +++ b/src/cron/schedule.ts @@ -93,11 +93,11 @@ export function computeNextRunAtMs(schedule: CronSchedule, nowMs: number): numbe if (!cron) { return undefined; } - let next = cron.nextRun(new Date(nowMs)); + const next = cron.nextRun(new Date(nowMs)); if (!next) { return undefined; } - let nextMs = next.getTime(); + const nextMs = next.getTime(); if (!Number.isFinite(nextMs)) { return undefined; } diff --git a/src/cron/service.issue-regressions.test.ts b/src/cron/service.issue-regressions.test.ts index fcd5f2fc2b0..3fe0b868512 100644 --- a/src/cron/service.issue-regressions.test.ts +++ b/src/cron/service.issue-regressions.test.ts @@ -171,8 +171,8 @@ describe("Cron issue regressions", () => { }), ).rejects.toThrow("CronPattern"); - let persisted = await loadCronStore(store.storePath); - let storedJob = persisted.jobs.find((job) => job.id === disabledJob.id); + const persisted = await loadCronStore(store.storePath); + const storedJob = persisted.jobs.find((job) => job.id === disabledJob.id); expect(storedJob?.enabled).toBe(false); expect(storedJob?.schedule.kind).toBe("cron"); if (storedJob?.schedule.kind !== "cron") { diff --git a/src/cron/service/timer.regression.test.ts b/src/cron/service/timer.regression.test.ts index a74d4b671fd..05ff04b8031 100644 --- a/src/cron/service/timer.regression.test.ts +++ b/src/cron/service/timer.regression.test.ts @@ -452,7 +452,7 @@ describe("cron service timer regressions", () => { }); await saveCronStore(store.storePath, { version: 1, jobs: [cronJob] }); - let now = scheduledAt; + const now = scheduledAt; const state = createCronServiceState({ cronEnabled: true, storePath: store.storePath, diff --git a/src/daemon/systemd.ts b/src/daemon/systemd.ts index d72f55f6ee8..2a7bef8cbfa 100644 --- a/src/daemon/systemd.ts +++ b/src/daemon/systemd.ts @@ -831,7 +831,7 @@ async function writeSystemdGatewayEnvironmentFile(params: { // OpenClaw-managed keys (identified by inlineManagedKeys) are excluded: a stale // file copy would override the fresh inline Environment= value because systemd's // EnvironmentFile takes precedence over inline Environment= directives. - let existing: Record = {}; + const existing: Record = {}; const legacyNodeEnvFilePath = resolveLegacyNodeSystemdEnvironmentFilePath({ stateDir: params.stateDir, environment: params.environment, diff --git a/src/gateway/call.ts b/src/gateway/call.ts index 756e18419bc..b7705728f78 100644 --- a/src/gateway/call.ts +++ b/src/gateway/call.ts @@ -789,9 +789,6 @@ async function executeGatewayRequestWithScopes(params: { let settled = false; let ignoreClose = false; const startAbort = new AbortController(); - let abortHandler: (() => void) | undefined; - let client: GatewayClient | undefined; - let timer: NodeJS.Timeout | undefined; let primaryRequestStarted = false; const cleanup = () => { startAbort.abort(); @@ -828,7 +825,7 @@ async function executeGatewayRequestWithScopes(params: { cleanup(); stopClientThenSettle(client, err, value); }; - abortHandler = () => { + const abortHandler: (() => void) | undefined = () => { if (settled) { return; } @@ -850,7 +847,7 @@ async function executeGatewayRequestWithScopes(params: { }; opts.signal?.addEventListener("abort", abortHandler, { once: true }); - client = gatewayCallDeps.createGatewayClient({ + const client: GatewayClient | undefined = gatewayCallDeps.createGatewayClient({ url, token, password, @@ -915,7 +912,7 @@ async function executeGatewayRequestWithScopes(params: { }, }); - timer = setTimeout(() => { + const timer: NodeJS.Timeout | undefined = setTimeout(() => { ignoreClose = true; stop( createGatewayTimeoutTransportError({ diff --git a/src/gateway/config-reload.ts b/src/gateway/config-reload.ts index a4aa8c8b301..9da71bc72eb 100644 --- a/src/gateway/config-reload.ts +++ b/src/gateway/config-reload.ts @@ -340,7 +340,7 @@ export function startGatewayConfigReloader(opts: { await promoteAcceptedInProcessWrite(pendingWrite.persistedHash); return; } - let snapshot = await opts.readSnapshot(); + const snapshot = await opts.readSnapshot(); if (lastAppliedWriteHash && typeof snapshot.hash === "string") { if (snapshot.hash === lastAppliedWriteHash) { return; diff --git a/src/gateway/gateway-cli-backend.live-helpers.ts b/src/gateway/gateway-cli-backend.live-helpers.ts index bf5135c8e25..ee2f2fc821c 100644 --- a/src/gateway/gateway-cli-backend.live-helpers.ts +++ b/src/gateway/gateway-cli-backend.live-helpers.ts @@ -360,7 +360,6 @@ async function connectClientOnce(params: { }): Promise { return await new Promise((resolve, reject) => { let done = false; - let client: GatewayClient | undefined; const abortStart = new AbortController(); const finish = (result: { client?: GatewayClient; error?: Error }) => { if (done) { @@ -405,7 +404,7 @@ async function connectClientOnce(params: { clientOptions.tickWatchTimeoutMs = params.tickWatchTimeoutMs; } - client = new GatewayClient(clientOptions); + const client: GatewayClient | undefined = new GatewayClient(clientOptions); const connectTimeout = setTimeout( () => finish({ error: new Error("gateway connect timeout") }), diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index d14feea6b11..0b0751b9d11 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -1722,7 +1722,6 @@ async function connectClientOnce(params: { url: string; token: string; timeoutMs const timeoutMs = params.timeoutMs ?? 10_000; return await new Promise((resolve, reject) => { let settled = false; - let client: GatewayClient | undefined; const stop = (err?: Error, nextClient?: GatewayClient) => { if (settled) { return; @@ -1738,7 +1737,7 @@ async function connectClientOnce(params: { url: string; token: string; timeoutMs resolve(nextClient as GatewayClient); } }; - client = new GatewayClient({ + const client: GatewayClient | undefined = new GatewayClient({ url: params.url, token: params.token, requestTimeoutMs: Math.max(timeoutMs, GATEWAY_LIVE_MODEL_TIMEOUT_MS), @@ -2542,8 +2541,6 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { agentDir: process.env.OPENCLAW_AGENT_DIR, stateDir: process.env.OPENCLAW_STATE_DIR, }; - let tempAgentDir: string | undefined; - let tempStateDir: string | undefined; process.env.OPENCLAW_SKIP_CHANNELS = "1"; process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; @@ -2571,9 +2568,16 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { lastGood: hostStore.lastGood ? { ...hostStore.lastGood } : undefined, usageStats: hostStore.usageStats ? { ...hostStore.usageStats } : undefined, }); - tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-state-")); + const tempStateDir: string | undefined = await fs.mkdtemp( + path.join(os.tmpdir(), "openclaw-live-state-"), + ); process.env.OPENCLAW_STATE_DIR = tempStateDir; - tempAgentDir = path.join(tempStateDir, "agents", DEFAULT_AGENT_ID, "agent"); + const tempAgentDir: string | undefined = path.join( + tempStateDir, + "agents", + DEFAULT_AGENT_ID, + "agent", + ); saveAuthProfileStore(sanitizedStore, tempAgentDir); const tempSessionAgentDir = path.join(tempStateDir, "agents", agentId, "agent"); if (tempSessionAgentDir !== tempAgentDir) { diff --git a/src/gateway/gateway-trajectory-export.live.test.ts b/src/gateway/gateway-trajectory-export.live.test.ts index 68d13a33f2f..f96b04003a2 100644 --- a/src/gateway/gateway-trajectory-export.live.test.ts +++ b/src/gateway/gateway-trajectory-export.live.test.ts @@ -165,7 +165,7 @@ async function approveTrajectoryExport(client: GatewayClient): Promise { } describeLive("gateway live trajectory export", () => { - let cleanup: Array<() => Promise> = []; + const cleanup: Array<() => Promise> = []; afterEach(async () => { for (const step of cleanup.splice(0).toReversed()) { diff --git a/src/gateway/openresponses-http.ts b/src/gateway/openresponses-http.ts index 7f08fd38c77..c7b3565e6b7 100644 --- a/src/gateway/openresponses-http.ts +++ b/src/gateway/openresponses-http.ts @@ -482,7 +482,7 @@ export async function handleOpenResponsesHttpRequest( // Extract images + files from input (Phase 2) let images: ImageContent[] = []; - let fileContexts: string[] = []; + const fileContexts: string[] = []; let urlParts = 0; const markUrlPart = () => { urlParts += 1; diff --git a/src/gateway/server-control-ui-root.ts b/src/gateway/server-control-ui-root.ts index ddd00b17272..ff7760adfdc 100644 --- a/src/gateway/server-control-ui-root.ts +++ b/src/gateway/server-control-ui-root.ts @@ -53,7 +53,7 @@ export async function resolveGatewayControlUiRootState(params: { cwd: process.cwd(), }); - let resolvedRoot = resolveRoot(); + const resolvedRoot = resolveRoot(); if (!resolvedRoot) { startControlUiAssetsBuild({ gatewayRuntime: params.gatewayRuntime, diff --git a/src/gateway/server-methods/agent-job.ts b/src/gateway/server-methods/agent-job.ts index 70177440b04..173e415bcb7 100644 --- a/src/gateway/server-methods/agent-job.ts +++ b/src/gateway/server-methods/agent-job.ts @@ -332,7 +332,6 @@ export async function waitForAgentJob(params: { let pendingErrorTimer: NodeJS.Timeout | undefined; let pendingTimeoutTimer: NodeJS.Timeout | undefined; let pendingTimeoutSnapshot: AgentRunSnapshot | undefined; - let onAbort: (() => void) | undefined; let removeWaiter = () => {}; const clearPendingErrorTimer = () => { @@ -481,7 +480,7 @@ export async function waitForAgentJob(params: { const pendingError = getPendingAgentRunError(runId); finish(pendingError ? createPendingErrorTimeoutSnapshot(pendingError.snapshot) : null); }, timeoutMs); - onAbort = () => finish(null); + const onAbort: (() => void) | undefined = () => finish(null); signal?.addEventListener("abort", onAbort, { once: true }); }); } diff --git a/src/gateway/server-methods/agent-wait-dedupe.ts b/src/gateway/server-methods/agent-wait-dedupe.ts index e9f5c4c76d6..44316b8e3fe 100644 --- a/src/gateway/server-methods/agent-wait-dedupe.ts +++ b/src/gateway/server-methods/agent-wait-dedupe.ts @@ -254,9 +254,6 @@ export async function waitForTerminalGatewayDedupe(params: { return await new Promise((resolve) => { let settled = false; - let timeoutHandle: NodeJS.Timeout | undefined; - let onAbort: (() => void) | undefined; - let removeWaiter: (() => void) | undefined; const finish = (snapshot: AgentWaitTerminalSnapshot | null) => { if (settled) { @@ -280,16 +277,19 @@ export async function waitForTerminalGatewayDedupe(params: { } }; - removeWaiter = addWaiter(params.runId, onWake); + const removeWaiter: (() => void) | undefined = addWaiter(params.runId, onWake); onWake(); if (settled) { return; } - timeoutHandle = setSafeTimeout(() => finish(null), params.timeoutMs); + const timeoutHandle: NodeJS.Timeout | undefined = setSafeTimeout( + () => finish(null), + params.timeoutMs, + ); timeoutHandle.unref?.(); - onAbort = () => finish(null); + const onAbort: (() => void) | undefined = () => finish(null); params.signal?.addEventListener("abort", onAbort, { once: true }); }); } diff --git a/src/gateway/server-methods/agent.ts b/src/gateway/server-methods/agent.ts index 22de86fa5a1..85d9e4c7e86 100644 --- a/src/gateway/server-methods/agent.ts +++ b/src/gateway/server-methods/agent.ts @@ -1877,7 +1877,7 @@ export const agentHandlers: GatewayRequestHandlers = { let resolvedChannel = deliveryPlan.resolvedChannel; let deliveryTargetMode = deliveryPlan.deliveryTargetMode; - let resolvedAccountId = deliveryPlan.resolvedAccountId; + const resolvedAccountId = deliveryPlan.resolvedAccountId; let resolvedTo = deliveryPlan.resolvedTo; let effectivePlan = deliveryPlan; let deliveryDowngradeReason: string | null = null; diff --git a/src/gateway/server-methods/channels.ts b/src/gateway/server-methods/channels.ts index 646db75f86f..f0b9fdccdfb 100644 --- a/src/gateway/server-methods/channels.ts +++ b/src/gateway/server-methods/channels.ts @@ -436,7 +436,7 @@ export const channelsHandlers: GatewayRequestHandlers = { if (!health.healthy) { snapshot.healthState = health.reason; } - return { accountId: accountId, account, snapshot }; + return { accountId, account, snapshot }; }; const buildChannelAccounts = async (channelId: ChannelId) => { diff --git a/src/gateway/server-methods/chat-reply-media.ts b/src/gateway/server-methods/chat-reply-media.ts index f1de87b82c2..86b3d1b578c 100644 --- a/src/gateway/server-methods/chat-reply-media.ts +++ b/src/gateway/server-methods/chat-reply-media.ts @@ -61,7 +61,7 @@ export async function normalizeWebchatReplyMediaPathsForDisplay(params: { continue; } const mergedMediaUrls: string[] = []; - let text = payload.text; + const text = payload.text; for (const mediaUrl of mediaUrls) { if (shouldPreserveDisplayMediaUrl(payload, mediaUrl)) { mergedMediaUrls.push(mediaUrl); diff --git a/src/gateway/server-methods/send.ts b/src/gateway/server-methods/send.ts index aa1d2a6243a..ce9523bb820 100644 --- a/src/gateway/server-methods/send.ts +++ b/src/gateway/server-methods/send.ts @@ -800,7 +800,7 @@ export const sendHandlers: GatewayRequestHandlers = { return { ok: false, error }; } const resolvedTarget = resolveGatewayOutboundTarget({ - channel: channel, + channel, to: request.to.trim(), cfg, accountId, diff --git a/src/gateway/server-methods/usage.ts b/src/gateway/server-methods/usage.ts index bed1d7a7357..2b6071b5bac 100644 --- a/src/gateway/server-methods/usage.ts +++ b/src/gateway/server-methods/usage.ts @@ -1458,7 +1458,7 @@ export const usageHandlers: GatewayRequestHandlers = { }; const tail = buildUsageAggregateTail({ - byChannelMap: byChannelMap, + byChannelMap, latencyTotals, dailyLatencyMap, modelDailyMap, diff --git a/src/gateway/server.cron.test.ts b/src/gateway/server.cron.test.ts index 2372ee7d163..119ae6b9c3d 100644 --- a/src/gateway/server.cron.test.ts +++ b/src/gateway/server.cron.test.ts @@ -181,7 +181,7 @@ async function createDirectCronState(params?: { deps: {} as never, broadcast: params?.broadcast ?? vi.fn(), }), - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, }; } diff --git a/src/gateway/server.preauth-hardening.test.ts b/src/gateway/server.preauth-hardening.test.ts index 4fd5dc7b5ed..c86958e438c 100644 --- a/src/gateway/server.preauth-hardening.test.ts +++ b/src/gateway/server.preauth-hardening.test.ts @@ -26,7 +26,7 @@ await import("./server.js"); const PREAUTH_HANDSHAKE_TEST_CLOSE_LIMIT_MS = 5_000; -let cleanupEnv: Array<() => void> = []; +const cleanupEnv: Array<() => void> = []; afterEach(async () => { while (cleanupEnv.length > 0) { diff --git a/src/gateway/server.sessions.list-changed.test.ts b/src/gateway/server.sessions.list-changed.test.ts index 92cbd1ddb6f..15a2b6daa18 100644 --- a/src/gateway/server.sessions.list-changed.test.ts +++ b/src/gateway/server.sessions.list-changed.test.ts @@ -449,7 +449,7 @@ test("sessions.changed mutation events include live usage metadata", async () => broadcastToConnIds, getSessionEventSubscriberConnIds: () => new Set(["conn-1"]), loadGatewayModelCatalog: async () => ({ providers: [] }), - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, } as never, client: null, isWebchatConnect: () => false, @@ -500,7 +500,7 @@ test("sessions.changed mutation events include live session setting metadata", a broadcastToConnIds, getSessionEventSubscriberConnIds: () => new Set(["conn-1"]), loadGatewayModelCatalog: async () => ({ providers: [] }), - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, } as never, client: null, isWebchatConnect: () => false, @@ -546,7 +546,7 @@ test("sessions.changed mutation events include sendPolicy metadata", async () => broadcastToConnIds, getSessionEventSubscriberConnIds: () => new Set(["conn-1"]), loadGatewayModelCatalog: async () => ({ providers: [] }), - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, } as never, client: null, isWebchatConnect: () => false, @@ -854,7 +854,7 @@ test("sessions.changed mutation events include subagent ownership metadata", asy broadcastToConnIds, getSessionEventSubscriberConnIds: () => new Set(["conn-1"]), loadGatewayModelCatalog: async () => ({ providers: [] }), - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, } as never, client: null, isWebchatConnect: () => false, diff --git a/src/gateway/server.sessions.store-rpc.test.ts b/src/gateway/server.sessions.store-rpc.test.ts index 7d7e3a5a915..f70a972133d 100644 --- a/src/gateway/server.sessions.store-rpc.test.ts +++ b/src/gateway/server.sessions.store-rpc.test.ts @@ -100,7 +100,7 @@ test("lists and patches session store via sessions.* RPC", async () => { getSessionEventSubscriberConnIds: () => new Set(), logGateway: { debug: vi.fn() }, loadGatewayModelCatalog: async () => agentDiscoveryMock.models, - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, } as never; async function directSessionReq( method: keyof typeof sessionsHandlers, diff --git a/src/gateway/server/ws-connection/auth-context.ts b/src/gateway/server/ws-connection/auth-context.ts index f48c7a4a3e1..ee025211991 100644 --- a/src/gateway/server/ws-connection/auth-context.ts +++ b/src/gateway/server/ws-connection/auth-context.ts @@ -113,7 +113,7 @@ export async function resolveConnectAuthState(params: { const { token: deviceTokenCandidate, source: deviceTokenCandidateSource } = params.hasDeviceIdentity ? resolveDeviceTokenCandidate(params.connectAuth) : {}; - let authResult: GatewayAuthResult = await authorizeWsControlUiGatewayConnect({ + const authResult: GatewayAuthResult = await authorizeWsControlUiGatewayConnect({ auth: params.resolvedAuth, connectAuth: sharedConnectAuth, req: params.req, diff --git a/src/gateway/server/ws-connection/message-handler.ts b/src/gateway/server/ws-connection/message-handler.ts index d479638d956..fbab58d9c82 100644 --- a/src/gateway/server/ws-connection/message-handler.ts +++ b/src/gateway/server/ws-connection/message-handler.ts @@ -728,16 +728,7 @@ export function attachGatewayWsMessageHandler(params: GatewayWsMessageHandlerPar deviceRaw, }); const device = controlUiAuthPolicy.device; - - let { - authResult, - authOk, - authMethod, - sharedAuthOk, - bootstrapTokenCandidate, - deviceTokenCandidate, - deviceTokenCandidateSource, - } = await resolveConnectAuthState({ + const connectAuthState = await resolveConnectAuthState({ resolvedAuth, connectAuth: connectParams.auth, hasDeviceIdentity: Boolean(device), @@ -747,6 +738,13 @@ export function attachGatewayWsMessageHandler(params: GatewayWsMessageHandlerPar rateLimiter: authRateLimiter, clientIp: browserRateLimitClientIp, }); + const { + sharedAuthOk, + bootstrapTokenCandidate, + deviceTokenCandidate, + deviceTokenCandidateSource, + } = connectAuthState; + let { authResult, authOk, authMethod } = connectAuthState; const rejectUnauthorized = (failedAuth: GatewayAuthResult) => { const { authProvided, canRetryWithDeviceToken, recommendedNextStep } = resolveUnauthorizedHandshakeContext({ diff --git a/src/gateway/sessions-history-http.ts b/src/gateway/sessions-history-http.ts index faf07147603..36a57225d81 100644 --- a/src/gateway/sessions-history-http.ts +++ b/src/gateway/sessions-history-http.ts @@ -230,12 +230,6 @@ export async function handleSessionHistoryHttpRequest( let cleanedUp = false; let streamQueue = Promise.resolve(); - // Forward-declared so `cleanup` can reference them without relying on - // Temporal-Dead-Zone leniency. A future refactor that wires the close event - // listeners before the `setInterval` / `onSessionTranscriptUpdate` calls - // would otherwise hit a `ReferenceError` on the first cleanup invocation. - let heartbeat: ReturnType | undefined; - let unsubscribe: (() => void) | undefined; const cleanup = () => { if (cleanedUp) { @@ -294,7 +288,7 @@ export async function handleSessionHistoryHttpRequest( return authorizeOperatorScopesForMethod("chat.history", requestedScopes).allowed; }; - heartbeat = setInterval(() => { + const heartbeat: ReturnType | undefined = setInterval(() => { queueStreamWork(async () => { if (!(await isStreamStillAuthorized())) { closeStream(); @@ -306,7 +300,7 @@ export async function handleSessionHistoryHttpRequest( }); }, 15_000); - unsubscribe = onSessionTranscriptUpdate((update) => { + const unsubscribe: (() => void) | undefined = onSessionTranscriptUpdate((update) => { // Filter to candidate sessions synchronously before enqueueing any async // work. `onSessionTranscriptUpdate` is a global fan-out listener, so every // transcript write in the gateway would otherwise append a Promise-chain diff --git a/src/gateway/talk-realtime-relay.ts b/src/gateway/talk-realtime-relay.ts index c2a4c1a9868..38b222b947e 100644 --- a/src/gateway/talk-realtime-relay.ts +++ b/src/gateway/talk-realtime-relay.ts @@ -331,7 +331,6 @@ export function createTalkRealtimeRelaySession( }, { onEvent: recordTalkObservabilityEvent }, ); - let relay: RelaySession | undefined; const emit = (event: TalkRealtimeRelayEventPayload, talkEvent?: TalkEventInput) => broadcastToOwner(params.context, params.connId, { ...event, @@ -339,6 +338,7 @@ export function createTalkRealtimeRelaySession( }); let currentOutputItemId: string | undefined; let currentOutputResponseId: string | undefined; + const relayRef: { current?: RelaySession } = {}; const bridge = createRealtimeVoiceBridgeSession({ provider: params.provider, cfg: params.cfg, @@ -350,9 +350,9 @@ export function createTalkRealtimeRelaySession( tools: params.tools, markStrategy: "ack-immediately", audioSink: { - isOpen: () => Boolean(relay && relaySessions.has(relay.id)), + isOpen: () => Boolean(relayRef.current && relaySessions.has(relayRef.current.id)), sendAudio: (audio) => { - const turnId = relay ? ensureRelayTurn(relay) : undefined; + const turnId = relayRef.current ? ensureRelayTurn(relayRef.current) : undefined; emit( { relaySessionId, @@ -369,7 +369,7 @@ export function createTalkRealtimeRelaySession( ); }, clearAudio: () => { - const turnId = relay ? ensureRelayTurn(relay) : undefined; + const turnId = relayRef.current ? ensureRelayTurn(relayRef.current) : undefined; emit( { relaySessionId, type: "clear" }, { @@ -381,7 +381,7 @@ export function createTalkRealtimeRelaySession( ); }, sendMark: (markName) => { - const turnId = relay ? ensureRelayTurn(relay) : undefined; + const turnId = relayRef.current ? ensureRelayTurn(relayRef.current) : undefined; emit( { relaySessionId, type: "mark", markName }, { @@ -428,6 +428,7 @@ export function createTalkRealtimeRelaySession( } }, onTranscript: (role, text, final) => { + const relay = relayRef.current; const turnId = relay ? ensureRelayTurn(relay) : undefined; if (final && relay) { recordRealtimeVoiceTranscript(relay.transcript, role, text); @@ -488,6 +489,7 @@ export function createTalkRealtimeRelaySession( } }, onToolCall: (toolCall) => { + const relay = relayRef.current; const turnId = relay ? ensureRelayTurn(relay) : undefined; if (relay && toolCall.name === REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME) { const forcedConsult = relay.forcedConsults.recordNativeConsult( @@ -545,7 +547,7 @@ export function createTalkRealtimeRelaySession( ); }, }); - relay = { + const relay: RelaySession = { id: relaySessionId, connId: params.connId, context: params.context, @@ -565,6 +567,7 @@ export function createTalkRealtimeRelaySession( forcedConsults: createRealtimeVoiceForcedConsultCoordinator(), transcript: [], }; + relayRef.current = relay; relay.cleanupTimer.unref?.(); relaySessions.set(relaySessionId, relay); bridge.connect().catch((error: unknown) => { diff --git a/src/gateway/talk-transcription-relay.ts b/src/gateway/talk-transcription-relay.ts index ddafc15f5c5..a0f7f4dbc28 100644 --- a/src/gateway/talk-transcription-relay.ts +++ b/src/gateway/talk-transcription-relay.ts @@ -233,14 +233,15 @@ export function createTalkTranscriptionRelaySession( }, { onEvent: recordTalkObservabilityEvent }, ); - let relay: TranscriptionRelaySession | undefined; const emit = (event: TalkTranscriptionRelayEventPayload, talkEvent?: TalkEventInput): void => { broadcastToOwner(params.context, params.connId, { ...event, ...(talkEvent ? { talkEvent: talk.emit(talkEvent) } : {}), }); }; + const relayRef: { current?: TranscriptionRelaySession } = {}; const ensureTurnId = (): string => { + const relay = relayRef.current; return relay ? ensureTranscriptionTurn(relay) : "turn-1"; }; const sttSession = params.provider.createSession({ @@ -271,6 +272,7 @@ export function createTalkTranscriptionRelaySession( final: true, }, ); + const relay = relayRef.current; if (relay) { const ended = relay.talk.endTurn({ turnId, payload: {} }); if (ended.ok) { @@ -293,12 +295,13 @@ export function createTalkTranscriptionRelaySession( final: true, }, ); + const relay = relayRef.current; if (relay) { closeTranscriptionSession(relay, "error"); } }, }); - relay = { + const relay: TranscriptionRelaySession = { id: transcriptionSessionId, connId: params.connId, context: params.context, @@ -314,6 +317,7 @@ export function createTalkTranscriptionRelaySession( }, TRANSCRIPTION_SESSION_TTL_MS), closed: false, }; + relayRef.current = relay; relay.cleanupTimer.unref?.(); transcriptionSessions.set(transcriptionSessionId, relay); sttSession diff --git a/src/gateway/talk.test-helpers.ts b/src/gateway/talk.test-helpers.ts index ebfbf0e1d36..af74724f2d7 100644 --- a/src/gateway/talk.test-helpers.ts +++ b/src/gateway/talk.test-helpers.ts @@ -27,7 +27,7 @@ export async function invokeTalkSpeakDirect(params: Record) { respond: (ok, payload, error) => { response = { ok, payload, error }; }, - context: { getRuntimeConfig: getRuntimeConfig } as never, + context: { getRuntimeConfig } as never, }); return response; } diff --git a/src/gateway/test-helpers.e2e.ts b/src/gateway/test-helpers.e2e.ts index e0d13613a56..12ee34b8d91 100644 --- a/src/gateway/test-helpers.e2e.ts +++ b/src/gateway/test-helpers.e2e.ts @@ -68,7 +68,6 @@ export async function connectGatewayClient(params: { ); return await new Promise>((resolve, reject) => { let settled = false; - let client: InstanceType | undefined; const stop = (err?: Error, connectedClient?: InstanceType) => { if (settled) { return; @@ -84,7 +83,7 @@ export async function connectGatewayClient(params: { resolve(connectedClient as InstanceType); } }; - client = new GatewayClient({ + const client: InstanceType | undefined = new GatewayClient({ url: params.url, token: params.token, deviceToken: params.deviceToken, diff --git a/src/gateway/test-helpers.server.ts b/src/gateway/test-helpers.server.ts index 537b951e0c3..15b3d696d71 100644 --- a/src/gateway/test-helpers.server.ts +++ b/src/gateway/test-helpers.server.ts @@ -553,7 +553,6 @@ export function onceMessage( timeoutMs = 10_000, ): Promise { return new Promise((resolve, reject) => { - let timer: ReturnType; function cleanup() { clearTimeout(timer); ws.off("message", handler); @@ -570,7 +569,7 @@ export function onceMessage( resolve(obj); } } - timer = setTimeout(() => { + const timer: ReturnType = setTimeout(() => { cleanup(); reject(new Error("timeout")); }, timeoutMs); diff --git a/src/gateway/test/server-sessions.test-helpers.ts b/src/gateway/test/server-sessions.test-helpers.ts index 259d3e2edeb..4518c470fea 100644 --- a/src/gateway/test/server-sessions.test-helpers.ts +++ b/src/gateway/test/server-sessions.test-helpers.ts @@ -496,7 +496,7 @@ export async function directSessionReq( broadcastToConnIds: vi.fn(), getSessionEventSubscriberConnIds: () => new Set(), loadGatewayModelCatalog: async () => agentDiscoveryMock.models, - getRuntimeConfig: getRuntimeConfig, + getRuntimeConfig, ...opts?.context, } as never, client: opts?.client ?? null, diff --git a/src/hooks/frontmatter.ts b/src/hooks/frontmatter.ts index f0c8c46a9b6..ff9032e3fd5 100644 --- a/src/hooks/frontmatter.ts +++ b/src/hooks/frontmatter.ts @@ -64,7 +64,7 @@ export function resolveOpenClawMetadata( export: readStringValue(metadataObj.export), os: osRaw.length > 0 ? osRaw : undefined, events: eventsRaw.length > 0 ? eventsRaw : [], - requires: requires, + requires, install: install.length > 0 ? install : undefined, }; } diff --git a/src/hooks/gmail-watcher.ts b/src/hooks/gmail-watcher.ts index 0a143061071..3e9f97df60b 100644 --- a/src/hooks/gmail-watcher.ts +++ b/src/hooks/gmail-watcher.ts @@ -138,8 +138,6 @@ function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess { function settleProcess(proc: ChildProcess): Promise { return new Promise((resolve) => { let settled = false; - let escalation: ReturnType | undefined; - let finalTimeout: ReturnType | undefined; const settle = () => { if (settled) { return; @@ -156,7 +154,7 @@ function settleProcess(proc: ChildProcess): Promise { proc.kill("SIGTERM"); - escalation = setTimeout(() => { + const escalation: ReturnType | undefined = setTimeout(() => { try { proc.kill("SIGKILL"); } catch { @@ -164,7 +162,7 @@ function settleProcess(proc: ChildProcess): Promise { } }, 3_000); - finalTimeout = setTimeout(() => { + const finalTimeout: ReturnType | undefined = setTimeout(() => { if (!settled) { log.warn("gog process did not exit after SIGKILL; giving up"); settle(); diff --git a/src/infra/net/ssrf.pinning.test.ts b/src/infra/net/ssrf.pinning.test.ts index 69389fd3af4..f60824904ec 100644 --- a/src/infra/net/ssrf.pinning.test.ts +++ b/src/infra/net/ssrf.pinning.test.ts @@ -27,7 +27,7 @@ describe("ssrf pinning", () => { if (err) { reject(err); } else { - resolve({ address: address, family }); + resolve({ address, family }); } }); }); @@ -60,7 +60,7 @@ describe("ssrf pinning", () => { if (err) { reject(err); } else { - resolve({ address: address, family }); + resolve({ address, family }); } }); }); @@ -70,7 +70,7 @@ describe("ssrf pinning", () => { if (err) { reject(err); } else { - resolve({ address: address, family }); + resolve({ address, family }); } }); }); @@ -136,7 +136,7 @@ describe("ssrf pinning", () => { if (err) { reject(err); } else { - resolve({ address: address }); + resolve({ address }); } }); }); diff --git a/src/infra/outbound/account-scoped-conversation-bindings.ts b/src/infra/outbound/account-scoped-conversation-bindings.ts index aee34b7f6e1..a63ed3c4612 100644 --- a/src/infra/outbound/account-scoped-conversation-bindings.ts +++ b/src/infra/outbound/account-scoped-conversation-bindings.ts @@ -140,8 +140,6 @@ export function createAccountScopedConversationBindingManager = { accountId, getByConversationId: (conversationId) => @@ -241,7 +239,7 @@ export function createAccountScopedConversationBindingManager, - apiKey: string, + apiKeyInput: string, options?: AzureOpenAIResponsesOptions, ) { + let apiKey = apiKeyInput; if (!apiKey) { if (!process.env.AZURE_OPENAI_API_KEY) { throw new Error( diff --git a/src/llm/providers/openai-completions.ts b/src/llm/providers/openai-completions.ts index d925061495a..7ad133f095c 100644 --- a/src/llm/providers/openai-completions.ts +++ b/src/llm/providers/openai-completions.ts @@ -849,7 +849,7 @@ export function convertMessages( if (context.systemPrompt) { const useDeveloperRole = model.reasoning && compat.supportsDeveloperRole; const role = useDeveloperRole ? "developer" : "system"; - params.push({ role: role, content: sanitizeSurrogates(context.systemPrompt) }); + params.push({ role, content: sanitizeSurrogates(context.systemPrompt) }); } let lastRole: string | null = null; diff --git a/src/media-understanding/image.ts b/src/media-understanding/image.ts index ec602b52cc7..de4b62ed036 100644 --- a/src/media-understanding/image.ts +++ b/src/media-understanding/image.ts @@ -187,7 +187,7 @@ async function resolveImageRuntime(params: { }, ); const { authStorage } = resolved; - let { model } = resolved; + const { model } = resolved; if (!model) { throw new Error(`Unknown model: ${resolvedRef.provider}/${resolvedRef.model}`); } diff --git a/src/media/web-media.ts b/src/media/web-media.ts index 13bb440a7ed..0fe1a8396ee 100644 --- a/src/media/web-media.ts +++ b/src/media/web-media.ts @@ -806,9 +806,10 @@ export async function optimizeImageBufferForWebMedia(params: { } async function loadWebMediaInternal( - mediaUrl: string, + mediaUrlInput: string, options: WebMediaOptions = {}, ): Promise { + let mediaUrl = mediaUrlInput; const { maxBytes, optimizeImages = true, diff --git a/src/node-host/invoke-system-run.ts b/src/node-host/invoke-system-run.ts index 8664c577330..abe26f9f4a6 100644 --- a/src/node-host/invoke-system-run.ts +++ b/src/node-host/invoke-system-run.ts @@ -506,14 +506,7 @@ async function evaluateSystemRunPolicyPhase( onWarning: warnWritableTrustedDirOnce, }); const bins = autoAllowSkills ? await opts.skillBins.current() : []; - let { - analysisOk, - allowlistMatches, - allowlistSatisfied, - segments, - segmentAllowlistEntries, - segmentSatisfiedBy, - } = evaluateSystemRunAllowlist({ + const allowlistEvaluation = evaluateSystemRunAllowlist({ shellCommand: parsed.shellPayload, argv: parsed.argv, approvals, @@ -526,6 +519,9 @@ async function evaluateSystemRunPolicyPhase( skillBins: bins, autoAllowSkills, }); + const { allowlistMatches, segments, segmentAllowlistEntries, segmentSatisfiedBy } = + allowlistEvaluation; + let { analysisOk, allowlistSatisfied } = allowlistEvaluation; const strictInlineEval = agentExec?.strictInlineEval === true || cfg.tools?.exec?.strictInlineEval === true; const inlineEvalHit = strictInlineEval ? detectPolicyInlineEval(segments) : null; diff --git a/src/plugins/contracts/plugin-sdk-root-alias.test.ts b/src/plugins/contracts/plugin-sdk-root-alias.test.ts index 293ffafd19c..98d87c271b1 100644 --- a/src/plugins/contracts/plugin-sdk-root-alias.test.ts +++ b/src/plugins/contracts/plugin-sdk-root-alias.test.ts @@ -656,9 +656,8 @@ describe("plugin-sdk root alias", () => { it("falls back and removes stale diagnostic listeners when the dist subscription is invalid", () => { const seen: string[] = []; - let lazyModule!: ReturnType; const preexistingListener = (): void => undefined; - lazyModule = loadRootAliasWithStubs({ + const lazyModule: ReturnType = loadRootAliasWithStubs({ aliasPath: createDistAliasPath(), distEntries: ["diagnostic-events-W3Hz61fI.js"], monolithicExports: { diff --git a/src/plugins/update.ts b/src/plugins/update.ts index db7c2c773af..392aca95810 100644 --- a/src/plugins/update.ts +++ b/src/plugins/update.ts @@ -1677,7 +1677,7 @@ export async function updateNpmInstalledPlugins(params: { usedFallback: usedNpmFallback, }), phase: "update", - result: result, + result, }) : resultSource === "clawhub" ? formatClawHubInstallFailure({ diff --git a/src/shared/json-schema-defaults.ts b/src/shared/json-schema-defaults.ts index 511abebe96d..d1fb6d84358 100644 --- a/src/shared/json-schema-defaults.ts +++ b/src/shared/json-schema-defaults.ts @@ -1125,12 +1125,13 @@ function applyObjectPropertyAndDependencyDefaults( function applySchemaDefaults( schema: JsonSchemaValue, - value: unknown, + valueInput: unknown, root = schema, resolvingRefs = new Set(), resourceRoot = root, resourceBaseId?: string, ): unknown { + let value = valueInput; if (value === undefined) { const defaultValue = getDefault(schema); if (defaultValue !== undefined) { diff --git a/src/skills/loading/frontmatter.ts b/src/skills/loading/frontmatter.ts index dacfc8a2c55..7394f0e1dd7 100644 --- a/src/skills/loading/frontmatter.ts +++ b/src/skills/loading/frontmatter.ts @@ -201,7 +201,7 @@ export function resolveOpenClawMetadata( skillKey: readStringValue(metadataObj.skillKey), primaryEnv: readStringValue(metadataObj.primaryEnv), os: osRaw.length > 0 ? osRaw : undefined, - requires: requires, + requires, install: install.length > 0 ? install : undefined, }; } diff --git a/src/skills/loading/plugin-sandbox-sync.test.ts b/src/skills/loading/plugin-sandbox-sync.test.ts index a0b8a592b91..0caceed74e9 100644 --- a/src/skills/loading/plugin-sandbox-sync.test.ts +++ b/src/skills/loading/plugin-sandbox-sync.test.ts @@ -66,7 +66,7 @@ describe("syncSkillsToWorkspace for plugin skills", () => { await syncSkillsToWorkspace({ sourceWorkspaceDir: sourceWorkspace, targetWorkspaceDir: targetWorkspace, - pluginSkillsDir: pluginSkillsDir, + pluginSkillsDir, bundledSkillsDir: path.join(sourceWorkspace, ".bundled"), managedSkillsDir: path.join(sourceWorkspace, ".managed"), }); @@ -127,7 +127,7 @@ describe("syncSkillsToWorkspace for plugin skills", () => { await syncSkillsToWorkspace({ sourceWorkspaceDir: sourceWorkspace, targetWorkspaceDir: targetWorkspace, - pluginSkillsDir: pluginSkillsDir, + pluginSkillsDir, bundledSkillsDir: path.join(sourceWorkspace, ".bundled"), managedSkillsDir: path.join(sourceWorkspace, ".managed"), }); @@ -170,7 +170,7 @@ describe("syncSkillsToWorkspace for plugin skills", () => { await syncSkillsToWorkspace({ sourceWorkspaceDir: sourceWorkspace, targetWorkspaceDir: targetWorkspace, - pluginSkillsDir: pluginSkillsDir, + pluginSkillsDir, bundledSkillsDir: path.join(sourceWorkspace, ".bundled"), managedSkillsDir: path.join(sourceWorkspace, ".managed"), }); diff --git a/src/talk/audio-codec.ts b/src/talk/audio-codec.ts index 5c2e50fc95e..a92c9522808 100644 --- a/src/talk/audio-codec.ts +++ b/src/talk/audio-codec.ts @@ -225,7 +225,8 @@ export function convertPcmToMulaw8k(pcm: Buffer, inputSampleRate: number): Buffe return pcmToMulaw(resamplePcmTo8k(pcm, inputSampleRate)); } -function linearToMulaw(sample: number): number { +function linearToMulaw(sampleInput: number): number { + let sample = sampleInput; const BIAS = 132; const CLIP = 32635; diff --git a/src/talk/session-runtime.ts b/src/talk/session-runtime.ts index e30d5123f3d..3a0e4174951 100644 --- a/src/talk/session-runtime.ts +++ b/src/talk/session-runtime.ts @@ -59,12 +59,12 @@ export type RealtimeVoiceBridgeSessionParams = { export function createRealtimeVoiceBridgeSession( params: RealtimeVoiceBridgeSessionParams, ): RealtimeVoiceBridgeSession { - let bridge: RealtimeVoiceBridge | undefined; + const bridgeRef: { current?: RealtimeVoiceBridge } = {}; const requireBridge = () => { - if (!bridge) { + if (!bridgeRef.current) { throw new Error("Realtime voice bridge is not ready"); } - return bridge; + return bridgeRef.current; }; const session: RealtimeVoiceBridgeSession = { get bridge() { @@ -82,7 +82,7 @@ export function createRealtimeVoiceBridgeSession( triggerGreeting: (instructions) => requireBridge().triggerGreeting?.(instructions), }; const canSendAudio = () => params.audioSink.isOpen?.() ?? true; - bridge = params.provider.createBridge({ + const bridge = params.provider.createBridge({ cfg: params.cfg, providerConfig: params.providerConfig, audioFormat: params.audioFormat, @@ -105,7 +105,7 @@ export function createRealtimeVoiceBridgeSession( return; } if (params.markStrategy === "ack-immediately") { - bridge?.acknowledgeMark(); + bridgeRef.current?.acknowledgeMark(); return; } if (params.markStrategy === undefined || params.markStrategy === "transport") { @@ -115,23 +115,24 @@ export function createRealtimeVoiceBridgeSession( onTranscript: params.onTranscript, onEvent: params.onEvent, onToolCall: (event) => { - if (!bridge) { + if (!bridgeRef.current) { return; } params.onToolCall?.(event, session); }, onReady: () => { - if (!bridge) { + if (!bridgeRef.current) { return; } if (params.triggerGreetingOnReady) { - bridge.triggerGreeting?.(params.initialGreetingInstructions); + bridgeRef.current.triggerGreeting?.(params.initialGreetingInstructions); } params.onReady?.(session); }, onError: params.onError, onClose: params.onClose, }); + bridgeRef.current = bridge; return session; } diff --git a/src/wizard/setup.finalize.ts b/src/wizard/setup.finalize.ts index 902e0fbc3a1..c1854672bec 100644 --- a/src/wizard/setup.finalize.ts +++ b/src/wizard/setup.finalize.ts @@ -474,7 +474,7 @@ export async function finalizeSetupWizard( ); let controlUiOpened = false; - let seededInBackground = false; + const seededInBackground = false; let hatchChoice: "tui" | "web" | "later" | null = null; let launchedTui = false; diff --git a/src/wizard/setup.ts b/src/wizard/setup.ts index 92d9cd105a8..e213309ce33 100644 --- a/src/wizard/setup.ts +++ b/src/wizard/setup.ts @@ -68,13 +68,14 @@ function loadOnboardConfigModule(): Promise { } async function writeWizardConfigFile( - config: OpenClawConfig, + configInput: OpenClawConfig, opts: { allowConfigSizeDrop?: boolean; migrationBaseConfig?: OpenClawConfig; onPendingPluginInstallMigration?: () => void; } = {}, ): Promise { + let config = configInput; const allowConfigSizeDrop = opts.allowConfigSizeDrop === true; if (!allowConfigSizeDrop && hasPendingPluginInstallRecords(config)) { const migrationBaseConfig = opts.migrationBaseConfig; @@ -221,9 +222,10 @@ async function requireRiskAcknowledgement(params: { export async function runSetupWizard( opts: OnboardOptions, - runtime: RuntimeEnv | undefined, + runtimeInput: RuntimeEnv | undefined, prompter: WizardPrompter, ) { + let runtime = runtimeInput; runtime ??= defaultRuntime; const onboardHelpers = await import("../commands/onboard-helpers.js"); onboardHelpers.printWizardHeader(runtime); diff --git a/test/scripts/oxlint-config.test.ts b/test/scripts/oxlint-config.test.ts index e0a20e9876e..5f00ffb19a0 100644 --- a/test/scripts/oxlint-config.test.ts +++ b/test/scripts/oxlint-config.test.ts @@ -22,6 +22,7 @@ const ZERO_BASELINE_RULES = [ "eslint/no-sequences", "eslint/no-self-compare", "eslint/no-var", + "eslint/no-param-reassign", "eslint/no-implicit-coercion", "eslint/no-useless-rename", "eslint/no-useless-return", @@ -29,7 +30,9 @@ const ZERO_BASELINE_RULES = [ "eslint/no-else-return", "eslint/no-lonely-if", "eslint/no-case-declarations", + "eslint/object-shorthand", "eslint/prefer-exponentiation-operator", + "eslint/prefer-const", "eslint/prefer-numeric-literals", "eslint/prefer-object-has-own", "eslint/radix", diff --git a/ui/src/ui/chat/realtime-talk-google-live.ts b/ui/src/ui/chat/realtime-talk-google-live.ts index 5c335cb6c0a..4844bffef23 100644 --- a/ui/src/ui/chat/realtime-talk-google-live.ts +++ b/ui/src/ui/chat/realtime-talk-google-live.ts @@ -404,7 +404,8 @@ export class GoogleLiveRealtimeTalkTransport implements RealtimeTalkTransport { } } -async function decodeGoogleLiveMessageData(data: unknown): Promise { +async function decodeGoogleLiveMessageData(dataInput: unknown): Promise { + let data = dataInput; if (typeof data === "string") { return data; } diff --git a/ui/src/ui/chat/session-controls.ts b/ui/src/ui/chat/session-controls.ts index 18708b10eed..2a2b9742730 100644 --- a/ui/src/ui/chat/session-controls.ts +++ b/ui/src/ui/chat/session-controls.ts @@ -1020,15 +1020,15 @@ async function switchChatModel(state: AppViewState, nextModel: string): Promise< [targetSessionKey]: createChatModelOverride(nextModel), }; const client = state.client; - let switchPromise: Promise; + const switchPromiseRef: { current?: Promise } = {}; const clearPendingSwitch = () => { - if (state.chatModelSwitchPromises?.[targetSessionKey] === switchPromise) { + if (state.chatModelSwitchPromises?.[targetSessionKey] === switchPromiseRef.current) { const nextSwitches = { ...state.chatModelSwitchPromises }; delete nextSwitches[targetSessionKey]; state.chatModelSwitchPromises = nextSwitches; } }; - switchPromise = (async () => { + const switchPromise: Promise = (async () => { try { await client.request("sessions.patch", { key: targetSessionKey, @@ -1046,6 +1046,7 @@ async function switchChatModel(state: AppViewState, nextModel: string): Promise< clearPendingSwitch(); } })(); + switchPromiseRef.current = switchPromise; state.chatModelSwitchPromises = { ...state.chatModelSwitchPromises, [targetSessionKey]: switchPromise, diff --git a/ui/src/ui/realtime-talk-google-live.test.ts b/ui/src/ui/realtime-talk-google-live.test.ts index 52f3d3ef6fd..0d22921fdbe 100644 --- a/ui/src/ui/realtime-talk-google-live.test.ts +++ b/ui/src/ui/realtime-talk-google-live.test.ts @@ -320,7 +320,7 @@ describe("GoogleLiveRealtimeTalkTransport", () => { it("does not revive Talk status after stop while a tool consult settles", async () => { const onStatus = vi.fn(); - let runId = "run-1"; + const runId = "run-1"; const listeners = new Set<(event: { event: string; payload?: unknown }) => void>(); const client = { addEventListener: vi.fn((listener: (event: { event: string; payload?: unknown }) => void) => { diff --git a/ui/src/ui/tool-display.ts b/ui/src/ui/tool-display.ts index 139dc0d7846..d5cb81d55f1 100644 --- a/ui/src/ui/tool-display.ts +++ b/ui/src/ui/tool-display.ts @@ -109,7 +109,7 @@ export function resolveToolDisplay(params: { const icon = (spec?.icon ?? FALLBACK.icon ?? "puzzle") as IconName; const title = spec?.title ?? defaultTitle(name); const label = spec?.label ?? title; - let { verb, detail } = resolveToolVerbAndDetailForArgs({ + const toolDisplayParts = resolveToolVerbAndDetailForArgs({ toolKey: key, args: params.args, meta: params.meta, @@ -119,6 +119,8 @@ export function resolveToolDisplay(params: { toolDetailMode: params.detailMode, detailCoerce: { includeFalse: true, includeZero: true }, }); + const { verb } = toolDisplayParts; + let { detail } = toolDisplayParts; if (detail) { detail = shortenHomeInString(detail); diff --git a/ui/src/ui/views/config.browser.test.ts b/ui/src/ui/views/config.browser.test.ts index 7bb3613a481..d98894789bb 100644 --- a/ui/src/ui/views/config.browser.test.ts +++ b/ui/src/ui/views/config.browser.test.ts @@ -244,7 +244,7 @@ describe("config view", () => { let busyButton = findButtonContainingText(container, "Saving…"); let actionButtons = findActionButtons(container); let clearButton = requireActionButton(actionButtons.clearButton, "Clear"); - let applyButton = requireActionButton(actionButtons.applyButton, "Apply"); + const applyButton = requireActionButton(actionButtons.applyButton, "Apply"); expect(busyButton.disabled).toBe(true); expect(busyButton.getAttribute("aria-busy")).toBe("true"); expect(busyButton.querySelectorAll(".config-action-spinner")).toHaveLength(1); diff --git a/ui/src/ui/views/dreaming.test.ts b/ui/src/ui/views/dreaming.test.ts index 04f35a97be8..8a960c58118 100644 --- a/ui/src/ui/views/dreaming.test.ts +++ b/ui/src/ui/views/dreaming.test.ts @@ -368,7 +368,6 @@ describe("dreaming view", () => { setDreamSubTab("diary"); setDreamDiarySubTab("insights"); const container = document.createElement("div"); - let props: DreamingProps; const onOpenWikiPage = vi.fn().mockResolvedValue({ title: "BA flight receipts process", path: "sources/chatgpt-2026-04-10-alpha.md", @@ -377,7 +376,7 @@ describe("dreaming view", () => { truncated: true, }); const rerender = () => render(renderDreaming(props), container); - props = buildProps({ + const props: DreamingProps = buildProps({ onOpenWikiPage, onRequestUpdate: rerender, }); @@ -438,9 +437,8 @@ describe("dreaming view", () => { setDreamSubTab("diary"); setDreamDiarySubTab("palace"); const container = document.createElement("div"); - let props: DreamingProps; const rerender = () => render(renderDreaming(props), container); - props = buildProps({ onRequestUpdate: rerender }); + const props: DreamingProps = buildProps({ onRequestUpdate: rerender }); rerender(); const card = expectElement(container, "[data-palace-page='syntheses/travel-system.md']"); @@ -462,9 +460,8 @@ describe("dreaming view", () => { truncated: false, }); const container = document.createElement("div"); - let props: DreamingProps; const rerender = () => render(renderDreaming(props), container); - props = buildProps({ + const props: DreamingProps = buildProps({ onOpenWikiPage, onRequestUpdate: rerender, wikiMemoryPalace: {