From 07e8aecb39568259e455eccf2d558ba262e30974 Mon Sep 17 00:00:00 2001 From: sallyom Date: Fri, 8 May 2026 00:05:50 -0400 Subject: [PATCH] fix: speed up status json channel detection Signed-off-by: sallyom --- CHANGELOG.md | 1 + src/commands/status.scan.fast-json.test.ts | 1 + src/commands/status.scan.fast-json.ts | 9 +++---- src/commands/status.scan.test-helpers.ts | 29 ++++++++++++++-------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd2982776e1..3915bedc804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -180,6 +180,7 @@ Docs: https://docs.openclaw.ai - Gateway/macOS: `openclaw gateway stop` now uses `launchctl bootout` by default instead of unconditionally calling `launchctl disable`, so KeepAlive auto-recovery still works after unexpected crashes; use the new `--disable` flag to opt into the persistent-disable behavior when a manual stop should survive reboots. Fixes #77934. Thanks @bmoran1022. - Gateway/macOS: `repairLaunchAgentBootstrap` no longer kickstarts an already-running LaunchAgent, preventing unnecessary service restarts and session disconnects when repair runs against a healthy gateway. Fixes #77428. Thanks @ramitrkar-hash. - Gateway/macOS: `openclaw gateway stop --disable` now persists the LaunchAgent disable bit even after a previous bootout left the service not loaded, keeping the explicit stay-down path reliable. (#78412) Thanks @wdeveloper16. +- CLI/status: keep lean `openclaw status --json` off manifest-backed channel discovery so configured-channel checks do not repeatedly rescan plugin metadata. Fixes #79129. - Control UI/chat: hide retired and non-public Google Gemini model IDs from chat model catalogs and route the bare `gemini-3-pro` alias to Gemini 3.1 Pro Preview instead of the shut-down Gemini 3 Pro Preview. Thanks @BunsDev. - CLI/install: refuse state-mutating OpenClaw CLI runs as root by default, keep an explicit `OPENCLAW_ALLOW_ROOT=1` escape hatch for intentional root/container use, and update DigitalOcean setup guidance to run OpenClaw as a non-root user. Fixes #67478. Thanks @Jerry-Xin and @natechicago. - Auto-reply/media: resolve `scp` from `PATH` when staging sandbox media so nonstandard OpenSSH installs can copy remote attachments. diff --git a/src/commands/status.scan.fast-json.test.ts b/src/commands/status.scan.fast-json.test.ts index 102b2ae6a70..496d7f76352 100644 --- a/src/commands/status.scan.fast-json.test.ts +++ b/src/commands/status.scan.fast-json.test.ts @@ -55,6 +55,7 @@ describe("scanStatusJsonFast", () => { await scanStatusJsonFast({}, {} as never); + expect(mocks.hasConfiguredChannelsForReadOnlyScope).not.toHaveBeenCalled(); expect(mocks.ensurePluginRegistryLoaded).not.toHaveBeenCalled(); expect(loggingStateRef.forceConsoleToStderr).toBe(false); }); diff --git a/src/commands/status.scan.fast-json.ts b/src/commands/status.scan.fast-json.ts index 9b84eca6b61..d5904557521 100644 --- a/src/commands/status.scan.fast-json.ts +++ b/src/commands/status.scan.fast-json.ts @@ -1,5 +1,5 @@ +import { hasPotentialConfiguredChannels } from "../channels/config-presence.js"; import type { OpenClawConfig } from "../config/types.js"; -import { hasConfiguredChannelsForReadOnlyScope } from "../plugins/channel-plugin-ids.js"; import type { RuntimeEnv } from "../runtime.js"; import { executeStatusScanFromOverview } from "./status.scan-execute.ts"; import { @@ -58,11 +58,8 @@ export async function scanStatusJsonFast( commandName: "status --json", allowMissingConfigFastPath: true, includeChannelSummary: false, - resolveHasConfiguredChannels: (cfg, sourceConfig) => - hasConfiguredChannelsForReadOnlyScope({ - config: cfg, - activationSourceConfig: sourceConfig, - env: process.env, + resolveHasConfiguredChannels: (cfg) => + hasPotentialConfiguredChannels(cfg, process.env, { includePersistedAuthState: false, }), resolveMemory: async ({ cfg, agentStatus, memoryPlugin }) => diff --git a/src/commands/status.scan.test-helpers.ts b/src/commands/status.scan.test-helpers.ts index 2acbbc47aa2..65b692a6108 100644 --- a/src/commands/status.scan.test-helpers.ts +++ b/src/commands/status.scan.test-helpers.ts @@ -8,6 +8,7 @@ type ResolveConfigPathMock = Mock<() => string>; type StatusScanSharedMocks = { resolveConfigPath: ResolveConfigPathMock; hasPotentialConfiguredChannels: UnknownMock; + hasConfiguredChannelsForReadOnlyScope: UnknownMock; readBestEffortConfig: UnknownMock; resolveCommandSecretRefsViaGateway: UnknownMock; getUpdateCheckResult: UnknownMock; @@ -26,6 +27,7 @@ export function createStatusScanSharedMocks(configPathLabel: string): StatusScan return { resolveConfigPath: vi.fn(() => `/tmp/openclaw-${configPathLabel}-missing-${process.pid}.json`), hasPotentialConfiguredChannels: vi.fn(), + hasConfiguredChannelsForReadOnlyScope: vi.fn(), readBestEffortConfig: vi.fn(), resolveCommandSecretRefsViaGateway: vi.fn(), getUpdateCheckResult: vi.fn(), @@ -187,16 +189,7 @@ export async function loadStatusScanModuleForTest( config: OpenClawConfig; env?: NodeJS.ProcessEnv; includePersistedAuthState?: boolean; - }) => - Boolean( - mocks.hasPotentialConfiguredChannels( - params.config, - params.env, - params.includePersistedAuthState === undefined - ? undefined - : { includePersistedAuthState: params.includePersistedAuthState }, - ), - ), + }) => mocks.hasConfiguredChannelsForReadOnlyScope(params), listConfiguredChannelIdsForReadOnlyScope: (params: { config: OpenClawConfig; env?: NodeJS.ProcessEnv; @@ -409,6 +402,22 @@ export function applyStatusScanDefaults( const resolvedConfig = options.resolvedConfig ?? sourceConfig; mocks.hasPotentialConfiguredChannels.mockReturnValue(options.hasConfiguredChannels ?? false); + mocks.hasConfiguredChannelsForReadOnlyScope.mockImplementation((rawParams: unknown) => { + const params = rawParams as { + config: OpenClawConfig; + env?: NodeJS.ProcessEnv; + includePersistedAuthState?: boolean; + }; + return Boolean( + mocks.hasPotentialConfiguredChannels( + params.config, + params.env, + params.includePersistedAuthState === undefined + ? undefined + : { includePersistedAuthState: params.includePersistedAuthState }, + ), + ); + }); mocks.readBestEffortConfig.mockResolvedValue(sourceConfig); mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({ resolvedConfig,