From dd2aedf08fe05af550aa3098b1f7978ffc26875b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 10 Aug 2026 18:17:13 -0700 Subject: [PATCH] refactor: burn export name collision debt (#121767) * refactor(tasks): disambiguate lifecycle helpers * refactor(channels): clarify account and id helpers * refactor(media): separate SDK facades from cores * refactor(auto-reply): consolidate command helpers * refactor(cli): disambiguate registration helpers * refactor(gateway): clarify runtime and test helpers * chore(scripts): burn resolved collision debt * fix(refactor): update remaining core callers * fix(refactor): update remaining UI callers * chore(plugin-sdk): refresh API baseline --- docs/.generated/plugin-sdk-api-baseline.jsonl | 34 +-- .../lib/export-name-collision-baseline.json | 253 ------------------ scripts/lib/wrapper-shadowing-baseline.json | 25 -- ...sh-tools.exec-gateway-approval.e2e.test.ts | 4 +- .../context-engine-maintenance.test.ts | 8 +- src/agents/tools/sessions-send-helpers.ts | 2 +- src/auto-reply/reply/agent-runner-utils.ts | 4 +- src/auto-reply/reply/commands-acp.test.ts | 4 +- src/auto-reply/reply/commands-acp.ts | 5 +- .../reply/commands-acp/diagnostics.ts | 20 +- .../reply/commands-acp/lifecycle.ts | 42 +-- .../reply/commands-acp/runtime-options.ts | 22 +- src/auto-reply/reply/commands-acp/shared.ts | 10 +- src/auto-reply/reply/commands-allowlist.ts | 8 +- src/auto-reply/reply/commands-config.ts | 4 +- src/auto-reply/reply/commands-status.test.ts | 40 +-- .../reply/commands-subagents-dispatch.ts | 1 - .../reply/commands-subagents-routing.test.ts | 8 - .../reply/commands-subagents.test.ts | 4 +- src/auto-reply/reply/commands-subagents.ts | 5 +- .../reply/commands-subagents/action-agents.ts | 5 +- .../reply/commands-subagents/action-focus.ts | 24 +- .../reply/commands-subagents/action-help.ts | 5 +- .../reply/commands-subagents/action-info.ts | 11 +- .../reply/commands-subagents/action-list.ts | 5 +- .../reply/commands-subagents/action-log.ts | 8 +- .../commands-subagents/action-unfocus.ts | 11 +- .../reply/commands-subagents/shared.ts | 7 +- src/auto-reply/reply/commands-tasks.test.ts | 38 +-- src/auto-reply/reply/dispatch-acp.runtime.ts | 4 +- src/auto-reply/reply/dispatch-acp.test.ts | 6 +- src/auto-reply/reply/dispatch-acp.ts | 2 +- src/auto-reply/thinking.shared.ts | 9 +- src/auto-reply/thinking.ts | 4 +- src/channels/account-summary.test.ts | 6 +- src/channels/account-summary.ts | 2 +- src/channels/plugins/session-conversation.ts | 2 +- src/channels/plugins/status.ts | 2 +- src/channels/registry.ts | 9 +- src/cli/completion-cli.ts | 4 +- src/cli/completion-cli.write-state.test.ts | 2 +- src/cli/daemon-cli/lifecycle-core.test.ts | 10 +- .../test-helpers/lifecycle-core-harness.ts | 2 +- src/cli/deps.ts | 4 +- src/cli/plugins-cli-test-helpers.ts | 92 +++---- src/cli/plugins-cli.install.test.ts | 16 +- src/cli/plugins-cli.list.test.ts | 92 +++---- src/cli/plugins-cli.policy.test.ts | 4 +- src/cli/plugins-cli.uninstall.test.ts | 18 +- src/cli/plugins-cli.update.test.ts | 28 +- src/cli/plugins-install-preflight.test.ts | 4 +- src/cli/program.smoke.test.ts | 4 +- src/cli/program.test-mocks.ts | 2 +- src/cli/program/register.subclis-core.ts | 4 +- src/cli/program/register.subclis.ts | 4 +- src/cli/run-main.ts | 31 +-- src/commands/agents.bindings.ts | 2 +- src/commands/channels.list.test.ts | 18 +- .../channels.status.command-flow.test.ts | 2 +- src/commands/channels/list.ts | 6 +- src/commands/channels/logs.ts | 2 +- src/commands/channels/status-config-format.ts | 4 +- src/commands/flows.test.ts | 20 +- src/commands/status-all/channels.ts | 4 +- src/config/io.factory.ts | 12 +- src/config/io.observe-recovery.test.ts | 28 +- src/config/io.observe-recovery.ts | 8 +- src/cron/service/ops.test.ts | 6 +- src/cron/service/task-runs.test.ts | 12 +- src/cron/service/task-runs.ts | 14 +- src/cron/service/timer.test.ts | 6 +- .../gateway-cli-backend.live-helpers.ts | 2 +- src/gateway/gateway-cli-backend.live.test.ts | 4 +- src/gateway/gateway-codex-bind.live.test.ts | 4 +- .../gateway-models.profiles.live.test.ts | 8 +- .../gateway-trajectory-export.live.test.ts | 4 +- src/gateway/gateway-wizard-cancel.e2e.test.ts | 4 +- src/gateway/gateway.test.ts | 20 +- .../operator-approvals-client.e2e.test.ts | 6 +- .../server-methods/channels.status.test.ts | 24 +- src/gateway/server-methods/channels.ts | 4 +- ...n-approval-turn-source-routing.e2e.test.ts | 4 +- src/gateway/server-methods/tasks.ts | 4 +- src/gateway/server-model-catalog.ts | 2 +- .../server-network-runtime.e2e.test.ts | 6 +- src/gateway/server-start.ts | 9 +- ...rver-startup-copied-auth-secretref.test.ts | 6 +- .../server-startup-plugin-quarantine.test.ts | 6 +- ...ver-startup-secret-owner-isolation.test.ts | 14 +- .../server-startup-web-fetch-bind.test.ts | 6 +- ...erver.agent.gateway-server-agent-a.test.ts | 4 +- .../server.auth.compat-baseline.test.ts | 14 +- src/gateway/server.auth.control-ui.suite.ts | 4 +- .../server.auth.default-token.suite.ts | 6 +- src/gateway/server.auth.modes.suite.ts | 22 +- src/gateway/server.auth.test-helpers.ts | 4 +- .../server.board-generated-identity.test.ts | 8 +- ...erver.context-prewarm.remote-proof.test.ts | 4 +- src/gateway/server.e2e-ws-harness.ts | 6 +- src/gateway/server.impl.ts | 2 +- .../server.minimal-channel-pin.test.ts | 4 +- .../server.models-voicewake-misc.test.ts | 8 +- src/gateway/server.sessions-send.test.ts | 6 +- .../server.shared-auth-rotation.test.ts | 10 +- .../server.shared-token-hot-reload.test.ts | 6 +- ...rver.shared-token-session-rotation.test.ts | 6 +- .../server.startup-websocket-race.test.ts | 10 +- src/gateway/server.ts | 8 +- ...henticated-request-dispatch.server.test.ts | 4 +- src/gateway/session-transcript-readers.ts | 4 +- src/gateway/session-utils.fs.test.ts | 15 +- src/gateway/session-utils.fs.ts | 2 +- src/gateway/test-helpers.e2e.ts | 4 +- src/gateway/test-helpers.server.ts | 13 +- src/gateway/test-helpers.ts | 2 +- src/infra/channel-summary.ts | 7 +- src/infra/provider-usage.fetch.shared.ts | 4 +- src/infra/provider-usage.load.ts | 16 +- src/infra/provider-usage.shared.ts | 6 +- src/infra/update-runner-command.ts | 2 +- src/infra/update-runner-install-surface.ts | 4 +- src/infra/update-runner.ts | 4 +- src/media-understanding/image-runtime.ts | 10 +- .../image.runtime-profile.test.ts | 28 +- .../image.runtime-timeout.test.ts | 30 +-- src/media-understanding/image.test.ts | 32 +-- src/media-understanding/image.ts | 12 +- src/plugins/install-persistence.test.ts | 16 +- .../install-persistence.warning-sink.test.ts | 14 +- src/tasks/detached-task-runtime.ts | 32 +-- src/tasks/runtime-internal.ts | 2 +- src/tasks/task-executor-cancel.runtime.ts | 2 +- src/tasks/task-executor.test.ts | 14 +- src/tasks/task-executor.ts | 32 +-- src/tasks/task-flow-registry.audit.test.ts | 4 +- src/tasks/task-flow-registry.e2e.test.ts | 4 +- .../task-flow-registry.maintenance.test.ts | 6 +- src/tasks/task-operations.e2e.test.ts | 8 +- src/tasks/task-registry-cancel.ts | 4 +- src/tasks/task-registry-record-api.ts | 2 +- src/tasks/task-registry.test.ts | 28 +- src/tasks/task-registry.ts | 2 +- .../plugins/canvas-agent-node.e2e.test.ts | 4 +- .../gateway-agent-artifact-apis.e2e.test.ts | 4 +- .../gateway-direct-tool-invoke.e2e.test.ts | 6 +- .../gateway-exec-approvals.e2e.test.ts | 4 +- .../runtime/gateway-hosted-web.e2e.test.ts | 4 +- .../runtime/gateway-http-apis.e2e.test.ts | 6 +- .../gateway-plugin-approvals.e2e.test.ts | 4 +- .../gateway-usage-memory-apis.e2e.test.ts | 4 +- test/plugin-cron-registry-owner.e2e.test.ts | 4 +- ui/src/e2e/board-mcp-app.e2e.test.ts | 4 +- ui/src/e2e/mcp-app-conformance.e2e.test.ts | 8 +- ui/src/lib/chat/thinking.ts | 6 +- 154 files changed, 753 insertions(+), 1071 deletions(-) diff --git a/docs/.generated/plugin-sdk-api-baseline.jsonl b/docs/.generated/plugin-sdk-api-baseline.jsonl index 0051b511b021..33b47283fbe5 100644 --- a/docs/.generated/plugin-sdk-api-baseline.jsonl +++ b/docs/.generated/plugin-sdk-api-baseline.jsonl @@ -53,7 +53,7 @@ {"closureHash":"ff3c4616cd6212a6d698831a8b287ad87e3968c8663f4090d095bb30ec40fc1c","declaration":"export function abortAndDrainAgentHarnessRun(params: { sessionId: string; sessionKey?: string; settleMs?: number; forceClear?: boolean; reason?: string; }): Promise;","entrypoint":"agent-harness","exportName":"abortAndDrainAgentHarnessRun","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} {"closureHash":"58989e3fa91eecf2e05202e36548e6e64a3b9219e83154bd99866c851604e34e","declaration":"export function createAgentToolResultMiddlewareRunner(ctx: AgentToolResultMiddlewareContext, handlers?: AgentToolResultMiddleware[]): { applyToolResultMiddleware(event: AgentToolResultMiddlewareEvent): Promise; };","entrypoint":"agent-harness","exportName":"createAgentToolResultMiddlewareRunner","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} {"closureHash":"b8f6355d7ad1700aceecddaa6e9ccf43091a792d5b481a1ee3f55294a881a67d","declaration":"export function createCodexAppServerToolResultExtensionRunner(ctx: CodexAppServerExtensionContext, factories?: CodexAppServerExtensionFactory[]): { applyToolResultExtensions(event: CodexAppServerToolResultEvent): Promise>; };","entrypoint":"agent-harness","exportName":"createCodexAppServerToolResultExtensionRunner","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} -{"closureHash":"b1fbc2d6c6a6725072af0ec97151814e998d59e19536f2567dbdcc42cd12765a","declaration":"export function createOpenClawCodingTools(options?: OpenClawCodingToolsOptions): AnyAgentTool[];","entrypoint":"agent-harness","exportName":"createOpenClawCodingTools","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} +{"closureHash":"9cfaaa0bb0d08eb8d47932492a7874fb138705087508d7b361b049da2c2e350b","declaration":"export function createOpenClawCodingTools(options?: OpenClawCodingToolsOptions): AnyAgentTool[];","entrypoint":"agent-harness","exportName":"createOpenClawCodingTools","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} {"closureHash":"13649ee853485319e7449fda25c106b3f3f53d3090e53cdbb28e220a8529eb80","declaration":"export function disposeRegisteredAgentHarnesses(): Promise;","entrypoint":"agent-harness","exportName":"disposeRegisteredAgentHarnesses","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} {"closureHash":"f255a91162ece4c239bb8fa745efa14a1054bc024a291e9954f75f239b2b87c3","declaration":"export function resolveActiveEmbeddedRunSessionId(sessionKey: string): string | undefined;","entrypoint":"agent-harness","exportName":"resolveActiveEmbeddedRunSessionId","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} {"closureHash":"27d9f61df9ccf68615cb2002a6da891e36ab0c07623bc37c4d07aa980b446881","declaration":"export function resolveWebSearchToolPolicy(params: WebSearchToolPolicyParams): WebSearchToolPolicyResolution;","entrypoint":"agent-harness","exportName":"resolveWebSearchToolPolicy","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"} @@ -1097,7 +1097,7 @@ {"closureHash":"9555a73ba2717bba0bf94888017be4cecef2c51cc3887ed34f8d8ef3c79d6abf","declaration":"export const DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS: number;","entrypoint":"channel-message","exportName":"DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"} {"closureHash":"3a2df3ab656149630c004d2d9f71b8ceda99aa81eb6b72b0cc7b3982ed0ce044","declaration":"export const DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS: 8;","entrypoint":"channel-message","exportName":"DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"} {"closureHash":"38c735a14c65067aa7825390d1c5c8876c651d0603e84980dfaf947f5235747a","declaration":"export const INGRESS_CLAIM_PROCESS_ID: string;","entrypoint":"channel-message","exportName":"INGRESS_CLAIM_PROCESS_ID","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"} -{"closureHash":"5236937315f09d137a86caad72e09219503aa2d4b2d66fa004e18c51455cabe7","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-message","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"} +{"closureHash":"d420856f586028947a5239f5f44c78f13d611039f1e5292438eae0b5e1f4133e","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-message","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"} {"closureHash":"2c52eff200a5b9bd2d93ee72209c2626bbe165f59b538591db661b94773023b0","declaration":"export type AgentPlanStep = AgentPlanStep;","entrypoint":"channel-message","exportName":"AgentPlanStep","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"} {"closureHash":"1e8bcb2c8d8f5327f5b81b8c217f722f090dccba21ba3943324010f4f80a5a50","declaration":"export type AgentPlanStepStatus = AgentPlanStepStatus;","entrypoint":"channel-message","exportName":"AgentPlanStepStatus","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"} {"closureHash":"b036fc26e5330dfd7da1af8839bb3c23e85283b9e16e252a659dd4bb0c35cd5e","declaration":"export type ChannelDeliveryStreamingConfig = ChannelDeliveryStreamingConfig;","entrypoint":"channel-message","exportName":"ChannelDeliveryStreamingConfig","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"} @@ -1226,7 +1226,7 @@ {"closureHash":"9555a73ba2717bba0bf94888017be4cecef2c51cc3887ed34f8d8ef3c79d6abf","declaration":"export const DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS: number;","entrypoint":"channel-outbound","exportName":"DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"} {"closureHash":"3a2df3ab656149630c004d2d9f71b8ceda99aa81eb6b72b0cc7b3982ed0ce044","declaration":"export const DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS: 8;","entrypoint":"channel-outbound","exportName":"DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"} {"closureHash":"38c735a14c65067aa7825390d1c5c8876c651d0603e84980dfaf947f5235747a","declaration":"export const INGRESS_CLAIM_PROCESS_ID: string;","entrypoint":"channel-outbound","exportName":"INGRESS_CLAIM_PROCESS_ID","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"} -{"closureHash":"5236937315f09d137a86caad72e09219503aa2d4b2d66fa004e18c51455cabe7","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-outbound","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"} +{"closureHash":"d420856f586028947a5239f5f44c78f13d611039f1e5292438eae0b5e1f4133e","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-outbound","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"} {"closureHash":"2c52eff200a5b9bd2d93ee72209c2626bbe165f59b538591db661b94773023b0","declaration":"export type AgentPlanStep = AgentPlanStep;","entrypoint":"channel-outbound","exportName":"AgentPlanStep","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"} {"closureHash":"1e8bcb2c8d8f5327f5b81b8c217f722f090dccba21ba3943324010f4f80a5a50","declaration":"export type AgentPlanStepStatus = AgentPlanStepStatus;","entrypoint":"channel-outbound","exportName":"AgentPlanStepStatus","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"} {"closureHash":"b036fc26e5330dfd7da1af8839bb3c23e85283b9e16e252a659dd4bb0c35cd5e","declaration":"export type ChannelDeliveryStreamingConfig = ChannelDeliveryStreamingConfig;","entrypoint":"channel-outbound","exportName":"ChannelDeliveryStreamingConfig","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"} @@ -2354,7 +2354,7 @@ {"closureHash":"98e0cc16352b7dfcceb4957f8cd2acfe3c2b3acb223c42a5cfb885e088fcb04c","declaration":"export function resolveInboundReplyDispatchCounts(result: ChannelTurnDispatchResultLike): Record;","entrypoint":"inbound-reply-dispatch","exportName":"resolveInboundReplyDispatchCounts","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"} {"closureHash":"9d503d05e408ddd1a1c373e3c4485b1f9acff4c240fdc241840a2cfa8b55c3a7","declaration":"export function runChannelInboundEvent(params: RunChannelTurnParams): Promise>;\nexport function runChannelInboundEvent(params: ChannelInboundEventRunnerParams): Promise>;","entrypoint":"inbound-reply-dispatch","exportName":"runChannelInboundEvent","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"} {"closureHash":"2c68496a174872b31aaf1ac8fad2789deb79d490c5ffbcb157325f1c95d1b51f","declaration":"export function runPreparedInboundReply(params: PreparedChannelTurn): Promise>;","entrypoint":"inbound-reply-dispatch","exportName":"runPreparedInboundReply","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"} -{"closureHash":"5236937315f09d137a86caad72e09219503aa2d4b2d66fa004e18c51455cabe7","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"inbound-reply-dispatch","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"const","recordType":"export"} +{"closureHash":"d420856f586028947a5239f5f44c78f13d611039f1e5292438eae0b5e1f4133e","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"inbound-reply-dispatch","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"const","recordType":"export"} {"closureHash":"278dc8a410230012ddbc3552ec621a224e6f7c5dd4cd3904c943ac98dd4259e4","declaration":"export type AssembledInboundReply = AssembledChannelTurn;","entrypoint":"inbound-reply-dispatch","exportName":"AssembledInboundReply","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"} {"closureHash":"3de0d6d1bb8f9a83bd1c6e57aa8618e3fea71054236cd530c555e348bd0b7702","declaration":"export type ChannelBotLoopProtectionFacts = ChannelBotLoopProtectionFacts;","entrypoint":"inbound-reply-dispatch","exportName":"ChannelBotLoopProtectionFacts","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"} {"closureHash":"f0da845bbdf49b30f6718a4b7ff012a0536deb98f65418583555dc90825797ca","declaration":"export type ChannelInboundDroppedHistoryOptions = ChannelTurnDroppedHistoryOptions;","entrypoint":"inbound-reply-dispatch","exportName":"ChannelInboundDroppedHistoryOptions","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"} @@ -3189,19 +3189,19 @@ {"closureHash":"50394942e0a454c742e80a4f3c8739c80258b387ade498eb5aed66df887108be","declaration":"export function callMeetingBrowserProxyOnNode(params: { runtime: PluginRuntime; adapter: NodeAdapter; nodeId: string; } & MeetingBrowserRequestParams): Promise;","entrypoint":"meeting-runtime","exportName":"callMeetingBrowserProxyOnNode","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"c5fcd1d157edcb4773235adfaf8051e3ec7ca428cb7916b6d55f2511affab56c","declaration":"export function convertMeetingBridgeAudioForStt(audio: Buffer, audioFormat: MeetingRealtimeAudioFormat): Buffer;","entrypoint":"meeting-runtime","exportName":"convertMeetingBridgeAudioForStt","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"aa9063c27c5ff714d3653571c4a2a71e9d2eea5609b161f03e4738e15411358b","declaration":"export function convertMeetingTtsAudioForBridge(audio: Buffer, sampleRate: number, audioFormat: MeetingRealtimeAudioFormat, outputFormat?: string, platformName?: string): Buffer;","entrypoint":"meeting-runtime","exportName":"convertMeetingTtsAudioForBridge","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"848a8280cc071320c1e62520382920bd4d3653b315d3e8b19df6d7aa787aa1b3","declaration":"export function createLocalMeetingRealtimeAudioTransport(params: { inputCommand: string[]; outputCommand: string[]; bargeInInputCommand?: string[]; bargeInRmsThreshold: number; bargeInPeakThreshold: number; bargeInCooldownMs: number; logger: RuntimeLogger; logScope: string; audioFormat?: MeetingRealtimeAudioFormat; spawn?: MeetingRealtimeAudioSpawn; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createLocalMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"c70707c4e2171a912f22899350eea3d71a5969eacd50dc1d59f06f3bb86acbd9","declaration":"export function createLocalMeetingRealtimeAudioTransport(params: { inputCommand: string[]; outputCommand: string[]; bargeInInputCommand?: string[]; bargeInRmsThreshold: number; bargeInPeakThreshold: number; bargeInCooldownMs: number; logger: RuntimeLogger; logScope: string; audioFormat?: MeetingRealtimeAudioFormat; spawn?: MeetingRealtimeAudioSpawn; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createLocalMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"9cb63eefd2e5a70aea960bf17fcf570ef02a2d7b5afd5ad9451802964c653fcf","declaration":"export function createMeetingBrowserNodeCaller(params: { runtime: PluginRuntime; adapter: NodeAdapter; nodeId: string; }): MeetingBrowserRequestCaller;","entrypoint":"meeting-runtime","exportName":"createMeetingBrowserNodeCaller","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"f244ca8c47f556c9f388953cf9a7581c7d4d413af93e0dfa1462779e6a687a7c","declaration":"export function createMeetingBrowserNodeInvokePolicy(options: MeetingBrowserNodePolicyOptions): OpenClawPluginNodeInvokePolicy;","entrypoint":"meeting-runtime","exportName":"createMeetingBrowserNodeInvokePolicy","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"1aa4e3ff39a2cbe162421c62b1fa4a362973381d4d9ff15c671249b1ebd566bc","declaration":"export function createMeetingNodeHost(options: MeetingNodeHostOptions): { handleCommand(paramsJSON?: string | null): Promise; };","entrypoint":"meeting-runtime","exportName":"createMeetingNodeHost","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"4932698dbb72134c12cabaae29be0fa82328cd46bd61d8aa3f087c78768486fd","declaration":"export function createMeetingRealtimeEngineBindings(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { agentId?: string; toolPolicy: RealtimeVoiceAgentConsultToolPolicy; }; }; fullConfig: OpenClawConfig; runtime: PluginRuntime; logger: RuntimeLogger; }): { platform: MeetingRuntimePlatform; consultAgent: (consult: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (call: MeetingRealtimeToolCallParams) => Promise; };","entrypoint":"meeting-runtime","exportName":"createMeetingRealtimeEngineBindings","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"70a5384f9a5e217338410ae45f1b93bb431ccb0c2b9c1a40bc5e50bc68a2449b","declaration":"export function createMeetingRealtimeEngineBindings(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { agentId?: string; toolPolicy: RealtimeVoiceAgentConsultToolPolicy; }; }; fullConfig: OpenClawConfig; runtime: PluginRuntime; logger: RuntimeLogger; }): { platform: MeetingRuntimePlatform; consultAgent: (consult: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (call: MeetingRealtimeToolCallParams) => Promise; };","entrypoint":"meeting-runtime","exportName":"createMeetingRealtimeEngineBindings","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"9124db05923060c467edb149bd8abdc8be1d00d00f867cf84600972923a58489","declaration":"export function createMeetingSession(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { provider?: string; voiceProvider?: string; transcriptionProvider?: string; model?: string; toolPolicy: TToolPolicy; }; }; resolved: MeetingResolvedJoin; createdAt: string; }): MeetingSessionRecord;","entrypoint":"meeting-runtime","exportName":"createMeetingSession","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"fb276e07e395ab19177b3d7967fd0a8fcda79130883f15092a4a306b826481b9","declaration":"export function createMeetingSetupStatus(checks: MeetingSetupCheck[]): MeetingSetupStatus;","entrypoint":"meeting-runtime","exportName":"createMeetingSetupStatus","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"93c4bb70429a2739151e6f900e67bed81f3cd8f597811220e790341edb0d6008","declaration":"export function createMeetingVoiceCallGateway(params: { config: MeetingVoiceCallConfig; runtime: PluginRuntime; surface: MeetingVoiceCallSurface; connectClient: (params: { config: MeetingVoiceCallConfig; surface: MeetingVoiceCallSurface; }) => Promise; }): MeetingVoiceCallGateway;","entrypoint":"meeting-runtime","exportName":"createMeetingVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"8390fe7fe0b6ab44150cccce3a11b05207fe2253f5b955d2fb3d7aa6588acffe","declaration":"export function createNodeMeetingRealtimeAudioTransport(params: { runtime: PluginRuntime; nodeId: string; bridgeId: string; logger: RuntimeLogger; commandName: string; logScope: string; logPrefix: string; audioFormat?: MeetingRealtimeAudioFormat; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createNodeMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"bc1315a8130ef57fe62d31d54f35b7a9d3085ae5bae65a5dc23a83a66c36436a","declaration":"export function createNodeMeetingRealtimeAudioTransport(params: { runtime: PluginRuntime; nodeId: string; bridgeId: string; logger: RuntimeLogger; commandName: string; logScope: string; logPrefix: string; audioFormat?: MeetingRealtimeAudioFormat; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createNodeMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"c0987b15a391a92d53d3e4e12b61eb122f9547fcf4f45478cdd3c5a8973a3e52","declaration":"export function endMeetingVoiceCallGatewayCall(params: { gateway: MeetingVoiceCallGateway; callId: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"endMeetingVoiceCallGatewayCall","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"b3ebc10fe7ab372e1317eaa8f78621cf277bba1e33fda57acf2254f6759d1e9d","declaration":"export function getMeetingVoiceCallGatewayCall(params: { gateway: MeetingVoiceCallGateway; callId: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"getMeetingVoiceCallGatewayCall","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"aac088df8e80d9ce89c45feccdb04ace3ae4417b3fcdd0f058410ddf25c96b46","declaration":"export function isMeetingVoiceCallMissingError(error: unknown): boolean;","entrypoint":"meeting-runtime","exportName":"isMeetingVoiceCallMissingError","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"e14386402c25ad496352bcf803e17218ed648e6b5f34514c7f07c9091f2466dd","declaration":"export function joinMeetingViaVoiceCallGateway(params: { config: MeetingVoiceCallConfig; gateway: MeetingVoiceCallGateway; surface: MeetingVoiceCallSurface; dialInNumber: string; dtmfSequence?: string; logger?: RuntimeLogger; message?: string; requesterSessionKey?: string; agentId?: string; sessionKey?: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"joinMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"6f5d639ae00dcc0d07499c27d21bf1f865139a81ddaa315468991d7ba2f35c7f","declaration":"export function joinMeetingViaVoiceCallGateway(params: { config: MeetingVoiceCallConfig; gateway: MeetingVoiceCallGateway; surface: MeetingVoiceCallSurface; dialInNumber: string; dtmfSequence?: string; logger?: RuntimeLogger; message?: string; requesterSessionKey?: string; agentId?: string; sessionKey?: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"joinMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"bac9621cd025754fbcd4c21409b06eb0503405db81f35cac993aaf0b881ab3e1","declaration":"export function leaveMeetingWithBrowser(params: { adapter: BrowserAdapter; callBrowser: MeetingBrowserRequestCaller; launch: boolean; meetingSessionId?: string; meetingUrl: string; tab: MeetingBrowserTab; timeoutMs: number; }): Promise<{ left: boolean; note: string; }>;","entrypoint":"meeting-runtime","exportName":"leaveMeetingWithBrowser","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"c7b1aeac134b2070d053adf33026d876998b852ccd65cd2c9667119b1a1abee2","declaration":"export function openMeetingWithBrowser, Mode extends string, Health extends MeetingBrowserHealth & { browserTitle?: string; browserUrl?: string; notes?: string[]; }, Transcript extends MeetingTranscriptSnapshot>(params: { adapter: BrowserAdapter; callBrowser: MeetingBrowserRequestCaller; config: MeetingBrowserControllerConfig; session: Session; }): Promise<{ launched: boolean; browser?: Health; tab?: MeetingBrowserTab; }>;","entrypoint":"meeting-runtime","exportName":"openMeetingWithBrowser","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"34858979bd248799c2215d9c7bdd5d4a6b27660c9173bfca2e50dd4373ac27db","declaration":"export function readMeetingBrowserTab(result: unknown): MeetingBrowserCandidateTab | undefined;","entrypoint":"meeting-runtime","exportName":"readMeetingBrowserTab","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} @@ -3212,8 +3212,8 @@ {"closureHash":"56874c5b2ced5af647b1dff296c931f0d8b85b1318e98c741aa88b58a9c5c606","declaration":"export function resolveMeetingBrowserNodeInfo(params: { runtime: PluginRuntime; adapter: NodeAdapter; requestedNode?: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"resolveMeetingBrowserNodeInfo","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"f21196c9ea8ab90248ffdcdef3e942f1247ee2b9064ddb9757fffe352362c779","declaration":"export function resolveMeetingRealtimeAudioFormat(audioFormat: MeetingRealtimeAudioFormat): RealtimeVoiceAudioFormat;","entrypoint":"meeting-runtime","exportName":"resolveMeetingRealtimeAudioFormat","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"521dc5c262524a709cdd27cdc88e95004073da8223537bcbc73d5d423172dc2b","declaration":"export function speakMeetingViaVoiceCallGateway(params: { gateway: MeetingVoiceCallGateway; callId: string; message: string; }): Promise;","entrypoint":"meeting-runtime","exportName":"speakMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"795a6bda2c41fecbb0f7d5e500d6ce18ddb062a1667f9be0f769d5aba14c5f91","declaration":"export function startMeetingAgentRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeTranscriptionProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; }): Promise;","entrypoint":"meeting-runtime","exportName":"startMeetingAgentRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} -{"closureHash":"a350254ea889399f103718694e4c16eb3246849e288e18c115cd60dba78d6a63","declaration":"export function startMeetingRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; talkSessionId?: string; talkContext?: { nodeId: string; bridgeId: string; }; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeVoiceProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (params: MeetingRealtimeToolCallParams) => Promise; }): Promise;","entrypoint":"meeting-runtime","exportName":"startMeetingRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"0e660fb72f507995ee218f6cb63a392ddac22e9fcb98b4a5b9b577d6afbd2377","declaration":"export function startMeetingAgentRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeTranscriptionProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; }): Promise;","entrypoint":"meeting-runtime","exportName":"startMeetingAgentRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} +{"closureHash":"690d10ea23a39c93ded9782825b020ebffa20d7a979ea5274773ef414d867529","declaration":"export function startMeetingRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; talkSessionId?: string; talkContext?: { nodeId: string; bridgeId: string; }; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeVoiceProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (params: MeetingRealtimeToolCallParams) => Promise; }): Promise;","entrypoint":"meeting-runtime","exportName":"startMeetingRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"} {"closureHash":"663b9c77231b21af697efd5042e22d1c33e9ee972adeb312ad86d81a2b2e36f7","declaration":"export type MeetingAgentConsultParams = MeetingAgentConsultParams;","entrypoint":"meeting-runtime","exportName":"MeetingAgentConsultParams","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"adf0745c611bf737fc28978d766fc2a25b7104e71b6b2fed4e9b95e519c7b115","declaration":"export type MeetingBrowserCandidateTab = MeetingBrowserCandidateTab;","entrypoint":"meeting-runtime","exportName":"MeetingBrowserCandidateTab","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"59b1526172b7491b85f14f13c1ee26d8d6726f33093770748580c767b1689a17","declaration":"export type MeetingBrowserControllerConfig = MeetingBrowserControllerConfig;","entrypoint":"meeting-runtime","exportName":"MeetingBrowserControllerConfig","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} @@ -3245,7 +3245,7 @@ {"closureHash":"8244b408803f57cf2004157e96f2ce11bb036cdf864123b15ba2fac7f03b5d43","declaration":"export type MeetingSessionRuntimeHandles = MeetingSessionRuntimeHandles;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeHandles","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"aa8054fc2c442891197e89bdad61e79999ea15d813c4b127fb6150607b9e67e7","declaration":"export type MeetingSessionRuntimeJoinContext, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab> = MeetingSessionRuntimeJoinContext;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeJoinContext","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"325241724edd38da439c5df03d225e2a7cb8e56d817e98ed7c37850656d3744b","declaration":"export type MeetingSessionRuntimeMessages = MeetingSessionRuntimeMessages;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeMessages","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} -{"closureHash":"358a20ffa7f1ac9cde7431a628c546817df5212955b9cb634699e9c9a065c246","declaration":"export type MeetingSessionRuntimeOptions, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> = MeetingSessionRuntimeOptions;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeOptions","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} +{"closureHash":"d5cfb8ce0591d2c56f9c7d2962a3c103affaa560f066b3a9ec19e96104883458","declaration":"export type MeetingSessionRuntimeOptions, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> = MeetingSessionRuntimeOptions;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeOptions","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"d3c730cba02d30512c4cdae6e2367c662982e2c25671833ecd8701283924c642","declaration":"export type MeetingSessionState = MeetingSessionState;","entrypoint":"meeting-runtime","exportName":"MeetingSessionState","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"2496931157bf64fdb16013172ab9c023e60c5f85b98f46a3ee9532ce58d636d6","declaration":"export type MeetingSetupCheck = MeetingSetupCheck;","entrypoint":"meeting-runtime","exportName":"MeetingSetupCheck","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"f0aed6f7955a43fc387d8bbc072cb6276b0f2d18e7f829441a2ad45974bb3831","declaration":"export type MeetingSetupStatus = MeetingSetupStatus;","entrypoint":"meeting-runtime","exportName":"MeetingSetupStatus","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} @@ -3259,9 +3259,9 @@ {"closureHash":"20c70a94483aeddda4d1500cfcc5e71fab844b474ba4061c55d6c8693d40821b","declaration":"export type MeetingVoiceCallJoinResult = MeetingVoiceCallJoinResult;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallJoinResult","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"4fb2c5928aa6f809dd4c604d71c5c99cdfe3e98b6e9c1662601c9b4ad9738162","declaration":"export type MeetingVoiceCallStatusResult = MeetingVoiceCallStatusResult;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallStatusResult","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} {"closureHash":"5ef812397b6409a4ca228943dd1080661365959477b42e705a9aaa219757d14f","declaration":"export type MeetingVoiceCallSurface = MeetingVoiceCallSurface;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallSurface","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"} -{"closureHash":"b981b84a269682560b6ca79bf62628f44d1cd30584c6703263b427f2f8592737","declaration":"export interface MeetingPlatformAdapter extends MeetingPlatformAdapterContract {\n}","entrypoint":"meeting-runtime","exportName":"MeetingPlatformAdapter","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"} +{"closureHash":"9b3952af9ca74d74b0ec98824cdc759023b134dacef29117fb907f7c5d5c7d1a","declaration":"export interface MeetingPlatformAdapter extends MeetingPlatformAdapterContract {\n}","entrypoint":"meeting-runtime","exportName":"MeetingPlatformAdapter","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"} {"closureHash":"79884bd1df1ea0d07d5ceb4c62d93c1ee744b75d31c94c988845869c0f3cbd2d","declaration":"export interface MeetingRealtimeAudioTransport {\n onFatal(handler: () => void): void;\n startInput(onAudio: (audio: Buffer) => void): void;\n beginOutput?(): void;\n stop(): Promise;\n writeOutput(audio: Buffer): Promise;\n clearOutput(): Promise;\n dispose(): Promise;\n getHealth?(): MeetingRealtimeAudioTransportHealth;\n startBargeInMonitor?(onBargeIn: (audio: Buffer) => boolean): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"} -{"closureHash":"74889426bdb2a90f11a40de44ec7399fb82d942d84eda3568aa23644c18dcfe1","declaration":"export class MeetingSessionRuntime, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> {\n readonly #sessions: Map;\n readonly #sessionLeaves: Map>>;\n readonly #sessionCleanup: MeetingSessionCleanupTracker;\n readonly #meetingLock: MeetingSessionJoinLock;\n readonly #sessionStops: Map Promise>;\n readonly #sessionSpeakers: Map void>;\n readonly #sessionHealth: Map Partial>;\n readonly #durableTranscripts: MeetingSessionDurableTranscripts;\n readonly #transcriptStore: MeetingSessionTranscriptStore;\n constructor(private readonly options: MeetingSessionRuntimeOptions);\n list(): TSession[];\n getSession(sessionId: string): TSession | undefined;\n async status(sessionId?: string): Promise<{\n found: boolean;\n session?: TSession;\n sessions?: TSession[];\n }>;\n async transcript(sessionId: string, options: {\n sinceIndex?: number;\n }): Promise<{ found: boolean; sessionId?: string; startIndex?: number; nextIndex?: number; droppedLines?: number; evicted?: boolean; lines?: MeetingTranscriptLine[]; }>;\n async startTranscriptSource(request: TranscriptStartRequest): Promise;\n async stopTranscriptSource(request: TranscriptStopRequest): Promise;\n isReusableSession(session: TSession, resolved: MeetingResolvedJoin): boolean;\n async join(request: TRequest): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async leave(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n async speak(sessionId: string, instructions?: string): Promise<{\n found: boolean;\n spoken: boolean;\n session?: TSession;\n }>;\n async speakWhenReady(session: TSession, instructions: string): Promise;\n hasHealthHandle(sessionId: string): boolean;\n refreshHealth(sessionId?: string): void;\n async refreshBrowserHealth(session: TSession, options: {\n force?: boolean;\n readOnly?: boolean;\n }): Promise;\n async refreshCaptionHealth(session: TSession): Promise;\n refreshSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n markSessionEnded(session: TSession, reason: string): void;\n async #joinUnlocked(request: TRequest, resolved: MeetingResolvedJoin): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async #leaveUnlocked(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n async #leaveSession(session: TSession, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n #meetingKey(transport: TTransport, url: string): string;\n #inheritBrowserTabOwnership(params: {\n session: TSession;\n transport: TTransport;\n nodeId?: string;\n meetingUrl: string;\n tab?: TTab;\n }): TTab | undefined;\n async #settleRetainedBrowserTabs(retained: Array<{\n session: TSession;\n tab: TTab;\n }>, adopted?: {\n transport: TTransport;\n nodeId?: string;\n tab: TTab;\n }): Promise;\n async #rollbackFailedJoinSession(session: TSession): Promise;\n async #settleRetainedBrowserTabsAfterFailure(retained: Array<{\n session: TSession;\n tab: TTab;\n }>): Promise;\n #attachRuntimeHandles(session: TSession, handles: MeetingSessionRuntimeHandles): void;\n #dropRuntimeHandles(sessionId: string): void;\n #isManagedBrowserSession(session: TSession): boolean;\n #evaluateSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n #noteSession(session: TSession, note: string): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"class","recordType":"export"} +{"closureHash":"1e14a81a141e1f34fc747e106e98538c67f53fe5e221883ce512f6863a6b53e3","declaration":"export class MeetingSessionRuntime, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> {\n readonly #sessions: Map;\n readonly #sessionLeaves: Map>>;\n readonly #sessionCleanup: MeetingSessionCleanupTracker;\n readonly #meetingLock: MeetingSessionJoinLock;\n readonly #sessionStops: Map Promise>;\n readonly #sessionSpeakers: Map void>;\n readonly #sessionHealth: Map Partial>;\n readonly #durableTranscripts: MeetingSessionDurableTranscripts;\n readonly #transcriptStore: MeetingSessionTranscriptStore;\n constructor(private readonly options: MeetingSessionRuntimeOptions);\n list(): TSession[];\n getSession(sessionId: string): TSession | undefined;\n async status(sessionId?: string): Promise<{\n found: boolean;\n session?: TSession;\n sessions?: TSession[];\n }>;\n async transcript(sessionId: string, options: {\n sinceIndex?: number;\n }): Promise<{ found: boolean; sessionId?: string; startIndex?: number; nextIndex?: number; droppedLines?: number; evicted?: boolean; lines?: MeetingTranscriptLine[]; }>;\n async startTranscriptSource(request: TranscriptStartRequest): Promise;\n async stopTranscriptSource(request: TranscriptStopRequest): Promise;\n isReusableSession(session: TSession, resolved: MeetingResolvedJoin): boolean;\n async join(request: TRequest): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async leave(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n async speak(sessionId: string, instructions?: string): Promise<{\n found: boolean;\n spoken: boolean;\n session?: TSession;\n }>;\n async speakWhenReady(session: TSession, instructions: string): Promise;\n hasHealthHandle(sessionId: string): boolean;\n refreshHealth(sessionId?: string): void;\n async refreshBrowserHealth(session: TSession, options: {\n force?: boolean;\n readOnly?: boolean;\n }): Promise;\n async refreshCaptionHealth(session: TSession): Promise;\n refreshSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n markSessionEnded(session: TSession, reason: string): void;\n async #joinUnlocked(request: TRequest, resolved: MeetingResolvedJoin): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async #leaveUnlocked(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n async #leaveSession(session: TSession, options?: {\n keepBrowserTab?: boolean;\n }): Promise>;\n #meetingKey(transport: TTransport, url: string): string;\n #inheritBrowserTabOwnership(params: {\n session: TSession;\n transport: TTransport;\n nodeId?: string;\n meetingUrl: string;\n tab?: TTab;\n }): TTab | undefined;\n async #settleRetainedBrowserTabs(retained: Array<{\n session: TSession;\n tab: TTab;\n }>, adopted?: {\n transport: TTransport;\n nodeId?: string;\n tab: TTab;\n }): Promise;\n async #rollbackFailedJoinSession(session: TSession): Promise;\n async #settleRetainedBrowserTabsAfterFailure(retained: Array<{\n session: TSession;\n tab: TTab;\n }>): Promise;\n #attachRuntimeHandles(session: TSession, handles: MeetingSessionRuntimeHandles): void;\n #dropRuntimeHandles(sessionId: string): void;\n #isManagedBrowserSession(session: TSession): boolean;\n #evaluateSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n #noteSession(session: TSession, note: string): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"class","recordType":"export"} {"category":null,"entrypoint":"memory-core-host-engine-foundation","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","recordType":"module"} {"closureHash":"e2df8d235401aebf58eb71652fbeaedb42ca00aaa5042a76909ff2c48ba6fd54","declaration":"export function createSubsystemLogger(subsystem: string): SubsystemLogger;","entrypoint":"memory-core-host-engine-foundation","exportName":"createSubsystemLogger","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","kind":"function","recordType":"export"} {"closureHash":null,"declaration":"export function isPathInside(root: string, target: string): boolean;","entrypoint":"memory-core-host-engine-foundation","exportName":"isPathInside","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","kind":"function","recordType":"export"} @@ -3655,10 +3655,10 @@ {"closureHash":"e66adcb55dec79be73a52bc76594b7e9210fd93c69a85b56098fbb58cecbb354","declaration":"export type WriteOAuthCredentialsOptions = WriteOAuthCredentialsOptions;","entrypoint":"provider-auth","exportName":"WriteOAuthCredentialsOptions","importSpecifier":"openclaw/plugin-sdk/provider-auth","kind":"type","recordType":"export"} {"category":null,"entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","recordType":"module"} {"closureHash":"b5665596a3f011454a5614681513516acd50b6c749536c43842d811980cf7ad3","declaration":"export function augmentModelCatalogWithProviderPlugins(params: { config?: OpenClawConfig; workspaceDir?: string; env?: NodeJS.ProcessEnv; metadataSnapshot?: PluginMetadataSnapshot; context: ProviderAugmentModelCatalogContext; }): Promise;","entrypoint":"provider-catalog-runtime","exportName":"augmentModelCatalogWithProviderPlugins","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} -{"closureHash":"92f24d657fc620b3d47cb3d8b2f05a1ac5d9eb3ee65ee897d2767175a0fc6a34","declaration":"export function isPluginProvidersLoadInFlight(params: Parameters[0]): boolean;","entrypoint":"provider-catalog-runtime","exportName":"isPluginProvidersLoadInFlight","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} -{"closureHash":"492e70830dc8040252f35c457233a9563f79938b163975b2ed1d8c9b1cec118a","declaration":"export function resolveCatalogHookProviderPluginIds(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; metadataSnapshot?: ProviderManifestLoadParams[\"metadataSnapshot\"]; }): string[];","entrypoint":"provider-catalog-runtime","exportName":"resolveCatalogHookProviderPluginIds","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} -{"closureHash":"ca3d898386ceb6c1e7d8a8be80cfcf93fc99cd9f9bb2bbf8ba0a844f9624cccf","declaration":"export function resolveOwningPluginIdsForProvider(params: { provider: string; config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; manifestRegistry?: PluginManifestRegistry; metadataSnapshot?: Pick; }): string[] | undefined;","entrypoint":"provider-catalog-runtime","exportName":"resolveOwningPluginIdsForProvider","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} -{"closureHash":"355e8319052cdc2e9e1e553f8dd58efaef3f8af710f855d0988dc165958e589b","declaration":"export function resolvePluginProviders(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; bundledProviderVitestCompat?: boolean; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; activate?: boolean; cache?: boolean; applyAutoEnable?: boolean; pluginSdkResolution?: PluginLoadOptions[\"pluginSdkResolution\"]; mode?: \"runtime\" | \"setup\"; includeUntrustedWorkspacePlugins?: boolean; pluginMetadataSnapshot?: PluginMetadataRegistryView; skipIfLoadInFlight?: boolean; }): ProviderPlugin[];","entrypoint":"provider-catalog-runtime","exportName":"resolvePluginProviders","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} +{"closureHash":"21ecb9d9b55785897a3abb0fd07613d0e06cb323c2d9e5066d66e64821e2acd5","declaration":"export function isPluginProvidersLoadInFlight(params: Parameters[0]): boolean;","entrypoint":"provider-catalog-runtime","exportName":"isPluginProvidersLoadInFlight","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} +{"closureHash":"a81a0603b2a5f136ec58ccf6b0963f15dcecec57506ca2f58a3aff2cc4ec903c","declaration":"export function resolveCatalogHookProviderPluginIds(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; metadataSnapshot?: ProviderManifestLoadParams[\"metadataSnapshot\"]; }): string[];","entrypoint":"provider-catalog-runtime","exportName":"resolveCatalogHookProviderPluginIds","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} +{"closureHash":"61d926974cc9b13df361c3fefa7b7ec570ecda663126f0847c77211d1b710058","declaration":"export function resolveOwningPluginIdsForProvider(params: { provider: string; config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; manifestRegistry?: PluginManifestRegistry; metadataSnapshot?: Pick; }): string[] | undefined;","entrypoint":"provider-catalog-runtime","exportName":"resolveOwningPluginIdsForProvider","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} +{"closureHash":"beaaa1633f55d6f9d1dc5c49da4a297d73e5c35756162302ed4dc72cfc291d90","declaration":"export function resolvePluginProviders(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; bundledProviderVitestCompat?: boolean; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; activate?: boolean; cache?: boolean; applyAutoEnable?: boolean; pluginSdkResolution?: PluginLoadOptions[\"pluginSdkResolution\"]; mode?: \"runtime\" | \"setup\"; includeUntrustedWorkspacePlugins?: boolean; pluginMetadataSnapshot?: PluginMetadataRegistryView; skipIfLoadInFlight?: boolean; }): ProviderPlugin[];","entrypoint":"provider-catalog-runtime","exportName":"resolvePluginProviders","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"} {"category":null,"entrypoint":"proxy-capture","importSpecifier":"openclaw/plugin-sdk/proxy-capture","recordType":"module"} {"closureHash":"d0e4e026d736bc00b1758d1089c44c3c5f3a09c7254291584de8cb297365804c","declaration":"export function acquireDebugProxyCaptureStore(dbPath: string, blobDir: string): { store: LegacyDebugProxyCaptureStore; release: () => void; };\nexport function acquireDebugProxyCaptureStore(options?: DebugProxyCaptureStoreOptions): { store: SharedDebugProxyCaptureStore; release: () => void; };","entrypoint":"proxy-capture","exportName":"acquireDebugProxyCaptureStore","importSpecifier":"openclaw/plugin-sdk/proxy-capture","kind":"function","recordType":"export"} {"closureHash":"d41cbb9de51b7aee1c6cf8c713b0bc44f27ac926fbb6422c05726f196d11964e","declaration":"export function captureHttpExchange(params: { url: string; method: string; requestHeaders?: Headers | Record | undefined; requestBody?: BodyInit | Buffer | string | null; response: Response; transport?: \"http\" | \"sse\"; flowId?: string; meta?: Record; }, resolved?: DebugProxySettings, deps?: DebugProxyCaptureRuntimeDeps): void;","entrypoint":"proxy-capture","exportName":"captureHttpExchange","importSpecifier":"openclaw/plugin-sdk/proxy-capture","kind":"function","recordType":"export"} diff --git a/scripts/lib/export-name-collision-baseline.json b/scripts/lib/export-name-collision-baseline.json index 1e434d2f12cd..db089282b06e 100644 --- a/scripts/lib/export-name-collision-baseline.json +++ b/scripts/lib/export-name-collision-baseline.json @@ -51,13 +51,6 @@ "src/gateway/server-methods/__mocks__/tools-effective.runtime.ts" ] }, - { - "name": "buildChannelAccountSnapshot", - "files": [ - "src/channels/account-summary.ts", - "src/channels/plugins/status.ts" - ] - }, { "name": "buildPluginDiagnosticsReport", "files": [ @@ -124,13 +117,6 @@ ], "sdk": true }, - { - "name": "cancelDetachedTaskRunById", - "files": [ - "src/tasks/task-executor-cancel.runtime.ts", - "src/tasks/task-executor.ts" - ] - }, { "name": "classifySessionKind", "files": [ @@ -183,13 +169,6 @@ "src/agents/embedded-agent-runner/compact.ts" ] }, - { - "name": "completeTaskRunByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, { "name": "containsConfigIncludeDirective", "files": [ @@ -240,20 +219,6 @@ "src/plugins/logger.ts" ] }, - { - "name": "createQueuedTaskRun", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, - { - "name": "createRunningTaskRun", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, { "name": "createSessionId", "files": [ @@ -276,13 +241,6 @@ ], "sdk": true }, - { - "name": "DEFAULT_TIMEOUT_MS", - "files": [ - "src/infra/provider-usage.shared.ts", - "src/infra/update-runner-command.ts" - ] - }, { "name": "defaultRuntime", "files": [ @@ -299,38 +257,6 @@ ], "sdk": true }, - { - "name": "describeImagesWithModel", - "files": [ - "src/media-understanding/image-runtime.ts", - "src/media-understanding/image.ts" - ], - "sdk": true - }, - { - "name": "describeImagesWithModelPayloadTransform", - "files": [ - "src/media-understanding/image-runtime.ts", - "src/media-understanding/image.ts" - ], - "sdk": true - }, - { - "name": "describeImageWithModel", - "files": [ - "src/media-understanding/image-runtime.ts", - "src/media-understanding/image.ts" - ], - "sdk": true - }, - { - "name": "describeImageWithModelPayloadTransform", - "files": [ - "src/media-understanding/image-runtime.ts", - "src/media-understanding/image.ts" - ], - "sdk": true - }, { "name": "dispatchReplyWithBufferedBlockDispatcher", "files": [ @@ -371,13 +297,6 @@ ], "sdk": true }, - { - "name": "ensureConfigReady", - "files": [ - "src/cli/program.test-mocks.ts", - "src/cli/program/config-guard.ts" - ] - }, { "name": "ensureConfiguredAcpBindingReady", "files": [ @@ -415,13 +334,6 @@ "src/gateway/session-transcript-readers.ts" ] }, - { - "name": "failTaskRunByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, { "name": "fileExists", "files": [ @@ -431,13 +343,6 @@ ], "sdk": true }, - { - "name": "finalizeTaskRunByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-registry-record-api.ts" - ] - }, { "name": "formatConfigPath", "files": [ @@ -507,13 +412,6 @@ ], "sdk": true }, - { - "name": "getFreeGatewayPort", - "files": [ - "src/gateway/gateway-cli-backend.live-helpers.ts", - "src/gateway/test-helpers.e2e.ts" - ] - }, { "name": "getFreePort", "files": [ @@ -856,14 +754,6 @@ "src/infra/state-migrations.session-store.ts" ] }, - { - "name": "normalizeChannelId", - "files": [ - "src/channels/plugins/registry.ts", - "src/channels/registry.ts" - ], - "sdk": true - }, { "name": "normalizeContainerPath", "files": [ @@ -900,13 +790,6 @@ "src/cron/run-diagnostics-normalize.ts" ] }, - { - "name": "notifyGatewayPluginMetadataChanged", - "files": [ - "src/cli/plugins-cli-test-helpers.ts", - "src/cli/plugins-update-gateway-signal.ts" - ] - }, { "name": "optimizeImageToJpeg", "files": [ @@ -1012,27 +895,6 @@ "src/plugins/uninstall.ts" ] }, - { - "name": "preserveConfigSnapshotAsClobbered", - "files": [ - "src/config/io.observe-recovery.ts", - "src/config/io.runtime.ts" - ] - }, - { - "name": "promoteConfigSnapshotToLastKnownGood", - "files": [ - "src/config/io.observe-recovery.ts", - "src/config/io.runtime.ts" - ] - }, - { - "name": "promptYesNo", - "files": [ - "src/cli/plugins-cli-test-helpers.ts", - "src/cli/prompt.ts" - ] - }, { "name": "readAmbientTranscriptWatermark", "files": [ @@ -1064,13 +926,6 @@ ], "sdk": true }, - { - "name": "readLatestSessionUsageFromTranscriptAsync", - "files": [ - "src/gateway/session-transcript-readers.ts", - "src/gateway/session-utils.fs.ts" - ] - }, { "name": "readPersistedInstalledPluginIndex", "files": [ @@ -1115,20 +970,6 @@ "src/plugins/installs.ts" ] }, - { - "name": "recordTaskRunProgressByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, - { - "name": "recoverConfigFromLastKnownGood", - "files": [ - "src/config/io.observe-recovery.ts", - "src/config/io.runtime.ts" - ] - }, { "name": "redactSecrets", "files": [ @@ -1144,27 +985,6 @@ "src/plugins/plugin-registry-snapshot.ts" ] }, - { - "name": "registerPluginsCli", - "files": [ - "src/cli/plugins-cli-test-helpers.ts", - "src/cli/plugins-cli.ts" - ] - }, - { - "name": "registerSubCliByName", - "files": [ - "src/cli/program/register.subclis-core.ts", - "src/cli/program/register.subclis.ts" - ] - }, - { - "name": "registerSubCliCommands", - "files": [ - "src/cli/program/register.subclis-core.ts", - "src/cli/program/register.subclis.ts" - ] - }, { "name": "replaceConfigFile", "files": [ @@ -1209,14 +1029,6 @@ "src/gateway/test-helpers.assertions.ts" ] }, - { - "name": "resetPreparedModelCatalogForTest", - "files": [ - "src/gateway/server-model-catalog.ts", - "src/gateway/server-start.ts", - "src/gateway/server.ts" - ] - }, { "name": "resolveAdvertisedLanHost", "files": [ @@ -1319,13 +1131,6 @@ "src/plugins/config-state.ts" ] }, - { - "name": "resolveMissingPluginCommandMessage", - "files": [ - "src/cli/run-main-policy.ts", - "src/cli/run-main.ts" - ] - }, { "name": "resolveNode", "files": [ @@ -1361,14 +1166,6 @@ "src/plugins/provider-thinking.ts" ] }, - { - "name": "resolveProviderUsageDisplayName", - "files": [ - "src/infra/provider-usage.admin.ts", - "src/infra/provider-usage.shared.ts" - ], - "sdk": true - }, { "name": "resolveSecretInputString", "files": [ @@ -1415,13 +1212,6 @@ ], "sdk": true }, - { - "name": "resolveThinkingDefaultForModel", - "files": [ - "src/auto-reply/thinking.shared.ts", - "src/auto-reply/thinking.ts" - ] - }, { "name": "restorePersistedInstalledPluginIndexIfCurrent", "files": [ @@ -1459,13 +1249,6 @@ "src/commands/system-agent-with-inference.ts" ] }, - { - "name": "runtimeLogs", - "files": [ - "src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts", - "src/cli/plugins-cli-test-helpers.ts" - ] - }, { "name": "runTui", "files": [ @@ -1497,13 +1280,6 @@ ], "sdk": true }, - { - "name": "setDetachedTaskDeliveryStatusByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, { "name": "setupCommand", "files": [ @@ -1526,28 +1302,6 @@ ], "sdk": true }, - { - "name": "startGatewayServer", - "files": [ - "src/gateway/server-start.ts", - "src/gateway/server.ts", - "src/gateway/test-helpers.server.ts" - ] - }, - { - "name": "startTaskRunByRunId", - "files": [ - "src/tasks/detached-task-runtime.ts", - "src/tasks/task-executor.ts" - ] - }, - { - "name": "stopWithText", - "files": [ - "src/auto-reply/reply/commands-acp/shared.ts", - "src/auto-reply/reply/commands-subagents/shared.ts" - ] - }, { "name": "stripTargetKindPrefix", "files": [ @@ -1609,13 +1363,6 @@ ], "sdk": true }, - { - "name": "tryDispatchAcpReply", - "files": [ - "src/auto-reply/reply/dispatch-acp.runtime.ts", - "src/auto-reply/reply/dispatch-acp.ts" - ] - }, { "name": "updateNpmInstalledHookPacks", "files": [ diff --git a/scripts/lib/wrapper-shadowing-baseline.json b/scripts/lib/wrapper-shadowing-baseline.json index 0c8fe130f15b..56d06ee4f7dc 100644 --- a/scripts/lib/wrapper-shadowing-baseline.json +++ b/scripts/lib/wrapper-shadowing-baseline.json @@ -253,27 +253,12 @@ "wrapped": "src/plugin-sdk/boolean-param.ts", "wrapper": "src/infra/outbound/message-action-params.ts" }, - { - "name": "readLatestSessionUsageFromTranscriptAsync", - "wrapped": "src/gateway/session-utils.fs.ts", - "wrapper": "src/gateway/session-transcript-readers.ts" - }, { "name": "readSessionTranscriptVisibleMessageDelta", "wrapped": "src/config/sessions/session-accessor.sqlite-active-events.ts", "wrapper": "src/plugin-sdk/session-transcript-runtime.ts", "via": "src/config/sessions/session-accessor.ts" }, - { - "name": "registerSubCliByName", - "wrapped": "src/cli/program/register.subclis-core.ts", - "wrapper": "src/cli/program/register.subclis.ts" - }, - { - "name": "registerSubCliCommands", - "wrapped": "src/cli/program/register.subclis-core.ts", - "wrapper": "src/cli/program/register.subclis.ts" - }, { "name": "replaceRuntimeAuthProfileStoreSnapshots", "wrapped": "src/agents/auth-profiles/runtime-snapshots.ts", @@ -305,11 +290,6 @@ "wrapped": "src/auto-reply/heartbeat.ts", "wrapper": "src/infra/heartbeat-runner-config.ts" }, - { - "name": "resolveMissingPluginCommandMessage", - "wrapped": "src/cli/run-main-policy.ts", - "wrapper": "src/cli/run-main.ts" - }, { "name": "resolvePluginProviders", "wrapped": "src/plugins/providers.runtime.ts", @@ -350,11 +330,6 @@ "wrapped": "src/config/sessions/paths.ts", "wrapper": "src/plugin-sdk/session-store-runtime.ts" }, - { - "name": "resolveThinkingDefaultForModel", - "wrapped": "src/auto-reply/thinking.shared.ts", - "wrapper": "src/auto-reply/thinking.ts" - }, { "name": "runProviderModelSelectedHook", "wrapped": "src/plugins/provider-wizard.ts", diff --git a/src/agents/bash-tools.exec-gateway-approval.e2e.test.ts b/src/agents/bash-tools.exec-gateway-approval.e2e.test.ts index 8f5eb948e2e2..f3507ece726b 100644 --- a/src/agents/bash-tools.exec-gateway-approval.e2e.test.ts +++ b/src/agents/bash-tools.exec-gateway-approval.e2e.test.ts @@ -15,7 +15,7 @@ import { startGatewayServer } from "../gateway/server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../gateway/test-helpers.e2e.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "../gateway/test-helpers.env.js"; import { captureEnv, setTestEnvValue } from "../test-utils/env.js"; @@ -68,7 +68,7 @@ describe("gateway-hosted exec approvals", () => { const workspaceDir = path.join(tempHome, "workspace"); await fs.mkdir(workspaceDir, { recursive: true }); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const token = "exec-approval-e2e-token"; const configPath = path.join(stateDir, "openclaw.json"); await fs.mkdir(stateDir, { recursive: true }); diff --git a/src/agents/embedded-agent-runner/context-engine-maintenance.test.ts b/src/agents/embedded-agent-runner/context-engine-maintenance.test.ts index 369da755784c..fb89c6930f40 100644 --- a/src/agents/embedded-agent-runner/context-engine-maintenance.test.ts +++ b/src/agents/embedded-agent-runner/context-engine-maintenance.test.ts @@ -9,7 +9,7 @@ import { enqueueCommandInLane, markGatewayDraining } from "../../process/command import * as commandQueueModule from "../../process/command-queue.js"; import { resetCommandQueueStateForTest } from "../../process/command-queue.test-support.js"; import { onSessionTranscriptUpdate } from "../../sessions/transcript-events.js"; -import { createQueuedTaskRun as createQueuedTaskRunOrNull } from "../../tasks/task-executor.js"; +import { createQueuedTaskRunCore as createQueuedTaskRunOrNull } from "../../tasks/task-executor.js"; import { getTaskFlowById } from "../../tasks/task-flow-registry.js"; import { getTaskById, listTasksForOwnerKey } from "../../tasks/task-registry.js"; import type { TaskRecord } from "../../tasks/task-registry.types.js"; @@ -39,7 +39,9 @@ let createDeferredTurnMaintenanceAbortSignal: typeof import("./context-engine-ma let resetDeferredTurnMaintenanceStateForTest: typeof import("./context-engine-maintenance.test-support.js").resetDeferredTurnMaintenanceStateForTest; let waitForDeferredTurnMaintenanceForSession: typeof import("./context-engine-maintenance.js").waitForDeferredTurnMaintenanceForSession; -function createQueuedTaskRun(params: Parameters[0]): TaskRecord { +function createQueuedTaskRunCore( + params: Parameters[0], +): TaskRecord { // Task creation can legally return null for invalid inputs; tests here always // need a concrete queued task record. const task = createQueuedTaskRunOrNull(params); @@ -997,7 +999,7 @@ describe("runContextEngineMaintenance", () => { resetTaskFlowRegistryForTests({ persist: false }); const sessionKey = "agent:main:session-legacy"; - const legacyTask = createQueuedTaskRun({ + const legacyTask = createQueuedTaskRunCore({ runtime: "acp", taskKind: TURN_MAINTENANCE_TASK_KIND, sourceId: TURN_MAINTENANCE_TASK_KIND, diff --git a/src/agents/tools/sessions-send-helpers.ts b/src/agents/tools/sessions-send-helpers.ts index dc88cb43867f..ccc785cf5fcb 100644 --- a/src/agents/tools/sessions-send-helpers.ts +++ b/src/agents/tools/sessions-send-helpers.ts @@ -8,7 +8,7 @@ import { normalizeChannelId as normalizeAnyChannelId, } from "../../channels/plugins/index.js"; import { resolveSessionConversationRef } from "../../channels/plugins/session-conversation.js"; -import { normalizeChannelId as normalizeChatChannelId } from "../../channels/registry.js"; +import { normalizeChatChannelId } from "../../channels/registry.js"; import { parseSessionDeliveryRoute } from "../../sessions/session-key-utils.js"; import { ANNOUNCE_SKIP_TOKEN, REPLY_SKIP_TOKEN } from "./sessions-send-tokens.js"; export { diff --git a/src/auto-reply/reply/agent-runner-utils.ts b/src/auto-reply/reply/agent-runner-utils.ts index 76fbe382cb89..b07b936355f7 100644 --- a/src/auto-reply/reply/agent-runner-utils.ts +++ b/src/auto-reply/reply/agent-runner-utils.ts @@ -7,7 +7,7 @@ import { resolveFastModeState } from "../../agents/fast-mode.js"; import { normalizeChatType } from "../../channels/chat-type.js"; import { getChannelPlugin } from "../../channels/plugins/index.js"; import type { ChannelId } from "../../channels/plugins/types.public.js"; -import { normalizeAnyChannelId, normalizeChannelId } from "../../channels/registry.js"; +import { normalizeAnyChannelId, normalizeChatChannelId } from "../../channels/registry.js"; import type { InternalChannelThreadingToolContext } from "../../channels/threading-tool-context-internal.js"; import { resolveCommandSecretRefsViaGateway } from "../../cli/command-secret-gateway.js"; import { @@ -144,7 +144,7 @@ export function buildThreadingToolContext(params: { currentSourceTurnId, }; } - const provider = normalizeChannelId(rawProvider) ?? normalizeAnyChannelId(rawProvider); + const provider = normalizeChatChannelId(rawProvider) ?? normalizeAnyChannelId(rawProvider); // Fallback for unrecognized/plugin channels (e.g., iMessage before plugin registry init) const threading = provider ? getChannelPlugin(provider)?.threading : undefined; if (!threading?.buildToolContext) { diff --git a/src/auto-reply/reply/commands-acp.test.ts b/src/auto-reply/reply/commands-acp.test.ts index 4fe5d340c12f..c4d4c3e7d14b 100644 --- a/src/auto-reply/reply/commands-acp.test.ts +++ b/src/auto-reply/reply/commands-acp.test.ts @@ -162,7 +162,7 @@ const { testing: acpResetTargetTesting } = await import("./acp-reset-target.test const { createTaskRecord } = await import("../../tasks/task-registry.js"); const { resetTaskRegistryForTests } = await import("../../tasks/task-runtime.test-helpers.js"); const { configureTaskRegistryRuntime } = await import("../../tasks/task-registry.store.js"); -const { failTaskRunByRunId } = await import("../../tasks/task-executor.js"); +const { failTaskRunByRunIdCore } = await import("../../tasks/task-executor.js"); function configureInMemoryTaskRegistryStoreForTests(): void { configureTaskRegistryRuntime({ @@ -2126,7 +2126,7 @@ describe("/acp command", () => { task: "Inspect ACP backlog", status: "running", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "acp-run-1", endedAt: Date.now(), error: [ diff --git a/src/auto-reply/reply/commands-acp.ts b/src/auto-reply/reply/commands-acp.ts index 8ad92d4c3afc..c044d18cd49c 100644 --- a/src/auto-reply/reply/commands-acp.ts +++ b/src/auto-reply/reply/commands-acp.ts @@ -1,13 +1,12 @@ // Implements ACP session commands and runtime status formatting. import { logVerbose } from "../../globals.js"; import { createLazyImportLoader } from "../../shared/lazy-promise.js"; -import { rejectNonOwnerCommand, requireGatewayClientScope } from "./command-gates.js"; +import { commandReply, rejectNonOwnerCommand, requireGatewayClientScope } from "./command-gates.js"; import { COMMAND, type AcpAction, resolveAcpAction, resolveAcpHelpText, - stopWithText, } from "./commands-acp/shared.js"; import type { CommandHandler, @@ -101,7 +100,7 @@ export const handleAcpCommand: CommandHandler = async (params, _allowTextCommand const tokens = rest.split(/\s+/).filter(Boolean); const action = resolveAcpAction(tokens); if (action === "help") { - return stopWithText(resolveAcpHelpText()); + return commandReply(resolveAcpHelpText()); } if (ACP_OWNER_REQUIRED_ACTIONS.has(action)) { diff --git a/src/auto-reply/reply/commands-acp/diagnostics.ts b/src/auto-reply/reply/commands-acp/diagnostics.ts index 7a076f3f8a55..81e6dbc2d929 100644 --- a/src/auto-reply/reply/commands-acp/diagnostics.ts +++ b/src/auto-reply/reply/commands-acp/diagnostics.ts @@ -10,6 +10,7 @@ import { listAcpSessionEntries, readAcpSessionEntry } from "../../../acp/runtime import type { SessionEntry } from "../../../config/sessions/types.js"; import type { SessionAcpMeta } from "../../../config/sessions/types.js"; import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js"; import { resolveAcpCommandBindingContext } from "./context.js"; import { resolveAcpInstallCommandHint } from "./install-hints.js"; @@ -18,7 +19,6 @@ import { ACP_INSTALL_USAGE, ACP_SESSIONS_USAGE, formatAcpCapabilitiesText, - stopWithText, } from "./shared.js"; import { resolveBoundAcpThreadSessionKey } from "./targets.js"; @@ -44,7 +44,7 @@ export async function handleAcpDoctorAction( restTokens: string[], ): Promise { if (restTokens.length > 0) { - return stopWithText(`⚠️ ${ACP_DOCTOR_USAGE}`); + return commandReply(`⚠️ ${ACP_DOCTOR_USAGE}`); } const backendId = normalizeOptionalString(params.cfg.acp?.backend) ?? "acpx"; @@ -117,7 +117,7 @@ export async function handleAcpDoctorAction( if ((capabilities.configOptionKeys?.length ?? 0) > 0) { lines.push(`configKeys: ${capabilities.configOptionKeys?.join(", ")}`); } - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } catch (error) { const acpError = toAcpRuntimeError({ error, @@ -134,7 +134,7 @@ export async function handleAcpDoctorAction( if (normalizeLowercaseStringOrEmpty(backendId) === "acpx") { lines.push("next: verify acpx is installed (`acpx --help`)."); } - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } } @@ -143,7 +143,7 @@ export function handleAcpInstallAction( restTokens: string[], ): CommandHandlerResult { if (restTokens.length > 0) { - return stopWithText(`⚠️ ${ACP_INSTALL_USAGE}`); + return commandReply(`⚠️ ${ACP_INSTALL_USAGE}`); } const backendId = normalizeOptionalString(params.cfg.acp?.backend) ?? "acpx"; const installHint = resolveAcpInstallCommandHint(params.cfg); @@ -155,7 +155,7 @@ export function handleAcpInstallAction( `then: openclaw config set plugins.entries.${backendId}.enabled true`, "then: /acp doctor", ]; - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } function formatAcpSessionLine(params: { @@ -177,12 +177,12 @@ export async function handleAcpSessionsAction( restTokens: string[], ): Promise { if (restTokens.length > 0) { - return stopWithText(ACP_SESSIONS_USAGE); + return commandReply(ACP_SESSIONS_USAGE); } const currentSessionKey = resolveBoundAcpThreadSessionKey(params) || params.sessionKey; if (!currentSessionKey) { - return stopWithText("⚠️ Missing session key."); + return commandReply("⚠️ Missing session key."); } const bindingContext = resolveAcpCommandBindingContext(params); @@ -223,8 +223,8 @@ export async function handleAcpSessionsAction( .filter(Boolean); if (rows.length === 0) { - return stopWithText("ACP sessions:\n-----\n(none)"); + return commandReply("ACP sessions:\n-----\n(none)"); } - return stopWithText(["ACP sessions:", "-----", ...rows].join("\n")); + return commandReply(["ACP sessions:", "-----", ...rows].join("\n")); } diff --git a/src/auto-reply/reply/commands-acp/lifecycle.ts b/src/auto-reply/reply/commands-acp/lifecycle.ts index 1a8399861178..f693020cbb49 100644 --- a/src/auto-reply/reply/commands-acp/lifecycle.ts +++ b/src/auto-reply/reply/commands-acp/lifecycle.ts @@ -28,6 +28,7 @@ import { getSessionBindingService, type SessionBindingRecord, } from "../../../infra/outbound/session-binding-service.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js"; import { resolveAcpBindingLabelNoun, @@ -42,7 +43,6 @@ import { parseSpawnInput, parseSteerInput, resolveCommandRequestId, - stopWithText, withAcpCommandErrorBoundary, } from "./shared.js"; import { resolveAcpTargetSessionKey } from "./targets.js"; @@ -107,12 +107,12 @@ export async function handleAcpSpawnAction( restTokens: string[], ): Promise { if (!isAcpEnabledByPolicy(params.cfg)) { - return stopWithText("ACP is disabled by policy (`acp.enabled=false`)."); + return commandReply("ACP is disabled by policy (`acp.enabled=false`)."); } const parsed = parseSpawnInput(params, restTokens); if (!parsed.ok) { - return stopWithText(`⚠️ ${parsed.error}`); + return commandReply(`⚠️ ${parsed.error}`); } const spawn = parsed.value; @@ -121,11 +121,11 @@ export async function handleAcpSpawnAction( requesterSessionKey: params.sessionKey, }); if (runtimePolicyError) { - return stopWithText(`⚠️ ${runtimePolicyError}`); + return commandReply(`⚠️ ${runtimePolicyError}`); } const agentPolicyError = resolveAcpAgentPolicyError(params.cfg, spawn.agentId); if (agentPolicyError) { - return stopWithText( + return commandReply( collectAcpErrorText({ error: agentPolicyError, fallbackCode: "ACP_SESSION_INIT_FAILED", @@ -149,7 +149,7 @@ export async function handleAcpSpawnAction( explicitCwd: spawn.cwd, }); } catch (error) { - return stopWithText( + return commandReply( collectAcpErrorText({ error, fallbackCode: "ACP_SESSION_INIT_FAILED", @@ -176,7 +176,7 @@ export async function handleAcpSpawnAction( initializedBackend = initialized.handle.backend || initialized.meta.backend; initializedMeta = initialized.meta; } catch (err) { - return stopWithText( + return commandReply( collectAcpErrorText({ error: err, fallbackCode: "ACP_SESSION_INIT_FAILED", @@ -202,7 +202,7 @@ export async function handleAcpSpawnAction( shouldDeleteSession: true, initializedRuntime, }); - return stopWithText(`⚠️ ${bound.error}`); + return commandReply(`⚠️ ${bound.error}`); } binding = bound.binding; } else if (spawn.thread !== "off") { @@ -221,7 +221,7 @@ export async function handleAcpSpawnAction( shouldDeleteSession: true, initializedRuntime, }); - return stopWithText(`⚠️ ${bound.error}`); + return commandReply(`⚠️ ${bound.error}`); } binding = bound.binding; } @@ -240,7 +240,7 @@ export async function handleAcpSpawnAction( initializedRuntime, }); const message = formatErrorMessage(err); - return stopWithText(`⚠️ ACP spawn failed: ${message}`); + return commandReply(`⚠️ ACP spawn failed: ${message}`); } const parts = [ @@ -286,7 +286,7 @@ export async function handleAcpSpawnAction( parts.push(`ℹ️ ${dispatchNote}`); } - return stopWithText(parts.join(" ")); + return commandReply(parts.join(" ")); } function resolveAcpSessionForCommandOrStop(params: { @@ -300,7 +300,7 @@ function resolveAcpSessionForCommandOrStop(params: { }); const error = resolveAcpSessionResolutionError(resolved); if (error) { - return stopWithText( + return commandReply( collectAcpErrorText({ error, fallbackCode: "ACP_SESSION_INIT_FAILED", @@ -321,7 +321,7 @@ async function resolveAcpTokenTargetSessionKeyOrStop(params: { token, }); if (!target.ok) { - return stopWithText(`⚠️ ${target.error}`); + return commandReply(`⚠️ ${target.error}`); } return target.sessionKey; } @@ -373,7 +373,7 @@ export async function handleAcpCancelAction( }), fallbackCode: "ACP_TURN_FAILED", fallbackMessage: "ACP cancel failed before completion.", - onSuccess: () => stopWithText(`✅ Cancel requested for ACP session ${sessionKey}.`), + onSuccess: () => commandReply(`✅ Cancel requested for ACP session ${sessionKey}.`), }), }); } @@ -418,7 +418,7 @@ export async function handleAcpSteerAction( ): Promise { const dispatchPolicyError = resolveAcpDispatchPolicyError(params.cfg); if (dispatchPolicyError) { - return stopWithText( + return commandReply( collectAcpErrorText({ error: dispatchPolicyError, fallbackCode: "ACP_DISPATCH_DISABLED", @@ -429,7 +429,7 @@ export async function handleAcpSteerAction( const parsed = parseSteerInput(restTokens); if (!parsed.ok) { - return stopWithText(`⚠️ ${parsed.error}`); + return commandReply(`⚠️ ${parsed.error}`); } const acpManager = getAcpSessionManager(); @@ -438,7 +438,7 @@ export async function handleAcpSteerAction( token: parsed.value.sessionToken, }); if (!target.ok) { - return stopWithText(`⚠️ ${target.error}`); + return commandReply(`⚠️ ${target.error}`); } const guardFailure = resolveAcpSessionForCommandOrStop({ @@ -462,9 +462,9 @@ export async function handleAcpSteerAction( fallbackMessage: "ACP steer failed before completion.", onSuccess: (steerOutput) => { if (!steerOutput) { - return stopWithText(`✅ ACP steer sent to ${target.sessionKey}.`); + return commandReply(`✅ ACP steer sent to ${target.sessionKey}.`); } - return stopWithText(`✅ ACP steer sent to ${target.sessionKey}.\n${steerOutput}`); + return commandReply(`✅ ACP steer sent to ${target.sessionKey}.\n${steerOutput}`); }, }); } @@ -488,7 +488,7 @@ export async function handleAcpCloseAction( }); runtimeNotice = closed.runtimeNotice ? ` (${closed.runtimeNotice})` : ""; } catch (error) { - return stopWithText( + return commandReply( collectAcpErrorText({ error, fallbackCode: "ACP_TURN_FAILED", @@ -502,7 +502,7 @@ export async function handleAcpCloseAction( reason: "manual", }); - return stopWithText( + return commandReply( `✅ Closed ACP session ${sessionKey}${runtimeNotice}. Removed ${removedBindings.length} binding${removedBindings.length === 1 ? "" : "s"}.`, ); }, diff --git a/src/auto-reply/reply/commands-acp/runtime-options.ts b/src/auto-reply/reply/commands-acp/runtime-options.ts index 66dde41a7b77..a1d94955a701 100644 --- a/src/auto-reply/reply/commands-acp/runtime-options.ts +++ b/src/auto-reply/reply/commands-acp/runtime-options.ts @@ -14,6 +14,7 @@ import { import type { AcpSessionRuntimeOptions } from "../../../config/sessions/types.js"; import { findLatestTaskForRelatedSessionKeyForOwner } from "../../../tasks/task-owner-access.js"; import { sanitizeTaskStatusText } from "../../../tasks/task-status.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js"; import { ACP_CWD_USAGE, @@ -28,7 +29,6 @@ import { parseOptionalSingleTarget, parseSetCommandInput, parseSingleValueCommandInput, - stopWithText, withAcpCommandErrorBoundary, } from "./shared.js"; import { resolveAcpTargetSessionKey } from "./targets.js"; @@ -42,7 +42,7 @@ async function resolveTargetSessionKeyOrStop(params: { token: params.token, }); if (!target.ok) { - return stopWithText(`⚠️ ${target.error}`); + return commandReply(`⚠️ ${target.error}`); } return target.sessionKey; } @@ -54,7 +54,7 @@ async function resolveOptionalSingleTargetOrStop(params: { }): Promise { const parsed = parseOptionalSingleTarget(params.restTokens, params.usage); if (!parsed.ok) { - return stopWithText(`⚠️ ${parsed.error}`); + return commandReply(`⚠️ ${parsed.error}`); } return await resolveTargetSessionKeyOrStop({ commandParams: params.commandParams, @@ -74,7 +74,7 @@ async function resolveSingleTargetValueOrStop(params: { }): Promise { const parsed = parseSingleValueCommandInput(params.restTokens, params.usage); if (!parsed.ok) { - return stopWithText(`⚠️ ${parsed.error}`); + return commandReply(`⚠️ ${parsed.error}`); } const targetSessionKey = await resolveTargetSessionKeyOrStop({ commandParams: params.commandParams, @@ -132,7 +132,7 @@ async function handleSingleRuntimeOptionAction( fallbackMessage: `Could not update ACP ${action.optionLabel}.`, onSuccess: ({ parsedValue, options }) => { const valueText = action.formatValue?.(parsedValue) ?? String(parsedValue); - return stopWithText( + return commandReply( `✅ Updated ACP ${action.optionLabel} for ${targetSessionKey}: ${valueText}. Effective options: ${formatRuntimeOptionsText(options)}`, ); }, @@ -214,7 +214,7 @@ export async function handleAcpStatusAction( ...(runtimeSummary ? [`runtime: ${runtimeSummary}`] : []), ...(runtimeDetails ? [`runtimeDetails: ${runtimeDetails}`] : []), ]; - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); }, }); } @@ -244,7 +244,7 @@ export async function handleAcpSetModeAction( fallbackCode: "ACP_TURN_FAILED", fallbackMessage: "Could not update ACP runtime mode.", onSuccess: ({ runtimeMode, options }) => - stopWithText( + commandReply( `✅ Updated ACP runtime mode for ${targetSessionKey}: ${runtimeMode}. Effective options: ${formatRuntimeOptionsText(options)}`, ), }), @@ -257,14 +257,14 @@ export async function handleAcpSetAction( ): Promise { const parsed = parseSetCommandInput(restTokens); if (!parsed.ok) { - return stopWithText(`⚠️ ${parsed.error}`); + return commandReply(`⚠️ ${parsed.error}`); } const target = await resolveAcpTargetSessionKey({ commandParams: params, token: parsed.value.sessionToken, }); if (!target.ok) { - return stopWithText(`⚠️ ${target.error}`); + return commandReply(`⚠️ ${target.error}`); } const key = parsed.value.key.trim(); const value = parsed.value.value.trim(); @@ -296,7 +296,7 @@ export async function handleAcpSetAction( }, fallbackCode: "ACP_TURN_FAILED", fallbackMessage: "Could not update ACP config option.", - onSuccess: ({ text }) => stopWithText(text), + onSuccess: ({ text }) => commandReply(text), }); } @@ -393,6 +393,6 @@ export async function handleAcpResetOptionsAction( }), fallbackCode: "ACP_TURN_FAILED", fallbackMessage: "Could not reset ACP runtime options.", - onSuccess: () => stopWithText(`✅ Reset ACP runtime options for ${targetSessionKey}.`), + onSuccess: () => commandReply(`✅ Reset ACP runtime options for ${targetSessionKey}.`), }); } diff --git a/src/auto-reply/reply/commands-acp/shared.ts b/src/auto-reply/reply/commands-acp/shared.ts index 8773105b7af4..4c6567773130 100644 --- a/src/auto-reply/reply/commands-acp/shared.ts +++ b/src/auto-reply/reply/commands-acp/shared.ts @@ -10,6 +10,7 @@ import { type AcpRuntimeError, toAcpRuntimeErrorText } from "../../../acp/runtim import { supportsAutomaticThreadBindingSpawn } from "../../../channels/thread-bindings-policy.js"; import type { AcpSessionRuntimeOptions } from "../../../config/sessions/types.js"; import { normalizeAgentId } from "../../../routing/session-key.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js"; import { resolveAcpCommandChannel, resolveAcpCommandThreadId } from "./context.js"; @@ -84,13 +85,6 @@ type ParsedSetCommandInput = { const ACP_UNICODE_DASH_PREFIX_RE = /^[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]+/; -export function stopWithText(text: string): CommandHandlerResult { - return { - shouldContinue: false, - reply: { text }, - }; -} - export function resolveAcpAction(tokens: string[]): AcpAction { const action = normalizeOptionalLowercaseString(tokens[0]); if ( @@ -524,7 +518,7 @@ export async function withAcpCommandErrorBoundary(params: { const result = await params.run(); return params.onSuccess(result); } catch (error) { - return stopWithText( + return commandReply( collectAcpErrorText({ error, fallbackCode: params.fallbackCode, diff --git a/src/auto-reply/reply/commands-allowlist.ts b/src/auto-reply/reply/commands-allowlist.ts index 27f38ac1cbd4..3d7f877beb43 100644 --- a/src/auto-reply/reply/commands-allowlist.ts +++ b/src/auto-reply/reply/commands-allowlist.ts @@ -8,7 +8,7 @@ import { normalizeStringEntries } from "@openclaw/normalization-core/string-norm import { resolveExplicitConfigWriteTarget } from "../../channels/plugins/config-writes.js"; import { getChannelPlugin } from "../../channels/plugins/index.js"; import type { ChannelId } from "../../channels/plugins/types.public.js"; -import { normalizeChannelId } from "../../channels/registry.js"; +import { normalizeChatChannelId } from "../../channels/registry.js"; import { readConfigFileSnapshot } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { @@ -284,9 +284,9 @@ export const handleAllowlistCommand: CommandHandler = async (params, allowTextCo } const channelId = - normalizeChannelId(parsed.channel) ?? + normalizeChatChannelId(parsed.channel) ?? params.command.channelId ?? - normalizeChannelId(params.command.channel); + normalizeChatChannelId(params.command.channel); if (!channelId) { return commandReply("⚠️ Unknown channel. Add channel= to the command."); } @@ -302,7 +302,7 @@ export const handleAllowlistCommand: CommandHandler = async (params, allowTextCo ctxAccountId: params.ctx.AccountId, }); const originChannelId = - params.command.channelId ?? normalizeChannelId(resolveCommandSurfaceChannel(params)); + params.command.channelId ?? normalizeChatChannelId(resolveCommandSurfaceChannel(params)); const originAccountId = resolveChannelAccountId({ cfg: params.cfg, ctx: params.ctx, diff --git a/src/auto-reply/reply/commands-config.ts b/src/auto-reply/reply/commands-config.ts index f24634765d05..43f2420fed51 100644 --- a/src/auto-reply/reply/commands-config.ts +++ b/src/auto-reply/reply/commands-config.ts @@ -1,7 +1,7 @@ // Implements config inspection and mutation commands for reply sessions. import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { resolveConfigWriteTargetFromPath } from "../../channels/plugins/config-writes.js"; -import { normalizeChannelId } from "../../channels/registry.js"; +import { normalizeChatChannelId } from "../../channels/registry.js"; import { getConfigValueAtPath, parseConfigPath, @@ -82,7 +82,7 @@ export const handleConfigCommand: CommandHandler = defineAuthorizedTextCommand( return commandReply(`⚠️ ${parsedPath.error}`); } parsedWritePath = parsedPath.path; - const channelId = params.command.channelId ?? normalizeChannelId(params.command.channel); + const channelId = params.command.channelId ?? normalizeChatChannelId(params.command.channel); const deniedText = resolveConfigWriteDeniedText({ cfg: params.cfg, channel: params.command.channel, diff --git a/src/auto-reply/reply/commands-status.test.ts b/src/auto-reply/reply/commands-status.test.ts index 49aa70ecb599..5823b59f7f1a 100644 --- a/src/auto-reply/reply/commands-status.test.ts +++ b/src/auto-reply/reply/commands-status.test.ts @@ -21,10 +21,10 @@ import { import type { ModelDefinitionConfig } from "../../config/types.models.js"; import type { ProviderThinkingProfile } from "../../plugins/provider-thinking.types.js"; import { - completeTaskRunByRunId, - createQueuedTaskRun, - createRunningTaskRun, - failTaskRunByRunId, + completeTaskRunByRunIdCore, + createQueuedTaskRunCore, + createRunningTaskRunCore, + failTaskRunByRunIdCore, } from "../../tasks/task-executor.js"; import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js"; import { withEnvAsync } from "../../test-utils/env.js"; @@ -444,7 +444,7 @@ describe("buildStatusReply subagent summary", () => { }); it("includes active and total task counts for the current session", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-running", @@ -452,7 +452,7 @@ describe("buildStatusReply subagent summary", () => { task: "active background task", progressSummary: "still working", }); - createQueuedTaskRun({ + createQueuedTaskRunCore({ runtime: "cron", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-queued", @@ -467,7 +467,7 @@ describe("buildStatusReply subagent summary", () => { }); it("hides stale completed task rows from the session task line", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-live", @@ -475,14 +475,14 @@ describe("buildStatusReply subagent summary", () => { task: "live background task", progressSummary: "still working", }); - createQueuedTaskRun({ + createQueuedTaskRunCore({ runtime: "cron", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-stale-done", runId: "run-status-task-stale-done", task: "stale completed task", }); - completeTaskRunByRunId({ + completeTaskRunByRunIdCore({ runId: "run-status-task-stale-done", endedAt: Date.now() - 10 * 60_000, terminalSummary: "done a while ago", @@ -497,14 +497,14 @@ describe("buildStatusReply subagent summary", () => { }); it("shows a recent failure when no active tasks remain", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "acp", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:acp:status-task-failed", runId: "run-status-task-failed", task: "failed background task", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "run-status-task-failed", endedAt: Date.now(), error: "approval denied", @@ -518,14 +518,14 @@ describe("buildStatusReply subagent summary", () => { }); it("does not leak internal runtime context through the task status line", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-leak", runId: "run-status-task-leak", task: "leaked context task", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "run-status-task-leak", endedAt: Date.now(), error: [ @@ -546,7 +546,7 @@ describe("buildStatusReply subagent summary", () => { }); it("truncates long task titles and details in the session task line", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-truncated", @@ -569,26 +569,26 @@ describe("buildStatusReply subagent summary", () => { }); it("prefers failure context over newer success context when showing recent failures", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "acp", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:acp:status-task-failed-priority", runId: "run-status-task-failed-priority", task: "failed background task", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "run-status-task-failed-priority", endedAt: Date.now() - 30_000, error: "approval denied", }); - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:status-task-succeeded-later", runId: "run-status-task-succeeded-later", task: "later successful task", }); - completeTaskRunByRunId({ + completeTaskRunByRunIdCore({ runId: "run-status-task-succeeded-later", endedAt: Date.now(), terminalSummary: "all done", @@ -604,7 +604,7 @@ describe("buildStatusReply subagent summary", () => { }); it("falls back to same-agent task counts without details when the current session has none", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:other", childSessionKey: "agent:main:subagent:status-agent-fallback-running", @@ -613,7 +613,7 @@ describe("buildStatusReply subagent summary", () => { task: "hidden task title", progressSummary: "hidden progress detail", }); - createQueuedTaskRun({ + createQueuedTaskRunCore({ runtime: "cron", requesterSessionKey: "agent:main:another", childSessionKey: "agent:main:subagent:status-agent-fallback-queued", diff --git a/src/auto-reply/reply/commands-subagents-dispatch.ts b/src/auto-reply/reply/commands-subagents-dispatch.ts index 7a27f149f334..064a26eb8ea0 100644 --- a/src/auto-reply/reply/commands-subagents-dispatch.ts +++ b/src/auto-reply/reply/commands-subagents-dispatch.ts @@ -6,7 +6,6 @@ export { resolveHandledPrefix, resolveRequesterSessionKey, resolveSubagentsAction, - stopWithText, } from "./commands-subagents/shared.js"; export type SubagentsCommandContext = { diff --git a/src/auto-reply/reply/commands-subagents-routing.test.ts b/src/auto-reply/reply/commands-subagents-routing.test.ts index 64a55f515b31..0f44ea7d73e1 100644 --- a/src/auto-reply/reply/commands-subagents-routing.test.ts +++ b/src/auto-reply/reply/commands-subagents-routing.test.ts @@ -13,7 +13,6 @@ import { resolveHandledPrefix, resolveRequesterSessionKey, resolveSubagentsAction, - stopWithText, } from "./commands-subagents-dispatch.js"; import { handleSubagentsCommand } from "./commands-subagents.js"; import type { HandleCommandsParams } from "./commands-types.js"; @@ -165,13 +164,6 @@ describe("subagents command dispatch", () => { expect(restTokens).toEqual(["foo"]); }); - it("builds stop replies", () => { - expect(stopWithText("hello")).toEqual({ - shouldContinue: false, - reply: { text: "hello" }, - }); - }); - it("rejects native subagents commands from non-owner senders when the plugin enforces owner-only commands", async () => { registerOwnerEnforcingTelegramPlugin(); const cfg = { diff --git a/src/auto-reply/reply/commands-subagents.test.ts b/src/auto-reply/reply/commands-subagents.test.ts index 03f8180739f5..978346e5ef89 100644 --- a/src/auto-reply/reply/commands-subagents.test.ts +++ b/src/auto-reply/reply/commands-subagents.test.ts @@ -20,7 +20,7 @@ import { } from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.types.js"; import type { OpenClawConfig } from "../../config/config.js"; -import { failTaskRunByRunId } from "../../tasks/task-executor.js"; +import { failTaskRunByRunIdCore } from "../../tasks/task-executor.js"; import { createTaskRecord } from "../../tasks/task-registry.js"; import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js"; import type { ReplyPayload } from "../types.js"; @@ -371,7 +371,7 @@ describe("subagents info", () => { status: "running", deliveryStatus: "delivered", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId, endedAt: now - 1_000, error: [ diff --git a/src/auto-reply/reply/commands-subagents.ts b/src/auto-reply/reply/commands-subagents.ts index 2aa99fa13d68..c535982a7d42 100644 --- a/src/auto-reply/reply/commands-subagents.ts +++ b/src/auto-reply/reply/commands-subagents.ts @@ -1,11 +1,10 @@ // Implements subagent commands for spawn, focus, routing, and status. import { createLazyImportLoader } from "../../shared/lazy-promise.js"; -import { defineAuthorizedTextCommand } from "./command-gates.js"; +import { commandReply, defineAuthorizedTextCommand } from "./command-gates.js"; import { resolveHandledPrefix, resolveRequesterSessionKey, resolveSubagentsAction, - stopWithText, type SubagentsCommandContext, } from "./commands-subagents-dispatch.js"; import type { CommandHandler } from "./commands-types.js"; @@ -82,7 +81,7 @@ export const handleSubagentsCommand: CommandHandler = defineAuthorizedTextComman const requesterKey = resolveRequesterSessionKey(params); if (!requesterKey) { - return stopWithText("⚠️ Missing session key."); + return commandReply("⚠️ Missing session key."); } const ctx: SubagentsCommandContext = { diff --git a/src/auto-reply/reply/commands-subagents/action-agents.ts b/src/auto-reply/reply/commands-subagents/action-agents.ts index b9c1238a78ef..4fcc445b7ab7 100644 --- a/src/auto-reply/reply/commands-subagents/action-agents.ts +++ b/src/auto-reply/reply/commands-subagents/action-agents.ts @@ -6,9 +6,10 @@ import { getSubagentRunsSnapshotForRead } from "../../../agents/subagents/regist import { getChannelPlugin, normalizeChannelId } from "../../../channels/plugins/index.js"; import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js"; import { resolveChannelAccountId, resolveCommandSurfaceChannel } from "../channel-context.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { formatRunLabel, sortSubagentRuns } from "../subagents-utils.js"; -import { RECENT_WINDOW_MINUTES, type SubagentsCommandContext, stopWithText } from "./shared.js"; +import { RECENT_WINDOW_MINUTES, type SubagentsCommandContext } from "./shared.js"; function formatConversationBindingText(params: { conversationId: string }): string { return `binding:${params.conversationId}`; @@ -124,5 +125,5 @@ export function handleSubagentsAgentsAction(ctx: SubagentsCommandContext): Comma } } - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } diff --git a/src/auto-reply/reply/commands-subagents/action-focus.ts b/src/auto-reply/reply/commands-subagents/action-focus.ts index f8f975cc21b5..d4f0070268e0 100644 --- a/src/auto-reply/reply/commands-subagents/action-focus.ts +++ b/src/auto-reply/reply/commands-subagents/action-focus.ts @@ -20,13 +20,13 @@ import { } from "../../../channels/thread-bindings-policy.js"; import { normalizeConversationRef } from "../../../infra/outbound/session-binding-normalization.js"; import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { resolveConversationBindingContextFromAcpCommand } from "../conversation-binding-input.js"; import { type SubagentsCommandContext, resolveCommandSubagentController, resolveFocusTargetSession, - stopWithText, } from "./shared.js"; type FocusBindingContext = { @@ -74,17 +74,17 @@ export async function handleSubagentsFocusAction( const { params, runs, restTokens } = ctx; const token = restTokens.join(" ").trim(); if (!token) { - return stopWithText("Usage: /focus "); + return commandReply("Usage: /focus "); } const controller = resolveCommandSubagentController(params, ctx.requesterKey); if (controller.controlScope !== "children") { - return stopWithText("⚠️ Leaf subagents cannot control other sessions."); + return commandReply("⚠️ Leaf subagents cannot control other sessions."); } const bindingContext = resolveFocusBindingContext(params); if (!bindingContext) { - return stopWithText("⚠️ /focus must be run inside a bindable conversation."); + return commandReply("⚠️ /focus must be run inside a bindable conversation."); } const bindingService = getSessionBindingService(); @@ -93,7 +93,7 @@ export async function handleSubagentsFocusAction( accountId: bindingContext.accountId, }); if (!capabilities.adapterAvailable || !capabilities.bindSupported) { - return stopWithText("⚠️ Conversation bindings are unavailable for this account."); + return commandReply("⚠️ Conversation bindings are unavailable for this account."); } const focusTarget = await resolveFocusTargetSession({ @@ -102,7 +102,7 @@ export async function handleSubagentsFocusAction( requesterKey: controller.controllerSessionKey, }); if (!focusTarget) { - return stopWithText(`⚠️ Unable to resolve focus target: ${token}`); + return commandReply(`⚠️ Unable to resolve focus target: ${token}`); } if (bindingContext.placement === "child") { @@ -113,7 +113,7 @@ export async function handleSubagentsFocusAction( kind: "subagent", }); if (!spawnPolicy.enabled) { - return stopWithText( + return commandReply( `⚠️ ${formatThreadBindingDisabledError({ channel: spawnPolicy.channel, accountId: spawnPolicy.accountId, @@ -122,7 +122,7 @@ export async function handleSubagentsFocusAction( ); } if (bindingContext.placement === "child" && !spawnPolicy.spawnEnabled) { - return stopWithText( + return commandReply( `⚠️ ${formatThreadBindingSpawnDisabledError({ channel: spawnPolicy.channel, accountId: spawnPolicy.accountId, @@ -145,7 +145,7 @@ export async function handleSubagentsFocusAction( ? existingBinding.metadata.boundBy.trim() : ""; if (existingBinding && boundBy && boundBy !== "system" && senderId && senderId !== boundBy) { - return stopWithText(`⚠️ Only ${boundBy} can refocus this conversation.`); + return commandReply(`⚠️ Only ${boundBy} can refocus this conversation.`); } const label = focusTarget.label || token; @@ -158,7 +158,7 @@ export async function handleSubagentsFocusAction( })?.acp : undefined; if (!capabilities.placements.includes(bindingContext.placement)) { - return stopWithText("⚠️ Conversation bindings are unavailable for this account."); + return commandReply("⚠️ Conversation bindings are unavailable for this account."); } let binding; @@ -206,12 +206,12 @@ export async function handleSubagentsFocusAction( }, }); } catch { - return stopWithText("⚠️ Failed to bind this conversation to the target session."); + return commandReply("⚠️ Failed to bind this conversation to the target session."); } const actionText = bindingContext.placement === "child" ? `created child conversation ${binding.conversation.conversationId} and bound it to ${binding.targetSessionKey}` : `bound this conversation to ${binding.targetSessionKey}`; - return stopWithText(`✅ ${actionText} (${focusTarget.targetKind}).`); + return commandReply(`✅ ${actionText} (${focusTarget.targetKind}).`); } diff --git a/src/auto-reply/reply/commands-subagents/action-help.ts b/src/auto-reply/reply/commands-subagents/action-help.ts index 5255cc4df755..18d640f7fa37 100644 --- a/src/auto-reply/reply/commands-subagents/action-help.ts +++ b/src/auto-reply/reply/commands-subagents/action-help.ts @@ -1,7 +1,8 @@ +import { commandReply } from "../command-gates.js"; // Formats subagent command help text and usage summaries. import type { CommandHandlerResult } from "../commands-types.js"; -import { buildSubagentsHelp, stopWithText } from "./shared.js"; +import { buildSubagentsHelp } from "./shared.js"; export function handleSubagentsHelpAction(): CommandHandlerResult { - return stopWithText(buildSubagentsHelp()); + return commandReply(buildSubagentsHelp()); } diff --git a/src/auto-reply/reply/commands-subagents/action-info.ts b/src/auto-reply/reply/commands-subagents/action-info.ts index 38612ec08521..37f86df766ec 100644 --- a/src/auto-reply/reply/commands-subagents/action-info.ts +++ b/src/auto-reply/reply/commands-subagents/action-info.ts @@ -11,13 +11,10 @@ import { formatTimeAgo } from "../../../infra/format-time/format-relative.ts"; import { parseAgentSessionKey } from "../../../routing/session-key.js"; import { findTaskByRunIdForOwner } from "../../../tasks/task-owner-access.js"; import { sanitizeTaskStatusText } from "../../../tasks/task-status.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { formatRunLabel } from "../subagents-utils.js"; -import { - resolveSubagentEntryForToken, - stopWithText, - type SubagentsCommandContext, -} from "./shared.js"; +import { resolveSubagentEntryForToken, type SubagentsCommandContext } from "./shared.js"; function formatTimestampWithAge(valueMs?: number) { if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) { @@ -48,7 +45,7 @@ export function handleSubagentsInfoAction(ctx: SubagentsCommandContext): Command const { params, requesterKey, runs, restTokens } = ctx; const target = restTokens[0]; if (!target) { - return stopWithText("ℹ️ Usage: /subagents info "); + return commandReply("ℹ️ Usage: /subagents info "); } const targetResolution = resolveSubagentEntryForToken(runs, target); @@ -108,5 +105,5 @@ export function handleSubagentsInfoAction(ctx: SubagentsCommandContext): Command linkedTask ? `Delivery: ${linkedTask.deliveryStatus}` : undefined, ].filter(Boolean); - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } diff --git a/src/auto-reply/reply/commands-subagents/action-list.ts b/src/auto-reply/reply/commands-subagents/action-list.ts index 8644fdadeb9b..40e3b1f942a0 100644 --- a/src/auto-reply/reply/commands-subagents/action-list.ts +++ b/src/auto-reply/reply/commands-subagents/action-list.ts @@ -1,7 +1,8 @@ // Lists subagent runs with focus and status information. import { buildSubagentList } from "../../../agents/subagents/registry/subagent-list.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; -import { type SubagentsCommandContext, RECENT_WINDOW_MINUTES, stopWithText } from "./shared.js"; +import { type SubagentsCommandContext, RECENT_WINDOW_MINUTES } from "./shared.js"; export function handleSubagentsListAction(ctx: SubagentsCommandContext): CommandHandlerResult { const { params, runs } = ctx; @@ -24,5 +25,5 @@ export function handleSubagentsListAction(ctx: SubagentsCommandContext): Command lines.push(list.recent.map((entry) => entry.line).join("\n")); } - return stopWithText(lines.join("\n")); + return commandReply(lines.join("\n")); } diff --git a/src/auto-reply/reply/commands-subagents/action-log.ts b/src/auto-reply/reply/commands-subagents/action-log.ts index 4ecf50e2518c..06517f9fee85 100644 --- a/src/auto-reply/reply/commands-subagents/action-log.ts +++ b/src/auto-reply/reply/commands-subagents/action-log.ts @@ -3,6 +3,7 @@ import { parseStrictNonNegativeInteger } from "@openclaw/normalization-core/numb import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; import { stripToolMessages } from "../../../agents/tools/chat-history-text.js"; import { callGateway } from "../../../gateway/call.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { formatRunLabel } from "../subagents-utils.js"; import { @@ -10,7 +11,6 @@ import { type SubagentsCommandContext, formatLogLines, resolveSubagentEntryForToken, - stopWithText, } from "./shared.js"; export async function handleSubagentsLogAction( @@ -19,7 +19,7 @@ export async function handleSubagentsLogAction( const { runs, restTokens } = ctx; const target = restTokens[0]; if (!target) { - return stopWithText("📜 Usage: /subagents log [limit]"); + return commandReply("📜 Usage: /subagents log [limit]"); } const includeTools = restTokens.some( @@ -45,7 +45,7 @@ export async function handleSubagentsLogAction( const lines = formatLogLines(filtered as ChatMessage[]); const header = `📜 Subagent log: ${formatRunLabel(targetResolution.entry)}`; if (lines.length === 0) { - return stopWithText(`${header}\n(no messages)`); + return commandReply(`${header}\n(no messages)`); } - return stopWithText([header, ...lines].join("\n")); + return commandReply([header, ...lines].join("\n")); } diff --git a/src/auto-reply/reply/commands-subagents/action-unfocus.ts b/src/auto-reply/reply/commands-subagents/action-unfocus.ts index 710e080d6f47..ca21ee038b53 100644 --- a/src/auto-reply/reply/commands-subagents/action-unfocus.ts +++ b/src/auto-reply/reply/commands-subagents/action-unfocus.ts @@ -2,9 +2,10 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { normalizeConversationRef } from "../../../infra/outbound/session-binding-normalization.js"; import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js"; +import { commandReply } from "../command-gates.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { resolveConversationBindingContextFromAcpCommand } from "../conversation-binding-input.js"; -import { type SubagentsCommandContext, stopWithText } from "./shared.js"; +import type { SubagentsCommandContext } from "./shared.js"; export async function handleSubagentsUnfocusAction( ctx: SubagentsCommandContext, @@ -13,7 +14,7 @@ export async function handleSubagentsUnfocusAction( const bindingService = getSessionBindingService(); const bindingContext = resolveConversationBindingContextFromAcpCommand(params); if (!bindingContext) { - return stopWithText("⚠️ /unfocus must be run inside a focused conversation."); + return commandReply("⚠️ /unfocus must be run inside a focused conversation."); } const binding = bindingService.resolveByConversation( @@ -25,18 +26,18 @@ export async function handleSubagentsUnfocusAction( }), ); if (!binding) { - return stopWithText("ℹ️ This conversation is not currently focused."); + return commandReply("ℹ️ This conversation is not currently focused."); } const senderId = normalizeOptionalString(params.command.senderId) ?? ""; const boundBy = normalizeOptionalString(binding.metadata?.boundBy) ?? ""; if (boundBy && boundBy !== "system" && senderId && senderId !== boundBy) { - return stopWithText(`⚠️ Only ${boundBy} can unfocus this conversation.`); + return commandReply(`⚠️ Only ${boundBy} can unfocus this conversation.`); } await bindingService.unbind({ bindingId: binding.bindingId, reason: "manual", }); - return stopWithText("✅ Conversation unfocused."); + return commandReply("✅ Conversation unfocused."); } diff --git a/src/auto-reply/reply/commands-subagents/shared.ts b/src/auto-reply/reply/commands-subagents/shared.ts index 8309acac1e43..5716c06e6272 100644 --- a/src/auto-reply/reply/commands-subagents/shared.ts +++ b/src/auto-reply/reply/commands-subagents/shared.ts @@ -18,6 +18,7 @@ import { parseAgentSessionKey } from "../../../routing/session-key.js"; import { isSubagentSessionKey } from "../../../routing/session-key.js"; import { looksLikeSessionId } from "../../../sessions/session-id.js"; import { isNativeCommandTurn, resolveCommandTurnContext } from "../../command-turn-context.js"; +import { commandReply } from "../command-gates.js"; import { extractMessageText, type ChatMessage } from "../commands-subagents-text.js"; import type { CommandHandler, CommandHandlerResult } from "../commands-types.js"; import { @@ -48,12 +49,8 @@ export type SubagentsCommandContext = { restTokens: string[]; }; -export function stopWithText(text: string): CommandHandlerResult { - return { shouldContinue: false, reply: { text } }; -} - function stopWithUnknownTargetError(error?: string): CommandHandlerResult { - return stopWithText(`⚠️ ${error ?? "Unknown subagent."}`); + return commandReply(`⚠️ ${error ?? "Unknown subagent."}`); } function resolveSubagentTarget( diff --git a/src/auto-reply/reply/commands-tasks.test.ts b/src/auto-reply/reply/commands-tasks.test.ts index ba6e73a6bacc..1ae095e83461 100644 --- a/src/auto-reply/reply/commands-tasks.test.ts +++ b/src/auto-reply/reply/commands-tasks.test.ts @@ -2,10 +2,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { resolveSessionAgentId } from "../../agents/agent-scope.js"; import { - completeTaskRunByRunId, - createQueuedTaskRun, - createRunningTaskRun, - failTaskRunByRunId, + completeTaskRunByRunIdCore, + createQueuedTaskRunCore, + createRunningTaskRunCore, + failTaskRunByRunIdCore, } from "../../tasks/task-executor.js"; import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js"; import { handleTasksCommand } from "./commands-tasks.js"; @@ -55,7 +55,7 @@ describe("handleTasksCommand task board", () => { }); it("lists active and recent tasks for the current session", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:tasks-running", @@ -63,21 +63,21 @@ describe("handleTasksCommand task board", () => { task: "active background task", progressSummary: "still working", }); - createQueuedTaskRun({ + createQueuedTaskRunCore({ runtime: "cron", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:tasks-queued", runId: "run-tasks-queued", task: "queued background task", }); - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "acp", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:acp:tasks-failed", runId: "run-tasks-failed", task: "failed background task", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "run-tasks-failed", endedAt: Date.now(), error: "approval denied", @@ -94,7 +94,7 @@ describe("handleTasksCommand task board", () => { }); it("lists session-backed video generation tasks for the current session", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "cli", taskKind: "video_generation", sourceId: "video_generate:openai", @@ -117,7 +117,7 @@ describe("handleTasksCommand task board", () => { }); it("lists session-backed image generation tasks for the current session", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "cli", taskKind: "image_generation", sourceId: "image_generate:openai", @@ -140,7 +140,7 @@ describe("handleTasksCommand task board", () => { }); it("sanitizes leaked internal runtime context from visible task details", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "acp", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:acp:tasks-sanitized-failed", @@ -148,7 +148,7 @@ describe("handleTasksCommand task board", () => { task: "Visible failed task", progressSummary: "still working", }); - failTaskRunByRunId({ + failTaskRunByRunIdCore({ runId: "run-tasks-sanitized-failed", endedAt: Date.now(), error: [ @@ -170,7 +170,7 @@ describe("handleTasksCommand task board", () => { }); it("sanitizes inline internal runtime fences from visible task titles", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "cli", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:main", @@ -182,7 +182,7 @@ describe("handleTasksCommand task board", () => { ].join("\n"), progressSummary: "done", }); - completeTaskRunByRunId({ + completeTaskRunByRunIdCore({ runId: "run-tasks-inline-fence", endedAt: Date.now(), terminalSummary: "Finished.", @@ -198,14 +198,14 @@ describe("handleTasksCommand task board", () => { }); it("hides stale completed tasks from the task board", async () => { - createQueuedTaskRun({ + createQueuedTaskRunCore({ runtime: "cron", requesterSessionKey: "agent:main:main", childSessionKey: "agent:main:subagent:tasks-stale", runId: "run-tasks-stale", task: "stale completed task", }); - completeTaskRunByRunId({ + completeTaskRunByRunIdCore({ runId: "run-tasks-stale", endedAt: Date.now() - 10 * 60_000, terminalSummary: "done a while ago", @@ -219,7 +219,7 @@ describe("handleTasksCommand task board", () => { }); it("falls back to agent-local counts when the current session has no visible tasks", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:main:other-session", childSessionKey: "agent:main:subagent:tasks-agent-fallback", @@ -240,7 +240,7 @@ describe("handleTasksCommand task board", () => { }); it("counts session-backed video generation tasks in agent-local fallback", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "cli", taskKind: "video_generation", sourceId: "video_generate:openai", @@ -265,7 +265,7 @@ describe("handleTasksCommand task board", () => { }); it("uses the canonical target session agent for agent-local fallback counts", async () => { - createRunningTaskRun({ + createRunningTaskRunCore({ runtime: "subagent", requesterSessionKey: "agent:target:other-session", childSessionKey: "agent:target:subagent:tasks-target-fallback", diff --git a/src/auto-reply/reply/dispatch-acp.runtime.ts b/src/auto-reply/reply/dispatch-acp.runtime.ts index 1a8b6488b3ed..fe11ccfa522d 100644 --- a/src/auto-reply/reply/dispatch-acp.runtime.ts +++ b/src/auto-reply/reply/dispatch-acp.runtime.ts @@ -3,7 +3,7 @@ import { createLazyImportLoader } from "../../shared/lazy-promise.js"; type ShouldBypassAcpDispatchForCommand = (typeof import("./dispatch-acp-command-bypass.js"))["shouldBypassAcpDispatchForCommand"]; -type TryDispatchAcpReply = (typeof import("./dispatch-acp.js"))["tryDispatchAcpReply"]; +type TryDispatchAcpReply = (typeof import("./dispatch-acp.js"))["tryDispatchAcpReplyCore"]; const dispatchAcpLoader = createLazyImportLoader(() => import("./dispatch-acp.js")); const dispatchAcpCommandBypassLoader = createLazyImportLoader( @@ -29,5 +29,5 @@ export async function tryDispatchAcpReply( ...args: Parameters ): Promise>> { const mod = await loadDispatchAcp(); - return await mod.tryDispatchAcpReply(...args); + return await mod.tryDispatchAcpReplyCore(...args); } diff --git a/src/auto-reply/reply/dispatch-acp.test.ts b/src/auto-reply/reply/dispatch-acp.test.ts index 11296bd14578..8496f9bf196c 100644 --- a/src/auto-reply/reply/dispatch-acp.test.ts +++ b/src/auto-reply/reply/dispatch-acp.test.ts @@ -17,7 +17,7 @@ import { resolveAgentTurnAttachments, resolveInlineAgentImageAttachments, } from "./agent-turn-attachments.js"; -import { tryDispatchAcpReply } from "./dispatch-acp.js"; +import { tryDispatchAcpReplyCore } from "./dispatch-acp.js"; import { createAbortAwareDispatcher } from "./dispatch-from-config.abort.js"; import { appendRecentHistoryImageContext, @@ -370,7 +370,7 @@ async function runDispatch(params: { markIdle?: (reason: string) => void; }) { const targetSessionKey = params.sessionKeyOverride ?? sessionKey; - return tryDispatchAcpReply({ + return tryDispatchAcpReplyCore({ ctx: buildTestCtx({ Provider: "discord", Surface: "discord", @@ -486,7 +486,7 @@ function expectRoutedPayload(callIndex: number, payload: Partial) } } -describe("tryDispatchAcpReply", () => { +describe("tryDispatchAcpReplyCore", () => { beforeEach(() => { auditMocks.emitAcpLifecycleStart.mockReset(); auditMocks.emitAcpRuntimeEvent.mockReset(); diff --git a/src/auto-reply/reply/dispatch-acp.ts b/src/auto-reply/reply/dispatch-acp.ts index 66bfa0a1b34f..f74d8490f231 100644 --- a/src/auto-reply/reply/dispatch-acp.ts +++ b/src/auto-reply/reply/dispatch-acp.ts @@ -408,7 +408,7 @@ async function finalizeAcpTurnOutput(params: { return queuedFinal; } -export async function tryDispatchAcpReply(params: { +export async function tryDispatchAcpReplyCore(params: { ctx: FinalizedRuntimeMsgContext; cfg: OpenClawConfig; dispatcher: ReplyDispatcher; diff --git a/src/auto-reply/thinking.shared.ts b/src/auto-reply/thinking.shared.ts index 8f26b825bfaf..7544f41dfe3e 100644 --- a/src/auto-reply/thinking.shared.ts +++ b/src/auto-reply/thinking.shared.ts @@ -118,18 +118,15 @@ export function isSessionDefaultDirectiveValue(raw?: string | null): boolean { } /** Chooses the default thinking level for one provider/model catalog entry. */ -export function resolveThinkingDefaultForModel(params: { +export function resolveThinkingDefaultForModelCore(params: { provider: string; model: string; - catalog?: ThinkingCatalogEntry[]; + catalog?: readonly ThinkingCatalogEntry[]; }): ThinkLevel { const candidate = params.catalog?.find( (entry) => entry.provider === params.provider && entry.id === params.model, ); - if (candidate?.reasoning) { - return "low"; - } - return "off"; + return candidate?.reasoning ? "low" : "off"; } type OnOffFullLevel = "off" | "on" | "full"; diff --git a/src/auto-reply/thinking.ts b/src/auto-reply/thinking.ts index cbbf9b6b8ca3..179ffa35e9e6 100644 --- a/src/auto-reply/thinking.ts +++ b/src/auto-reply/thinking.ts @@ -4,7 +4,7 @@ import { resolveClaudeThinkingProfile } from "../plugins/provider-claude-thinkin import { BASE_THINKING_LEVELS, normalizeThinkLevel, - resolveThinkingDefaultForModel as resolveThinkingDefaultForModelFallback, + resolveThinkingDefaultForModelCore, THINKING_LEVEL_RANKS, } from "./thinking.shared.js"; import type { ThinkLevel, ThinkingCatalogEntry } from "./thinking.shared.js"; @@ -311,7 +311,7 @@ export function resolveThinkingDefaultForModel(params: { if (profile.defaultLevel) { return profile.defaultLevel; } - const fallback = resolveThinkingDefaultForModelFallback(params); + const fallback = resolveThinkingDefaultForModelCore(params); if (fallback === "off") { return "off"; } diff --git a/src/channels/account-summary.test.ts b/src/channels/account-summary.test.ts index 9f5d6b1ebcb5..cb010e91b4a3 100644 --- a/src/channels/account-summary.test.ts +++ b/src/channels/account-summary.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { buildChannelAccountSnapshot } from "./account-summary.js"; +import { buildChannelAccountSummary } from "./account-summary.js"; import type { ChannelPlugin } from "./plugins/types.plugin.js"; -describe("buildChannelAccountSnapshot", () => { +describe("buildChannelAccountSummary", () => { it("redacts a raw baseUrl returned by describeAccount without mutating the account", () => { const rawBaseUrl = [ "https://", @@ -25,7 +25,7 @@ describe("buildChannelAccountSnapshot", () => { }, } as unknown as ChannelPlugin; - const snapshot = buildChannelAccountSnapshot({ + const snapshot = buildChannelAccountSummary({ plugin, account, cfg: {} as OpenClawConfig, diff --git a/src/channels/account-summary.ts b/src/channels/account-summary.ts index 8870b4f0e047..e43afdfe8474 100644 --- a/src/channels/account-summary.ts +++ b/src/channels/account-summary.ts @@ -16,7 +16,7 @@ import type { ChannelPlugin } from "./plugins/types.plugin.js"; /** * Builds the safe account snapshot shown by CLI, gateway, and status summaries. */ -export function buildChannelAccountSnapshot(params: { +export function buildChannelAccountSummary(params: { plugin: ChannelPlugin; account: unknown; cfg: OpenClawConfig; diff --git a/src/channels/plugins/session-conversation.ts b/src/channels/plugins/session-conversation.ts index c52d91ae50ab..9cdc7ff2af66 100644 --- a/src/channels/plugins/session-conversation.ts +++ b/src/channels/plugins/session-conversation.ts @@ -16,7 +16,7 @@ import { type ParsedThreadSessionSuffix, type RawSessionConversationRef, } from "../../sessions/session-key-utils.js"; -import { normalizeChannelId as normalizeChatChannelId } from "../registry.js"; +import { normalizeChatChannelId } from "../registry.js"; import { getLoadedChannelPlugin, normalizeChannelId as normalizeAnyChannelId } from "./registry.js"; /** diff --git a/src/channels/plugins/status.ts b/src/channels/plugins/status.ts index 29cca4e46a8b..99edbc7a4518 100644 --- a/src/channels/plugins/status.ts +++ b/src/channels/plugins/status.ts @@ -96,7 +96,7 @@ export async function buildReadOnlySourceChannelAccountSnapshot }); } -export async function buildChannelAccountSnapshot(params: { +export async function resolveChannelAccountSnapshot(params: { plugin: ChannelPlugin; cfg: OpenClawConfig; accountId: string; diff --git a/src/channels/registry.ts b/src/channels/registry.ts index 486daa89a7f0..250a0bcb9ec5 100644 --- a/src/channels/registry.ts +++ b/src/channels/registry.ts @@ -1,6 +1,6 @@ // Public channel registry facade for channel ids, metadata, and setup copy. import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { normalizeChatChannelId, type ChatChannelId } from "./ids.js"; +import { normalizeChatChannelId } from "./ids.js"; import type { ChannelId } from "./plugins/channel-id.types.js"; import type { ChannelMeta } from "./plugins/types.core.js"; import { @@ -13,13 +13,6 @@ export type { ChatChannelId } from "./ids.js"; export { normalizeAnyChannelId } from "./registry-normalize.js"; export { normalizeChatChannelId }; -/** - * Normalizes built-in chat channel ids without loading channel plugin implementations. - */ -export function normalizeChannelId(raw?: string | null): ChatChannelId | null { - return normalizeChatChannelId(raw); -} - /** * Lists registered channel plugin ids without importing their runtime implementations. */ diff --git a/src/cli/completion-cli.ts b/src/cli/completion-cli.ts index 91b8e898b90c..d1319765226b 100644 --- a/src/cli/completion-cli.ts +++ b/src/cli/completion-cli.ts @@ -25,7 +25,7 @@ import { import { publishOutputFileAtomically } from "./output-file.runtime.js"; import { getCoreCliCommandNames, registerCoreCliByName } from "./program/command-registry-core.js"; import { getProgramContext } from "./program/program-context.js"; -import { getSubCliEntries, registerSubCliByName } from "./program/register.subclis-core.js"; +import { getSubCliEntries, registerSubCliByNameCore } from "./program/register.subclis-core.js"; import { quoteCliArg } from "./quote-cli-arg.js"; export function getCompletionScript(shell: CompletionShell, program: Command): string { @@ -164,7 +164,7 @@ async function registerSubcommandsForCompletion(program: Command): Promise continue; } try { - await registerSubCliByName(program, entry.name, process.argv, { purpose: "completion" }); + await registerSubCliByNameCore(program, entry.name, process.argv, { purpose: "completion" }); } catch (error) { writeCompletionRegistrationWarning( `skipping subcommand \`${entry.name}\` while building completion cache: ${error instanceof Error ? error.message : String(error)}`, diff --git a/src/cli/completion-cli.write-state.test.ts b/src/cli/completion-cli.write-state.test.ts index d3c4230463d4..556af60f176b 100644 --- a/src/cli/completion-cli.write-state.test.ts +++ b/src/cli/completion-cli.write-state.test.ts @@ -63,7 +63,7 @@ vi.mock("./program/program-context.js", () => ({ vi.mock("./program/register.subclis-core.js", () => ({ getSubCliEntries: getSubCliEntriesMock, - registerSubCliByName: registerSubCliByNameMock, + registerSubCliByNameCore: registerSubCliByNameMock, })); vi.mock("../plugins/cli.js", () => ({ diff --git a/src/cli/daemon-cli/lifecycle-core.test.ts b/src/cli/daemon-cli/lifecycle-core.test.ts index 931aaaf650df..817d4b7b7f01 100644 --- a/src/cli/daemon-cli/lifecycle-core.test.ts +++ b/src/cli/daemon-cli/lifecycle-core.test.ts @@ -7,7 +7,7 @@ import { defaultRuntime, resetLifecycleRuntimeLogs, resetLifecycleServiceMocks, - runtimeLogs, + lifecycleRuntimeLogs, service, stubEmptyGatewayEnv, } from "./test-helpers/lifecycle-core-harness.js"; @@ -74,7 +74,7 @@ let runServiceStop: typeof import("./lifecycle-core.js").runServiceStop; // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe logged JSON shape. function readJsonLog() { - const jsonLine = runtimeLogs.find((line) => line.trim().startsWith("{")); + const jsonLine = lifecycleRuntimeLogs.find((line) => line.trim().startsWith("{")); return JSON.parse(jsonLine ?? "{}") as T; } @@ -248,8 +248,8 @@ describe("runServiceRestart token drift", () => { opts: { json: false }, }); - expect(runtimeLogs).toContain("Gateway service not loaded."); - expect(runtimeLogs).toContain( + expect(lifecycleRuntimeLogs).toContain("Gateway service not loaded."); + expect(lifecycleRuntimeLogs).toContain( "Start with: Restart the container or the service that manages it for openclaw-demo-container.", ); }); @@ -680,7 +680,7 @@ describe("runServiceRestart token drift", () => { expectedPort: 19_001, }); - const repairWarnings = runtimeLogs.filter((line) => + const repairWarnings = lifecycleRuntimeLogs.filter((line) => line.startsWith( "Gateway service already running, but its installed service definition needs repair:", ), diff --git a/src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts b/src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts index f587f44c94d4..a5f156c301e8 100644 --- a/src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts +++ b/src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts @@ -5,7 +5,7 @@ import type { MockFn } from "../../../test-utils/vitest-mock-fn.js"; import { createCliRuntimeCapture } from "../../test-runtime-capture.js"; const lifecycleRuntimeCapture = createCliRuntimeCapture(); -export const runtimeLogs = lifecycleRuntimeCapture.runtimeLogs; +export const lifecycleRuntimeLogs = lifecycleRuntimeCapture.runtimeLogs; type LifecycleRuntimeHarness = typeof lifecycleRuntimeCapture.defaultRuntime; type LifecycleServiceHarness = GatewayService & { diff --git a/src/cli/deps.ts b/src/cli/deps.ts index d52f3d1c7ee3..cfae3300b591 100644 --- a/src/cli/deps.ts +++ b/src/cli/deps.ts @@ -1,5 +1,5 @@ // Default CLI dependency surface with lazy outbound channel send adapters. -import { normalizeChannelId } from "../channels/registry.js"; +import { normalizeChatChannelId } from "../channels/registry.js"; import { getOrCreatePromise } from "../shared/lazy-promise.js"; import type { CliDeps } from "./deps.types.js"; @@ -45,7 +45,7 @@ const NON_CHANNEL_DEP_KEYS = new Set([ ]); function resolveKnownChannelId(raw: string): string | undefined { - return normalizeChannelId(raw) ?? undefined; + return normalizeChatChannelId(raw) ?? undefined; } // Per-channel module caches for lazy loading. diff --git a/src/cli/plugins-cli-test-helpers.ts b/src/cli/plugins-cli-test-helpers.ts index 3649fc3de6db..bdeed230ff4c 100644 --- a/src/cli/plugins-cli-test-helpers.ts +++ b/src/cli/plugins-cli-test-helpers.ts @@ -141,14 +141,14 @@ export const buildPluginDiagnosticsReport: UnknownMock = vi.fn(); const buildPluginCompatibilityNotices: UnknownMock = vi.fn(); export const inspectPluginRegistry: AsyncUnknownMock = vi.fn(); export const refreshPluginRegistry: AsyncUnknownMock = vi.fn(); -export const notifyGatewayPluginMetadataChanged: AsyncUnknownMock = vi.fn(); +export const notifyGatewayPluginMetadataChangedMock: AsyncUnknownMock = vi.fn(); export const clearPluginRegistryLoadCache: UnknownMock = vi.fn(); export const applyExclusiveSlotSelection: UnknownMock = vi.fn(); export const planPluginUninstall: UnknownMock = vi.fn(); export const applyPluginUninstallDirectoryRemoval: AsyncUnknownMock = vi.fn(); export const updateNpmInstalledPlugins: Mock = vi.fn(); export const updateNpmInstalledHookPacks: Mock = vi.fn(); -export const promptYesNo: AsyncUnknownMock = vi.fn(); +export const promptYesNoMock: AsyncUnknownMock = vi.fn(); const promptText: AsyncUnknownMock = vi.fn(); export class PromptInputClosedError extends Error { constructor() { @@ -168,42 +168,44 @@ export const installHooksFromNpmSpec: AsyncUnknownMock = vi.fn(); export const installHooksFromPath: AsyncUnknownMock = vi.fn(); export const recordHookInstall: UnknownMock = vi.fn(); -const { defaultRuntime, runtimeLogs, runtimeErrors, resetRuntimeCapture } = vi.hoisted(() => { - const runtimeLogsLocal: string[] = []; - const runtimeErrorsLocal: string[] = []; - const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" "); - const normalizeStdout = (value: string) => (value.endsWith("\n") ? value.slice(0, -1) : value); - const stringifyJson = (value: unknown, space = 2) => - JSON.stringify(value, null, space > 0 ? space : undefined); - const defaultRuntimeLocal = { - log: vi.fn((...args: unknown[]) => { - runtimeLogsLocal.push(stringifyArgs(args)); - }), - error: vi.fn((...args: unknown[]) => { - runtimeErrorsLocal.push(stringifyArgs(args)); - }), - writeStdout: vi.fn((value: string) => { - defaultRuntimeLocal.log(normalizeStdout(value)); - }), - writeJson: vi.fn((value: unknown, space = 2) => { - defaultRuntimeLocal.log(stringifyJson(value, space)); - }), - exit: vi.fn((code: number) => { - throw new Error(`__exit__:${code}`); - }), - } as CliMockOutputRuntime; - return { - defaultRuntime: defaultRuntimeLocal, - runtimeLogs: runtimeLogsLocal, - runtimeErrors: runtimeErrorsLocal, - resetRuntimeCapture: () => { - runtimeLogsLocal.length = 0; - runtimeErrorsLocal.length = 0; - }, - }; -}); +const { defaultRuntime, pluginsCliRuntimeLogs, runtimeErrors, resetRuntimeCapture } = vi.hoisted( + () => { + const runtimeLogsLocal: string[] = []; + const runtimeErrorsLocal: string[] = []; + const stringifyArgs = (args: unknown[]) => args.map((value) => String(value)).join(" "); + const normalizeStdout = (value: string) => (value.endsWith("\n") ? value.slice(0, -1) : value); + const stringifyJson = (value: unknown, space = 2) => + JSON.stringify(value, null, space > 0 ? space : undefined); + const defaultRuntimeLocal = { + log: vi.fn((...args: unknown[]) => { + runtimeLogsLocal.push(stringifyArgs(args)); + }), + error: vi.fn((...args: unknown[]) => { + runtimeErrorsLocal.push(stringifyArgs(args)); + }), + writeStdout: vi.fn((value: string) => { + defaultRuntimeLocal.log(normalizeStdout(value)); + }), + writeJson: vi.fn((value: unknown, space = 2) => { + defaultRuntimeLocal.log(stringifyJson(value, space)); + }), + exit: vi.fn((code: number) => { + throw new Error(`__exit__:${code}`); + }), + } as CliMockOutputRuntime; + return { + defaultRuntime: defaultRuntimeLocal, + pluginsCliRuntimeLogs: runtimeLogsLocal, + runtimeErrors: runtimeErrorsLocal, + resetRuntimeCapture: () => { + runtimeLogsLocal.length = 0; + runtimeErrorsLocal.length = 0; + }, + }; + }, +); -export { runtimeErrors, runtimeLogs }; +export { runtimeErrors, pluginsCliRuntimeLogs }; export function setInstalledPluginIndexInstallRecords(records: PluginInstallRecordMap): void { mockInstalledPluginIndexInstallRecords = clonePluginInstallRecords(records); @@ -212,7 +214,7 @@ export function setInstalledPluginIndexInstallRecords(records: PluginInstallReco function restoreRuntimeCaptureMocks() { defaultRuntime.log.mockReset(); defaultRuntime.log.mockImplementation((...args: unknown[]) => { - runtimeLogs.push(args.map((value) => String(value)).join(" ")); + pluginsCliRuntimeLogs.push(args.map((value) => String(value)).join(" ")); }); defaultRuntime.error.mockReset(); @@ -244,7 +246,7 @@ vi.mock("../runtime.js", () => ({ vi.mock("./plugins-update-gateway-signal.js", () => ({ notifyGatewayPluginMetadataChanged: (...args: unknown[]) => - notifyGatewayPluginMetadataChanged(...args), + notifyGatewayPluginMetadataChangedMock(...args), })); vi.mock("../config/config.js", () => ({ @@ -630,7 +632,7 @@ vi.mock("./prompt.js", () => ({ invokeMock< Parameters<(typeof import("./prompt.js"))["promptYesNo"]>, ReturnType<(typeof import("./prompt.js"))["promptYesNo"]> - >(promptYesNo, ...args)) as (typeof import("./prompt.js"))["promptYesNo"], + >(promptYesNoMock, ...args)) as (typeof import("./prompt.js"))["promptYesNo"], })); vi.mock("../plugins/install.js", () => ({ @@ -806,8 +808,6 @@ vi.mock("../infra/clawhub-packages.js", () => ({ const { registerPluginsCli } = await import("./plugins-cli.js"); -export { registerPluginsCli }; - export async function runPluginsCommand(argv: string[]) { const program = new Command(); program.exitOverride(); @@ -844,7 +844,7 @@ export function resetPluginsCliTestState() { buildPluginCompatibilityNotices.mockReset(); inspectPluginRegistry.mockReset(); refreshPluginRegistry.mockReset(); - notifyGatewayPluginMetadataChanged.mockReset(); + notifyGatewayPluginMetadataChangedMock.mockReset(); clearPluginRegistryLoadCache.mockReset(); applyExclusiveSlotSelection.mockReset(); planPluginUninstall.mockReset(); @@ -853,7 +853,7 @@ export function resetPluginsCliTestState() { updateNpmInstalledHookPacks.mockReset(); mockHookInstallRecords = {}; promptText.mockReset(); - promptYesNo.mockReset(); + promptYesNoMock.mockReset(); installPluginFromGitSpec.mockReset(); parseGitPluginSpec.mockReset(); installPluginFromNpmSpec.mockReset(); @@ -976,7 +976,7 @@ export function resetPluginsCliTestState() { current: defaultRegistryIndex, }); refreshPluginRegistry.mockResolvedValue(defaultRegistryIndex); - notifyGatewayPluginMetadataChanged.mockResolvedValue(true); + notifyGatewayPluginMetadataChangedMock.mockResolvedValue(true); applyExclusiveSlotSelection.mockImplementation((({ config }: { config: OpenClawConfig }) => ({ config, warnings: [], @@ -1008,7 +1008,7 @@ export function resetPluginsCliTestState() { changed: false, config: {} as OpenClawConfig, }); - promptYesNo.mockResolvedValue(true); + promptYesNoMock.mockResolvedValue(true); promptText.mockResolvedValue("demo"); installPluginFromPath.mockResolvedValue({ ok: false, error: "path install disabled in test" }); installPluginFromGitSpec.mockResolvedValue({ diff --git a/src/cli/plugins-cli.install.test.ts b/src/cli/plugins-cli.install.test.ts index c71b35d841bb..df768d14b735 100644 --- a/src/cli/plugins-cli.install.test.ts +++ b/src/cli/plugins-cli.install.test.ts @@ -30,7 +30,7 @@ import { readConfigFileSnapshot, readConfigFileSnapshotForWrite, parseClawHubPluginSpec, - promptYesNo, + promptYesNoMock, reportClawHubPluginInstallTelemetry, recordHookInstall, recordPluginInstall, @@ -38,7 +38,7 @@ import { replaceConfigFile, runPluginsCommand, runtimeErrors, - runtimeLogs, + pluginsCliRuntimeLogs, writeConfigFile, writePersistedInstalledPluginIndexInstallRecordsWithLease, } from "./plugins-cli-test-helpers.js"; @@ -456,7 +456,7 @@ function recordHookInstallCall(callIndex = 0): PersistedInstallRecord { } function runtimeLogsContain(fragment: string): boolean { - return runtimeLogs.some((line) => line.includes(fragment)); + return pluginsCliRuntimeLogs.some((line) => line.includes(fragment)); } function setTty(value: boolean): void { @@ -1444,14 +1444,14 @@ describe("plugins cli install", () => { fs.rmSync(localPath, { recursive: true, force: true }); } - expect(promptYesNo).not.toHaveBeenCalled(); + expect(promptYesNoMock).not.toHaveBeenCalled(); expect(runtimeErrors.join("\n")).not.toContain("outside ClawHub review"); expect(installPluginFromPath).toHaveBeenCalledTimes(1); }); it("prompts interactive users before non-ClawHub plugin installs and cancels on no", async () => { setTty(true); - promptYesNo.mockResolvedValueOnce(false); + promptYesNoMock.mockResolvedValueOnce(false); primeSuccessfulPluginPersistence("demo"); installPluginFromNpmSpec.mockResolvedValue(createNpmPluginInstallResult("demo")); @@ -1459,7 +1459,7 @@ describe("plugins cli install", () => { "__exit__:1", ); - expect(promptYesNo).toHaveBeenCalledWith("Install this non-ClawHub plugin source?"); + expect(promptYesNoMock).toHaveBeenCalledWith("Install this non-ClawHub plugin source?"); expect(runtimeLogsContain("Installing plugin from npm registry")).toBe(true); expect(runtimeLogsContain("outside ClawHub review")).toBe(true); expect(installPluginFromNpmSpec).not.toHaveBeenCalled(); @@ -1467,13 +1467,13 @@ describe("plugins cli install", () => { it("prompts interactive users before non-ClawHub plugin installs and proceeds on yes", async () => { setTty(true); - promptYesNo.mockResolvedValueOnce(true); + promptYesNoMock.mockResolvedValueOnce(true); primeSuccessfulPluginPersistence("demo"); installPluginFromNpmSpec.mockResolvedValue(createNpmPluginInstallResult("demo")); await runPluginsCommand(["plugins", "install", "npm:demo"]); - expect(promptYesNo).toHaveBeenCalledWith("Install this non-ClawHub plugin source?"); + expect(promptYesNoMock).toHaveBeenCalledWith("Install this non-ClawHub plugin source?"); expect(runtimeLogsContain("Installing plugin from npm registry")).toBe(true); expect(runtimeLogsContain("outside ClawHub review")).toBe(true); expect(installPluginFromNpmSpec).toHaveBeenCalledTimes(1); diff --git a/src/cli/plugins-cli.list.test.ts b/src/cli/plugins-cli.list.test.ts index 9f026c730029..7ef19360bdda 100644 --- a/src/cli/plugins-cli.list.test.ts +++ b/src/cli/plugins-cli.list.test.ts @@ -20,7 +20,7 @@ import { refreshPluginRegistry, runPluginsCommand, runtimeErrors, - runtimeLogs, + pluginsCliRuntimeLogs, setInstalledPluginIndexInstallRecords, } from "./plugins-cli-test-helpers.js"; @@ -103,7 +103,7 @@ describe("plugins cli list", () => { expect(reportOptions?.logger?.warn).toBeTypeOf("function"); expect(reportOptions?.logger?.error).toBeTypeOf("function"); - const output = JSON.parse(runtimeLogs[0] ?? "null") as { + const output = JSON.parse(pluginsCliRuntimeLogs[0] ?? "null") as { workspaceDir?: string; registry?: { source?: string; diagnostics?: unknown[] }; plugins?: Array<{ @@ -134,7 +134,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); expect(buildPluginDiagnosticsReport).toHaveBeenCalledWith({ config: {}, effectiveOnly: true }); - expect(runtimeLogs).toContain(cleanDoctorMessage); + expect(pluginsCliRuntimeLogs).toContain(cleanDoctorMessage); }); it.each([ @@ -155,7 +155,7 @@ describe("plugins cli list", () => { const warning = "- plugins.entries.google: plugin disabled (not in allowlist) but config is present"; if (args.includes("--json")) { - const output = JSON.parse(runtimeLogs[0] ?? "null") as { + const output = JSON.parse(pluginsCliRuntimeLogs[0] ?? "null") as { ok: boolean; configurationWarnings: string[]; }; @@ -163,8 +163,8 @@ describe("plugins cli list", () => { expect(output.configurationWarnings).toEqual([warning]); return; } - expect(runtimeLogs.join("\n")).toContain(warning); - expect(runtimeLogs).not.toContain(cleanDoctorMessage); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(warning); + expect(pluginsCliRuntimeLogs).not.toContain(cleanDoctorMessage); }, ); @@ -183,7 +183,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor", "--json"]); - const output = JSON.parse(runtimeLogs[0] ?? "null") as { + const output = JSON.parse(pluginsCliRuntimeLogs[0] ?? "null") as { ok: boolean; configurationWarnings: string[]; }; @@ -205,13 +205,13 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor", ...args]); if (args.includes("--json")) { - expect(JSON.parse(runtimeLogs[0] ?? "null")).toMatchObject({ + expect(JSON.parse(pluginsCliRuntimeLogs[0] ?? "null")).toMatchObject({ ok: true, configurationWarnings: [], }); return; } - expect(runtimeLogs).toContain(cleanDoctorMessage); + expect(pluginsCliRuntimeLogs).toContain(cleanDoctorMessage); }); it.each([ @@ -229,13 +229,13 @@ describe("plugins cli list", () => { const warning = "- plugins.\\nentries.google: bad\\r\\n\\tvalue"; if (args.includes("--json")) { - expect(JSON.parse(runtimeLogs[0] ?? "null")).toMatchObject({ + expect(JSON.parse(pluginsCliRuntimeLogs[0] ?? "null")).toMatchObject({ ok: false, configurationWarnings: [warning], }); return; } - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain(warning); expect(output).not.toContain("\u0007"); expect(output).not.toContain("\u001b"); @@ -273,12 +273,12 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor", "--json"]); }); - expect(runtimeLogs).toHaveLength(1); + expect(pluginsCliRuntimeLogs).toHaveLength(1); expect(runtimeErrors).toEqual([]); - expect(runtimeLogs[0]).not.toContain(homeDir); - expect(runtimeLogs[0]).not.toContain("Plugin errors:"); - expect(runtimeLogs[0]).not.toContain("Docs:"); - expect(JSON.parse(runtimeLogs[0] ?? "null")).toEqual({ + expect(pluginsCliRuntimeLogs[0]).not.toContain(homeDir); + expect(pluginsCliRuntimeLogs[0]).not.toContain("Plugin errors:"); + expect(pluginsCliRuntimeLogs[0]).not.toContain("Docs:"); + expect(JSON.parse(pluginsCliRuntimeLogs[0] ?? "null")).toEqual({ ok: false, pluginErrors: [ { @@ -344,7 +344,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("Diagnostics:"); expect(output).toContain(expected); expect(output).not.toContain(cleanDoctorMessage); @@ -362,7 +362,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("broken: plugin manifest invalid"); expect(output).toContain("calendar: required plugin contacts is missing"); expect(output).not.toContain(cleanDoctorMessage); @@ -403,7 +403,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("Plugin configuration:"); expect(output).toContain( "Stale plugin references (plugins.allow/deny/entries): lossless-claw.", @@ -455,7 +455,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("Plugin configuration:"); expect(output).toContain('Configured runtime "codex" requires the Codex plugin'); expect(output).toContain("openclaw doctor --fix"); @@ -480,7 +480,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("Plugin configuration:"); expect(output).toContain('Configured runtime "acpx" requires the ACPX Runtime plugin'); expect(output).toContain("openclaw doctor --fix"); @@ -507,7 +507,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain('Configured runtime "acpx" requires the ACPX Runtime plugin'); expect(output).toContain("Set plugins.entries.acpx.enabled=true"); expect(output).toContain("disable ACP/acpx in acp config"); @@ -530,7 +530,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain('Configured runtime "acpx" requires the ACPX Runtime plugin'); expect(output).toContain('Enable the "acpx" plugin'); expect(output).toContain("disable ACP/acpx in acp config"); @@ -555,7 +555,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).not.toContain('Configured runtime "codex"'); expect(output).toContain(cleanDoctorMessage); }); @@ -580,7 +580,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - expect(runtimeLogs).toContain(cleanDoctorMessage); + expect(pluginsCliRuntimeLogs).toContain(cleanDoctorMessage); }); it("reports configured Codex runtime when the plugin record is disabled", async () => { @@ -603,7 +603,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain('Configured runtime "codex" requires the Codex plugin'); expect(output).toContain('but "codex" is disabled'); expect(output).toContain('Enable the "codex" plugin'); @@ -634,7 +634,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain('Configured runtime "codex" requires the Codex plugin'); expect(output).toContain('but "codex" is blocked by plugin configuration'); expect(output).toContain('Remove "codex" from plugins.deny'); @@ -668,7 +668,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain('Configured runtime "codex" requires the Codex plugin'); expect(output).toContain('but "codex" is blocked by plugin configuration'); expect(output).toContain("Set plugins.entries.codex.enabled=true"); @@ -701,7 +701,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - const output = runtimeLogs.join("\n"); + const output = pluginsCliRuntimeLogs.join("\n"); expect(output).toContain("Plugin source shadowing:"); expect(output).toContain( "discord: duplicate plugin id resolved by explicit config-selected plugin", @@ -734,7 +734,7 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "doctor"]); - expect(runtimeLogs).toContain(cleanDoctorMessage); + expect(pluginsCliRuntimeLogs).toContain(cleanDoctorMessage); }); it("reports persisted plugin registry state without refreshing", async () => { @@ -756,10 +756,10 @@ describe("plugins cli list", () => { expect(inspectPluginRegistry).toHaveBeenCalledWith({ config: {} }); expect(refreshPluginRegistry).not.toHaveBeenCalled(); - expect(runtimeLogs.join("\n")).toContain("State:"); - expect(runtimeLogs.join("\n")).toContain("stale"); - expect(runtimeLogs.join("\n")).toContain("Refresh reasons:"); - expect(runtimeLogs.join("\n")).toContain("openclaw plugins registry --refresh"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("State:"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("stale"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("Refresh reasons:"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("openclaw plugins registry --refresh"); }); it("refreshes the persisted plugin registry on request", async () => { @@ -777,7 +777,7 @@ describe("plugins cli list", () => { reason: "manual", }); expect(inspectPluginRegistry).not.toHaveBeenCalled(); - expect(runtimeLogs.join("\n")).toContain("Plugin registry refreshed: 1/2 enabled"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("Plugin registry refreshed: 1/2 enabled"); }); it("keeps inspect on the static snapshot by default", async () => { @@ -839,19 +839,19 @@ describe("plugins cli list", () => { await runPluginsCommand(["plugins", "inspect", "openclaw-mem0"]); expect(buildPluginDiagnosticsReport).not.toHaveBeenCalled(); - expect(runtimeLogs.join("\n")).toContain("Policy"); - expect(runtimeLogs.join("\n")).toContain("allowConversationAccess: true"); - expect(runtimeLogs.join("\n")).toContain("ClawHub package: openclaw-mem0"); - expect(runtimeLogs.join("\n")).toContain("Artifact kind: npm-pack"); - expect(runtimeLogs.join("\n")).toContain("Npm integrity: sha512-clawpack"); - expect(runtimeLogs.join("\n")).toContain( + expect(pluginsCliRuntimeLogs.join("\n")).toContain("Policy"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("allowConversationAccess: true"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("ClawHub package: openclaw-mem0"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("Artifact kind: npm-pack"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("Npm integrity: sha512-clawpack"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain( "ClawPack sha256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ); - expect(runtimeLogs.join("\n")).toContain("ClawPack spec: 1"); - expect(runtimeLogs.join("\n")).toContain("ClawPack size: 4096 bytes"); - expect(runtimeLogs.join("\n")).toContain("remote"); - expect(runtimeLogs.join("\n")).not.toContain("remote (unsupported transport)"); - expect(runtimeLogs.join("\n")).toContain("broken (unsupported transport)"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("ClawPack spec: 1"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("ClawPack size: 4096 bytes"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("remote"); + expect(pluginsCliRuntimeLogs.join("\n")).not.toContain("remote (unsupported transport)"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("broken (unsupported transport)"); }); it("runtime-inspects without repairing deps", async () => { diff --git a/src/cli/plugins-cli.policy.test.ts b/src/cli/plugins-cli.policy.test.ts index 14cc09d25a50..e9360ab2cd30 100644 --- a/src/cli/plugins-cli.policy.test.ts +++ b/src/cli/plugins-cli.policy.test.ts @@ -9,7 +9,7 @@ import { refreshPluginRegistry, resetPluginsCliTestState, runtimeErrors, - runtimeLogs, + pluginsCliRuntimeLogs, runPluginsCommand, writeConfigFile, } from "./plugins-cli-test-helpers.js"; @@ -135,7 +135,7 @@ describe("plugins cli policy mutations", () => { expect(writeConfigFile).not.toHaveBeenCalled(); expect(refreshPluginRegistry).not.toHaveBeenCalled(); expect(runtimeErrors).toContain(`Plugin "alpha" could not be enabled (${reason}).`); - expect(runtimeLogs).not.toContain(`Plugin "alpha" could not be enabled (${reason}).`); + expect(pluginsCliRuntimeLogs).not.toContain(`Plugin "alpha" could not be enabled (${reason}).`); }); it("refuses plugin enablement in Nix mode before config mutation", async () => { diff --git a/src/cli/plugins-cli.uninstall.test.ts b/src/cli/plugins-cli.uninstall.test.ts index 0b0a7e38b4e1..c2bda7fb28bd 100644 --- a/src/cli/plugins-cli.uninstall.test.ts +++ b/src/cli/plugins-cli.uninstall.test.ts @@ -14,7 +14,7 @@ import { loadConfig, planPluginUninstall, PromptInputClosedError, - promptYesNo, + promptYesNoMock, readPersistedInstalledPluginIndex, refreshPluginRegistry, replaceConfigFile, @@ -22,7 +22,7 @@ import { restorePersistedInstalledPluginIndexIfCurrent, runPluginsCommand, runtimeErrors, - runtimeLogs, + pluginsCliRuntimeLogs, setInstalledPluginIndexInstallRecords, writeConfigFile, writePersistedInstalledPluginIndexInstallRecordsWithLease, @@ -59,7 +59,7 @@ function primeUninstallPlan( } function expectRuntimeLogIncludes(fragment: string) { - expect(runtimeLogs.join("\n")).toContain(fragment); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(fragment); } function expectInstallRecordsWrittenWithLease(records: unknown, config: unknown) { @@ -195,7 +195,7 @@ describe("plugins cli uninstall", () => { await runPluginsCommand(["plugins", "uninstall", "alpha", "--force", "--keep-files"]); - expect(promptYesNo).not.toHaveBeenCalled(); + expect(promptYesNoMock).not.toHaveBeenCalled(); expectLatestUninstallPlanParams({ pluginId: "alpha", deleteFiles: false }); expectInstallRecordsWrittenWithLease({}, { plugins: { entries: {} } }); expect(writeConfigFile).toHaveBeenCalledWith({ @@ -306,7 +306,7 @@ describe("plugins cli uninstall", () => { expect(runtimeErrors.at(-1)).toContain('Plugin uninstall target "calendar" is ambiguous'); expect(planPluginUninstall).not.toHaveBeenCalled(); - expect(promptYesNo).not.toHaveBeenCalled(); + expect(promptYesNoMock).not.toHaveBeenCalled(); expect(applyPluginUninstallDirectoryRemoval).not.toHaveBeenCalled(); expect(writePersistedInstalledPluginIndexInstallRecordsWithLease).not.toHaveBeenCalled(); expect(writeConfigFile).not.toHaveBeenCalled(); @@ -392,7 +392,7 @@ describe("plugins cli uninstall", () => { diagnostics: [], }); primeUninstallPlan({ plugins: { entries: {}, installs: {} } } as OpenClawConfig); - promptYesNo.mockRejectedValueOnce(new PromptInputClosedError()); + promptYesNoMock.mockRejectedValueOnce(new PromptInputClosedError()); await expect(runPluginsCommand(["plugins", "uninstall", "alpha"])).rejects.toThrow( "__exit__:1", @@ -595,7 +595,7 @@ describe("plugins cli uninstall", () => { expectLatestUninstallPlanParams({ pluginId: "alpha", deleteFiles: true }); expect(writeConfigFile).toHaveBeenCalledWith(nextConfig); - expect(runtimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); + expect(pluginsCliRuntimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); }); it("uninstalls stale enabled entries when plugin is absent from the current registry", async () => { @@ -627,7 +627,7 @@ describe("plugins cli uninstall", () => { reason: "source-changed", }); expect(runtimeErrors).not.toContain("Plugin not found: alpha"); - expect(runtimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); + expect(pluginsCliRuntimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); }); it.each([ @@ -758,7 +758,7 @@ describe("plugins cli uninstall", () => { expectInstallRecordsWrittenWithLease({}, nextConfig); expect(writeConfigFile).toHaveBeenCalledWith(nextConfig); expectRuntimeLogIncludes("channel config (channels.alpha)"); - expect(runtimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); + expect(pluginsCliRuntimeLogs.at(-2)).toContain('Uninstalled plugin "alpha"'); }); it("exits when uninstall target is not managed by plugin install records", async () => { diff --git a/src/cli/plugins-cli.update.test.ts b/src/cli/plugins-cli.update.test.ts index bb7937744fb9..582f8e6fdcc0 100644 --- a/src/cli/plugins-cli.update.test.ts +++ b/src/cli/plugins-cli.update.test.ts @@ -10,17 +10,16 @@ import { VERSION } from "../version.js"; import { createTestInstalledPluginIndex, loadConfig, - notifyGatewayPluginMetadataChanged, + notifyGatewayPluginMetadataChangedMock, readConfigFileSnapshotForWrite, readPersistedInstalledPluginIndex, refreshPluginRegistry, - registerPluginsCli, replaceConfigFile, resetPluginsCliTestState, restorePersistedInstalledPluginIndexIfCurrent, runPluginsCommand, runtimeErrors, - runtimeLogs, + pluginsCliRuntimeLogs, setInstalledPluginIndexInstallRecords, setHookInstallRecords, updateNpmInstalledHookPacks, @@ -28,6 +27,7 @@ import { writeConfigFile, writePersistedInstalledPluginIndexInstallRecordsWithLease, } from "./plugins-cli-test-helpers.js"; +import { registerPluginsCli } from "./plugins-cli.js"; const ORIGINAL_OPENCLAW_NIX_MODE = process.env.OPENCLAW_NIX_MODE; const ORIGINAL_STDIN_TTY = Object.getOwnPropertyDescriptor(process.stdin, "isTTY"); @@ -78,7 +78,7 @@ function createTrackedPluginConfig(params: { function expectRestartNoticeLogged() { expect( - runtimeLogs.some((message) => + pluginsCliRuntimeLogs.some((message) => message.includes("Restart the gateway to load plugins and hooks."), ), ).toBe(true); @@ -237,7 +237,7 @@ async function expectSkippedClawHubPluginUpdate(params: { await expect(runPluginsCommand(["plugins", "update", "demo"])).rejects.toThrow("__exit__:1"); expect(writePersistedInstalledPluginIndexInstallRecordsWithLease).not.toHaveBeenCalled(); - expect(runtimeLogs.at(-1)).toContain(params.expectedLog); + expect(pluginsCliRuntimeLogs.at(-1)).toContain(params.expectedLog); } describe("plugins cli update", () => { @@ -317,7 +317,7 @@ describe("plugins cli update", () => { expect(replaceConfigFile).not.toHaveBeenCalled(); expect(writePersistedInstalledPluginIndexInstallRecordsWithLease).not.toHaveBeenCalled(); expect(refreshPluginRegistry).not.toHaveBeenCalled(); - expect(runtimeLogs).toContain("Would update alpha: 1.0.0 -> 1.1.0."); + expect(pluginsCliRuntimeLogs).toContain("Would update alpha: 1.0.0 -> 1.1.0."); } finally { acquireLease.mockRestore(); } @@ -681,7 +681,7 @@ describe("plugins cli update", () => { installRecords: nextRecords, reason: "source-changed", }); - expect(notifyGatewayPluginMetadataChanged).toHaveBeenCalledWith(cfg); + expect(notifyGatewayPluginMetadataChangedMock).toHaveBeenCalledWith(cfg); expectRestartNoticeLogged(); }); @@ -749,7 +749,7 @@ describe("plugins cli update", () => { installRecords: nextRecords, reason: "source-changed", }); - expect(notifyGatewayPluginMetadataChanged).not.toHaveBeenCalled(); + expect(notifyGatewayPluginMetadataChangedMock).not.toHaveBeenCalled(); }); it("rolls back persisted install records when source config changes during a records-only update", async () => { @@ -811,7 +811,7 @@ describe("plugins cli update", () => { expect(writeConfigFile).not.toHaveBeenCalled(); expect(replaceConfigFile).not.toHaveBeenCalled(); expect(refreshPluginRegistry).not.toHaveBeenCalled(); - expect(notifyGatewayPluginMetadataChanged).not.toHaveBeenCalled(); + expect(notifyGatewayPluginMetadataChangedMock).not.toHaveBeenCalled(); }); it("rolls back persisted install records when included config changes during a records-only update", async () => { @@ -1216,7 +1216,7 @@ describe("plugins cli update", () => { expect(updateNpmInstalledPlugins).not.toHaveBeenCalled(); expect(updateNpmInstalledHookPacks).not.toHaveBeenCalled(); - expect(runtimeLogs.at(-1)).toBe("No tracked plugins or hook packs to update."); + expect(pluginsCliRuntimeLogs.at(-1)).toBe("No tracked plugins or hook packs to update."); }); it("passes dangerous force unsafe install to plugin updates", async () => { @@ -1240,7 +1240,7 @@ describe("plugins cli update", () => { expect(updateParams.pluginIds).toEqual(["openclaw-codex-app-server"]); expect(updateParams.dangerouslyForceUnsafeInstall).toBe(true); expect( - runtimeLogs.some((message) => + pluginsCliRuntimeLogs.some((message) => message.includes( "--dangerously-force-unsafe-install is deprecated and no longer affects plugin updates", ), @@ -1536,7 +1536,7 @@ describe("plugins cli update", () => { installRecords: nextConfig.plugins?.installs, reason: "source-changed", }); - expect(runtimeLogs).toContain("Failed to update beta: registry timeout"); + expect(pluginsCliRuntimeLogs).toContain("Failed to update beta: registry timeout"); }); it("exits non-zero when a ClawHub update is skipped for missing risk acknowledgement", async () => { @@ -1596,7 +1596,9 @@ describe("plugins cli update", () => { ); expect(writeConfigFile).not.toHaveBeenCalled(); - expect(runtimeLogs).toContain('Failed to update hook pack "demo-hooks": registry timeout'); + expect(pluginsCliRuntimeLogs).toContain( + 'Failed to update hook pack "demo-hooks": registry timeout', + ); }); }); /* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */ diff --git a/src/cli/plugins-install-preflight.test.ts b/src/cli/plugins-install-preflight.test.ts index 0f9d987ce1f6..c523532efdb6 100644 --- a/src/cli/plugins-install-preflight.test.ts +++ b/src/cli/plugins-install-preflight.test.ts @@ -10,7 +10,7 @@ import { installPluginFromNpmSpec, installPluginFromPath, parseClawHubPluginSpec, - promptYesNo, + promptYesNoMock, readConfigFileSnapshotForWrite, resetPluginsCliTestState, resolveMarketplaceInstallShortcut, @@ -31,7 +31,7 @@ vi.mock("../plugins/plugin-lifecycle-lease.js", () => ({ function expectNoPluginInstallSideEffects(): void { expect(withPluginLifecycleLeaseMock).not.toHaveBeenCalled(); expect(readConfigFileSnapshotForWrite).not.toHaveBeenCalled(); - expect(promptYesNo).not.toHaveBeenCalled(); + expect(promptYesNoMock).not.toHaveBeenCalled(); expect(installPluginFromClawHub).not.toHaveBeenCalled(); expect(installPluginFromGitSpec).not.toHaveBeenCalled(); expect(installPluginFromMarketplace).not.toHaveBeenCalled(); diff --git a/src/cli/program.smoke.test.ts b/src/cli/program.smoke.test.ts index 4d2114d2e436..e0ce945e099e 100644 --- a/src/cli/program.smoke.test.ts +++ b/src/cli/program.smoke.test.ts @@ -4,7 +4,7 @@ import { buildProgram } from "./program.js"; import { callGateway, configureCommand, - ensureConfigReady, + ensureConfigReadyMock, runSystemAgentWithInference, runTui, runtime, @@ -46,7 +46,7 @@ describe("cli program (smoke)", () => { vi.clearAllMocks(); runTui.mockResolvedValue(undefined); runSystemAgentWithInference.mockResolvedValue(undefined); - ensureConfigReady.mockResolvedValue(undefined); + ensureConfigReadyMock.mockResolvedValue(undefined); }); it("registers message + status commands", () => { diff --git a/src/cli/program.test-mocks.ts b/src/cli/program.test-mocks.ts index e603c852fcb7..840b763adea5 100644 --- a/src/cli/program.test-mocks.ts +++ b/src/cli/program.test-mocks.ts @@ -44,7 +44,7 @@ export const setupWizardCommand = programMocks.setupWizardCommand as AnyMock; export const callGateway = programMocks.callGateway as AnyMock; export const runTui = programMocks.runTui as AnyMock; export const runSystemAgentWithInference = programMocks.runSystemAgentWithInference as AnyMock; -export const ensureConfigReady = programMocks.ensureConfigReady as AnyMock; +export const ensureConfigReadyMock = programMocks.ensureConfigReady as AnyMock; export const runtime = programMocks.runtime as { log: Mock<(...args: unknown[]) => void>; diff --git a/src/cli/program/register.subclis-core.ts b/src/cli/program/register.subclis-core.ts index 163972944591..5ba6f0f6483a 100644 --- a/src/cli/program/register.subclis-core.ts +++ b/src/cli/program/register.subclis-core.ts @@ -332,7 +332,7 @@ export function getSubCliEntries(): ReadonlyArray { return getSubCliEntryDescriptors(); } -export async function registerSubCliByName( +export async function registerSubCliByNameCore( program: Command, name: string, argv: string[] = process.argv, @@ -345,7 +345,7 @@ export async function registerSubCliByName( return registerCommandGroupByName(program, resolveSubCliCommandGroups(argv, context), name); } -export function registerSubCliCommands(program: Command, argv: string[] = process.argv) { +export function registerSubCliCommandsCore(program: Command, argv: string[] = process.argv) { const { primary } = resolveCliArgvInvocation(argv); registerCommandGroups(program, resolveSubCliCommandGroups(argv), { eager: shouldEagerRegisterSubcommands(), diff --git a/src/cli/program/register.subclis.ts b/src/cli/program/register.subclis.ts index d730344801f5..a5b81ed04bd7 100644 --- a/src/cli/program/register.subclis.ts +++ b/src/cli/program/register.subclis.ts @@ -16,8 +16,8 @@ import { type CommandGroupEntry, } from "./register-command-groups.js"; import { - registerSubCliByName as registerSubCliByNameCore, - registerSubCliCommands as registerSubCliCommandsCore, + registerSubCliByNameCore, + registerSubCliCommandsCore, type SubCliRegistrationContext, } from "./register.subclis-core.js"; import { getSubCliEntries as getSubCliEntryDescriptors } from "./subcli-descriptors.js"; diff --git a/src/cli/run-main.ts b/src/cli/run-main.ts index 03254299784c..d17e0be3a179 100644 --- a/src/cli/run-main.ts +++ b/src/cli/run-main.ts @@ -20,7 +20,6 @@ import type { ProxyHandle } from "../infra/net/proxy/proxy-lifecycle.js"; import { ensureOpenClawCliOnPath } from "../infra/path-env.js"; import { assertSupportedRuntime } from "../infra/runtime-guard.js"; import { tryProcessCwd } from "../infra/safe-cwd.js"; -import type { PluginManifestCommandAliasRegistry } from "../plugins/manifest-command-aliases.js"; import { resolveCliArgvInvocation } from "./argv-invocation.js"; import { normalizeGeneratedHelpCommandArgv, @@ -58,7 +57,7 @@ import { } from "./program/core-command-descriptors.js"; import { getSubCliEntries } from "./program/subcli-descriptors.js"; import { - resolveMissingPluginCommandMessage as resolveMissingPluginCommandMessageFromPolicy, + resolveMissingPluginCommandMessage, rewriteUpdateFlagArgv, shouldHandleBareRoot, shouldEnsureCliPath, @@ -695,18 +694,6 @@ function pauseNonTtyStdinForCliExit(): void { } } -export function resolveMissingPluginCommandMessage( - pluginId: string, - config?: OpenClawConfig, - options?: { registry?: PluginManifestCommandAliasRegistry }, -): string | null { - return resolveMissingPluginCommandMessageFromPolicy( - pluginId, - config, - options?.registry ? { registry: options.registry } : undefined, - ); -} - function shouldLoadCliDotEnv( loadGlobalEnv: boolean, env: NodeJS.ProcessEnv = process.env, @@ -1005,15 +992,11 @@ async function resolveUnownedCliPrimaryMessage(params: { const { resolveManifestCommandAliasOwner, resolveManifestToolOwner } = await loadManifestCommandAliasesRuntimeModule(); const cliCommandSurfaceOwner = await resolveCliCommandSurfaceOwner(params); - const pluginPolicyMessage = resolveMissingPluginCommandMessageFromPolicy( - params.primary, - params.config, - { - resolveCommandAliasOwner: resolveManifestCommandAliasOwner, - resolveToolOwner: resolveManifestToolOwner, - resolveCliCommandSurfaceOwner: () => cliCommandSurfaceOwner, - }, - ); + const pluginPolicyMessage = resolveMissingPluginCommandMessage(params.primary, params.config, { + resolveCommandAliasOwner: resolveManifestCommandAliasOwner, + resolveToolOwner: resolveManifestToolOwner, + resolveCliCommandSurfaceOwner: () => cliCommandSurfaceOwner, + }); if (pluginPolicyMessage) { return pluginPolicyMessage; } @@ -1628,7 +1611,7 @@ async function runCliWithPreparedOutputMode( primary, config, }); - const missingPluginCommandMessage = resolveMissingPluginCommandMessageFromPolicy( + const missingPluginCommandMessage = resolveMissingPluginCommandMessage( primary, config, { diff --git a/src/commands/agents.bindings.ts b/src/commands/agents.bindings.ts index c3f11eefe63d..e20c80e9fb93 100644 --- a/src/commands/agents.bindings.ts +++ b/src/commands/agents.bindings.ts @@ -6,7 +6,7 @@ import { getBundledChannelSetupPlugin } from "../channels/plugins/bundled.js"; import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js"; import { getLoadedChannelPlugin } from "../channels/plugins/index.js"; import type { ChannelId } from "../channels/plugins/types.public.js"; -import { normalizeChannelId as normalizeBundledChannelId } from "../channels/registry.js"; +import { normalizeChatChannelId as normalizeBundledChannelId } from "../channels/registry.js"; import { formatUnknownChannelMessage } from "../cli/error-format.js"; import { isRouteBinding, listRouteBindings } from "../config/bindings.js"; import type { AgentRouteBinding } from "../config/types.js"; diff --git a/src/commands/channels.list.test.ts b/src/commands/channels.list.test.ts index 201e069f514d..68616e522bd6 100644 --- a/src/commands/channels.list.test.ts +++ b/src/commands/channels.list.test.ts @@ -18,7 +18,7 @@ const mocks = vi.hoisted(() => ({ diagnostics: [], })), listReadOnlyChannelPluginsForConfig: vi.fn<() => ChannelPlugin[]>(() => []), - buildChannelAccountSnapshot: vi.fn(), + resolveChannelAccountSnapshot: vi.fn(), listTrustedChannelPluginCatalogEntries: vi.fn<() => ChannelPluginCatalogEntry[]>(() => []), listManifestInstalledChannelIds: vi.fn<() => Set>(() => new Set()), resolveMissingOfficialExternalChannelPluginRepairHint: vi.fn(), @@ -53,7 +53,7 @@ vi.mock("../channels/plugins/read-only.js", () => ({ })); vi.mock("../channels/plugins/status.js", () => ({ - buildChannelAccountSnapshot: mocks.buildChannelAccountSnapshot, + resolveChannelAccountSnapshot: mocks.resolveChannelAccountSnapshot, })); vi.mock("./channel-setup/trusted-catalog.js", () => ({ @@ -130,7 +130,7 @@ describe("channels list", () => { mocks.resolveCommandConfigWithSecrets.mockClear(); mocks.listReadOnlyChannelPluginsForConfig.mockReset(); mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([]); - mocks.buildChannelAccountSnapshot.mockReset(); + mocks.resolveChannelAccountSnapshot.mockReset(); mocks.listTrustedChannelPluginCatalogEntries.mockReset(); mocks.listTrustedChannelPluginCatalogEntries.mockReturnValue([]); mocks.listManifestInstalledChannelIds.mockReset(); @@ -213,7 +213,7 @@ describe("channels list", () => { mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([ createMockChannelPlugin({ accountIds: ["default"] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: true, tokenSource: "config", @@ -253,7 +253,7 @@ describe("channels list", () => { mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([ createMockChannelPlugin({ id: "discord", label: "Discord", accountIds: ["default"] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: false, tokenSource: "none", @@ -302,7 +302,7 @@ describe("channels list", () => { mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([ createMockChannelPlugin({ id: "discord", label: "Discord", accountIds: ["default"] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: false, tokenSource: "none", @@ -331,7 +331,7 @@ describe("channels list", () => { mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([ createMockChannelPlugin({ id: "discord", label: "Discord", accountIds: ["default"] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: true, tokenSource: "config", @@ -488,7 +488,7 @@ describe("channels list", () => { mocks.listReadOnlyChannelPluginsForConfig.mockReturnValue([ createMockChannelPlugin({ id: "discord", label: "Discord", accountIds: [] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: false, enabled: false, @@ -520,7 +520,7 @@ describe("channels list", () => { createMockChannelPlugin({ id: "telegram", accountIds: ["default"] }), createMockChannelPlugin({ id: "discord", label: "Discord", accountIds: [] }), ]); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: false, enabled: false, diff --git a/src/commands/channels.status.command-flow.test.ts b/src/commands/channels.status.command-flow.test.ts index cdb4bb4394f5..36894abf3a8a 100644 --- a/src/commands/channels.status.command-flow.test.ts +++ b/src/commands/channels.status.command-flow.test.ts @@ -152,7 +152,7 @@ vi.mock("../channels/plugins/status.js", () => ({ accountId, ...plugin.config.inspectAccount(cfg), }), - buildChannelAccountSnapshot: async ({ + resolveChannelAccountSnapshot: async ({ plugin, cfg, accountId, diff --git a/src/commands/channels/list.ts b/src/commands/channels/list.ts index 7060b8d262b3..5ee19fc4f728 100644 --- a/src/commands/channels/list.ts +++ b/src/commands/channels/list.ts @@ -5,7 +5,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/ag import type { ChannelPluginCatalogEntry } from "../../channels/plugins/catalog.js"; import { isChannelVisibleInConfiguredLists } from "../../channels/plugins/exposure.js"; import { listReadOnlyChannelPluginsForConfig } from "../../channels/plugins/read-only.js"; -import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js"; +import { resolveChannelAccountSnapshot } from "../../channels/plugins/status.js"; import type { ChannelPlugin } from "../../channels/plugins/types.plugin.js"; import type { ChannelAccountSnapshot } from "../../channels/plugins/types.public.js"; import { @@ -223,7 +223,7 @@ export async function channelsListCommand( localAccountIds: accountIds, runtimeAccounts, resolveLocalSnapshot: (accountId) => - buildChannelAccountSnapshot({ plugin, cfg, accountId }), + resolveChannelAccountSnapshot({ plugin, cfg, accountId }), }); for (const row of rows) { accountLines.push({ @@ -245,7 +245,7 @@ export async function channelsListCommand( // full set of channels they could enable without first running // `channels add`. Use the channel's default account so the snapshot // can reflect "not configured / not enabled" state. - const snapshot = await buildChannelAccountSnapshot({ + const snapshot = await resolveChannelAccountSnapshot({ plugin, cfg, accountId: "default", diff --git a/src/commands/channels/logs.ts b/src/commands/channels/logs.ts index 723592fc2e7b..8173560a7459 100644 --- a/src/commands/channels/logs.ts +++ b/src/commands/channels/logs.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; import { theme } from "../../../packages/terminal-core/src/theme.js"; -import { normalizeChannelId as normalizeBundledChannelId } from "../../channels/registry.js"; +import { normalizeChatChannelId as normalizeBundledChannelId } from "../../channels/registry.js"; import { readFileWindowFully } from "../../infra/file-read.js"; import { parseStrictPositiveInteger } from "../../infra/parse-finite-number.js"; import { getResolvedLoggerSettings } from "../../logging.js"; diff --git a/src/commands/channels/status-config-format.ts b/src/commands/channels/status-config-format.ts index d157e4725b6b..eb74a7dd9c44 100644 --- a/src/commands/channels/status-config-format.ts +++ b/src/commands/channels/status-config-format.ts @@ -9,7 +9,7 @@ import { import { normalizeChannelId } from "../../channels/plugins/index.js"; import { listReadOnlyChannelPluginsForConfig } from "../../channels/plugins/read-only.js"; import { - buildChannelAccountSnapshot, + resolveChannelAccountSnapshot, buildReadOnlySourceChannelAccountSnapshot, } from "../../channels/plugins/status.js"; import type { ChannelAccountSnapshot } from "../../channels/plugins/types.public.js"; @@ -87,7 +87,7 @@ export async function formatConfigChannelsStatusLines( cfg: sourceConfig, accountId, }); - const resolvedSnapshot = await buildChannelAccountSnapshot({ + const resolvedSnapshot = await resolveChannelAccountSnapshot({ plugin, cfg, accountId, diff --git a/src/commands/flows.test.ts b/src/commands/flows.test.ts index d17ac1761384..78bc2af6d6a9 100644 --- a/src/commands/flows.test.ts +++ b/src/commands/flows.test.ts @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { visibleWidth } from "../../packages/terminal-core/src/ansi.js"; import type { RuntimeEnv } from "../runtime.js"; -import { createRunningTaskRun as createRunningTaskRunOrNull } from "../tasks/task-executor.js"; +import { createRunningTaskRunCore as createRunningTaskRunOrNull } from "../tasks/task-executor.js"; import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "../tasks/task-flow-registry.js"; import type { TaskFlowRecord } from "../tasks/task-flow-registry.types.js"; import { markTaskLostById, markTaskTerminalById } from "../tasks/task-registry.js"; @@ -37,7 +37,7 @@ function createManagedTaskFlow( return flow; } -function createRunningTaskRun( +function createRunningTaskRunCore( params: Parameters[0], ): TaskRecord { const task = createRunningTaskRunOrNull(params); @@ -109,7 +109,7 @@ describe("flows commands", () => { updatedAt: 100, }); - const childTask = createRunningTaskRun({ + const childTask = createRunningTaskRunCore({ runtime: "acp", ownerKey: "agent:main:main", scopeKind: "session", @@ -302,7 +302,7 @@ describe("flows commands", () => { updatedAt: 100, }); - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -347,7 +347,7 @@ describe("flows commands", () => { goal: "Inspect child task failures", status: "running", }); - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -402,7 +402,7 @@ describe("flows commands", () => { goal: "Inspect child task updates", status: "running", }); - const running = createRunningTaskRun({ + const running = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -415,7 +415,7 @@ describe("flows commands", () => { startedAt: Date.now(), progressSummary: "Downloading provider metadata", }); - const completed = createRunningTaskRun({ + const completed = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -455,7 +455,7 @@ describe("flows commands", () => { goal: "Inspect unsafe child error", status: "running", }); - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -495,7 +495,7 @@ describe("flows commands", () => { currentStep: `step${unsafe}`, status: "running", }); - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "subagent", ownerKey: "agent:main:main", scopeKind: "session", @@ -603,7 +603,7 @@ describe("flows commands", () => { updatedAt: 100, }); - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "subagent", ownerKey: unsafeOwnerKey, scopeKind: "session", diff --git a/src/commands/status-all/channels.ts b/src/commands/status-all/channels.ts index 0e2ff714cbff..ea0dd08bd863 100644 --- a/src/commands/status-all/channels.ts +++ b/src/commands/status-all/channels.ts @@ -9,7 +9,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/ag import { resolveInspectedChannelAccount } from "../../channels/account-inspection.js"; import { hasConfiguredUnavailableCredentialStatus } from "../../channels/account-snapshot-fields.js"; import { - buildChannelAccountSnapshot, + buildChannelAccountSummary, formatChannelAllowFrom, } from "../../channels/account-summary.js"; import { resolveChannelDefaultAccountId } from "../../channels/plugins/helpers.js"; @@ -79,7 +79,7 @@ async function resolveChannelAccountRow( sourceConfig, accountId, }); - const snapshot = buildChannelAccountSnapshot({ + const snapshot = buildChannelAccountSummary({ plugin, cfg, accountId, diff --git a/src/config/io.factory.ts b/src/config/io.factory.ts index 32808ca4843a..4b65cdf73a1f 100644 --- a/src/config/io.factory.ts +++ b/src/config/io.factory.ts @@ -1,9 +1,9 @@ import { createConfigIoContext } from "./io.context.js"; import { loadConfigFromContext } from "./io.load.js"; import { - preserveConfigSnapshotAsClobbered, - promoteConfigSnapshotToLastKnownGood, - recoverConfigFromLastKnownGood, + preserveConfigSnapshotAsClobberedCore, + promoteConfigSnapshotToLastKnownGoodCore, + recoverConfigFromLastKnownGoodCore, } from "./io.observe-recovery.js"; import { recoverConfigFromJsonRootSuffixWithContext } from "./io.recovery.js"; import { @@ -36,20 +36,20 @@ export function createConfigIO(options: ConfigIoFactoryOptions = {}) { readConfigFileSnapshotWithPluginMetadataFromContext(context, readOptions), readConfigFileSnapshotForWrite: () => readConfigFileSnapshotForWriteFromContext(context), promoteConfigSnapshotToLastKnownGood: (snapshot: ConfigFileSnapshot) => - promoteConfigSnapshotToLastKnownGood({ + promoteConfigSnapshotToLastKnownGoodCore({ deps: context.deps, snapshot, logger: context.deps.logger, }), recoverConfigFromLastKnownGood: (params: { snapshot: ConfigFileSnapshot; reason: string }) => - recoverConfigFromLastKnownGood({ + recoverConfigFromLastKnownGoodCore({ deps: context.deps, snapshot: params.snapshot, reason: params.reason, prepareCandidate: context.prepareRecoveryBackupCandidate, }), preserveConfigSnapshotAsClobbered: (snapshot: ConfigFileSnapshot) => - preserveConfigSnapshotAsClobbered({ deps: context.deps, snapshot }), + preserveConfigSnapshotAsClobberedCore({ deps: context.deps, snapshot }), recoverConfigFromJsonRootSuffix: (snapshot: ConfigFileSnapshot) => recoverConfigFromJsonRootSuffixWithContext(context, snapshot), writeConfigFile: ( diff --git a/src/config/io.observe-recovery.test.ts b/src/config/io.observe-recovery.test.ts index 738d05ae0966..5fec1d05e7fe 100644 --- a/src/config/io.observe-recovery.test.ts +++ b/src/config/io.observe-recovery.test.ts @@ -16,8 +16,8 @@ import { createConfigIO } from "./io.js"; import { maybeRecoverSuspiciousConfigRead, maybeRecoverSuspiciousConfigReadSync, - promoteConfigSnapshotToLastKnownGood, - recoverConfigFromLastKnownGood, + promoteConfigSnapshotToLastKnownGoodCore, + recoverConfigFromLastKnownGoodCore, } from "./io.observe-recovery.js"; import type { ConfigFileSnapshot } from "./types.js"; @@ -866,7 +866,7 @@ describe("config observe recovery", () => { await withSuiteHome(async (home) => { const { deps, configPath, auditPath } = makeDeps(home); const snapshot = await makeSnapshot(configPath, recoverableTelegramConfig); - await promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }); + await promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }); await fsp.writeFile( `${configPath}.bak`, `${JSON.stringify({ meta: { lastTouchedVersion: "2026.4.22" } })}\n`, @@ -1174,7 +1174,7 @@ describe("config observe recovery", () => { const snapshot = await makeSnapshot(configPath, recoverableTelegramConfig); await expect( - promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }), ).resolves.toBe(true); await expectPathMissing(path.join(home, ".openclaw", "logs", "config-health.json")); @@ -1216,7 +1216,7 @@ describe("config observe recovery", () => { }); await expect( - promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }), ).resolves.toBe(true); await expect(fsp.readFile(resolveLastKnownGoodConfigPath(configPath), "utf-8")).resolves.toBe( snapshot.raw, @@ -1224,7 +1224,7 @@ describe("config observe recovery", () => { const brokenRaw = "{ gateway: { mode: 123 } }\n"; await fsp.writeFile(configPath, brokenRaw, "utf-8"); - const restored = await recoverConfigFromLastKnownGood({ + const restored = await recoverConfigFromLastKnownGoodCore({ deps, snapshot: { ...snapshot, @@ -1254,12 +1254,12 @@ describe("config observe recovery", () => { gateway: { mode: "local" }, }); await expect( - promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }), ).resolves.toBe(true); const brokenRaw = "{ gateway: { mode: 123 } }\n"; await fsp.writeFile(configPath, brokenRaw, "utf-8"); - const restored = await recoverConfigFromLastKnownGood({ + const restored = await recoverConfigFromLastKnownGoodCore({ deps, snapshot: { ...snapshot, @@ -1289,7 +1289,7 @@ describe("config observe recovery", () => { const lastGoodPath = resolveLastKnownGoodConfigPath(configPath); await expect( - promoteConfigSnapshotToLastKnownGood({ + promoteConfigSnapshotToLastKnownGoodCore({ deps: withAsyncChmodFailure(deps, lastGoodPath), snapshot, logger: deps.logger, @@ -1311,13 +1311,13 @@ describe("config observe recovery", () => { channels: { discord: { enabled: true, dmPolicy: "pairing" } }, }); await expect( - promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }), ).resolves.toBe(true); const brokenRaw = "{ gateway: { mode: 123 } }\n"; await fsp.writeFile(configPath, brokenRaw, "utf-8"); await expect( - recoverConfigFromLastKnownGood({ + recoverConfigFromLastKnownGoodCore({ deps: withAsyncChmodFailure(deps, configPath), snapshot: { ...snapshot, @@ -1395,14 +1395,14 @@ describe("config observe recovery", () => { const { deps, configPath, warn } = makeDeps(home); const staleSnapshot = await makeSnapshot(configPath, staleConfig); await expect( - promoteConfigSnapshotToLastKnownGood({ + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot: staleSnapshot, logger: deps.logger, }), ).resolves.toBe(true); const active = await writeConfigRaw(configPath, activeConfig); - const restored = await recoverConfigFromLastKnownGood({ + const restored = await recoverConfigFromLastKnownGoodCore({ deps, snapshot: { ...staleSnapshot, ...active, valid: false, issues: [issue] }, reason: "reload-invalid-config", @@ -1427,7 +1427,7 @@ describe("config observe recovery", () => { }); await expect( - promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + promoteConfigSnapshotToLastKnownGoodCore({ deps, snapshot, logger: deps.logger }), ).resolves.toBe(false); await expectPathMissing(resolveLastKnownGoodConfigPath(configPath)); expectWarnContaining(warn, "Config last-known-good promotion skipped"); diff --git a/src/config/io.observe-recovery.ts b/src/config/io.observe-recovery.ts index 89ce7ea0e4a3..402cc67ba0bf 100644 --- a/src/config/io.observe-recovery.ts +++ b/src/config/io.observe-recovery.ts @@ -498,7 +498,7 @@ function* recoverSuspiciousConfigRead( return preparedCandidate; } -export async function promoteConfigSnapshotToLastKnownGood(params: { +export async function promoteConfigSnapshotToLastKnownGoodCore(params: { deps: ObserveRecoveryDeps; snapshot: ConfigFileSnapshot; logger?: Pick; @@ -548,7 +548,7 @@ export async function promoteConfigSnapshotToLastKnownGood(params: { return true; } -export async function recoverConfigFromLastKnownGood(params: { +export async function recoverConfigFromLastKnownGoodCore(params: { deps: ObserveRecoveryDeps; snapshot: ConfigFileSnapshot; reason: string; @@ -611,7 +611,7 @@ export async function recoverConfigFromLastKnownGood(params: { stat, observedAt: now, }); - const clobberedPath = await preserveConfigSnapshotAsClobbered({ + const clobberedPath = await preserveConfigSnapshotAsClobberedCore({ deps, snapshot, observedAt: now, @@ -662,7 +662,7 @@ export async function recoverConfigFromLastKnownGood(params: { return true; } -export async function preserveConfigSnapshotAsClobbered(params: { +export async function preserveConfigSnapshotAsClobberedCore(params: { deps: ObserveRecoveryDeps; snapshot: ConfigFileSnapshot; observedAt?: string; diff --git a/src/cron/service/ops.test.ts b/src/cron/service/ops.test.ts index d251dec3612a..de9046f13e49 100644 --- a/src/cron/service/ops.test.ts +++ b/src/cron/service/ops.test.ts @@ -760,7 +760,7 @@ describe("cron service ops seam coverage", () => { const taskRunId = reservationOffsetMs === undefined ? tryCreateCronTaskRun({ state, job, startedAt }) - : taskExecutor.createRunningTaskRun({ + : taskExecutor.createRunningTaskRunCore({ runtime: "cron", sourceId: job.id, ownerKey: "", @@ -1334,7 +1334,7 @@ describe("cron service ops seam coverage", () => { }); const createTaskRecordSpy = vi - .spyOn(taskExecutor, "createRunningTaskRun") + .spyOn(taskExecutor, "createRunningTaskRunCore") .mockImplementation(() => { throw new Error("disk full"); }); @@ -1357,7 +1357,7 @@ describe("cron service ops seam coverage", () => { await writeDueIsolatedJobSnapshot(storePath, now); const updateTaskRecordSpy = vi - .spyOn(taskExecutor, "finalizeTaskRunByRunId") + .spyOn(taskExecutor, "finalizeTaskRunByRunIdCore") .mockImplementation(() => { throw new Error("disk full"); }); diff --git a/src/cron/service/task-runs.test.ts b/src/cron/service/task-runs.test.ts index b8dfc03199e5..c597a4007ea1 100644 --- a/src/cron/service/task-runs.test.ts +++ b/src/cron/service/task-runs.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js"; import * as taskExecutor from "../../tasks/task-executor.js"; -import { finalizeTaskRunByRunId } from "../../tasks/task-executor.js"; +import { finalizeTaskRunByRunIdCore } from "../../tasks/task-executor.js"; import * as taskRegistry from "../../tasks/task-registry.js"; import { markTaskLostById } from "../../tasks/task-registry.js"; import { listTaskRegistryRecordsByRuntimeSourceIdFromSqlite } from "../../tasks/task-registry.store.sqlite.js"; @@ -584,7 +584,7 @@ describe("cron task run terminal records", () => { if (!taskRunId) { throw new Error("expected cron task run id"); } - finalizeTaskRunByRunId({ + finalizeTaskRunByRunIdCore({ runId: taskRunId, runtime: "cron", status: "cancelled", @@ -664,8 +664,8 @@ describe("cron task run terminal records", () => { if (!taskRunId) { throw new Error("expected cron task run id"); } - const finalize = taskExecutor.finalizeTaskRunByRunId; - vi.spyOn(taskExecutor, "finalizeTaskRunByRunId") + const finalize = taskExecutor.finalizeTaskRunByRunIdCore; + vi.spyOn(taskExecutor, "finalizeTaskRunByRunIdCore") .mockReturnValueOnce([]) .mockImplementation((params) => finalize(params)); @@ -929,7 +929,7 @@ describe("cron task run terminal records", () => { }); const legacyRunId = `cron:legacy-job:${startedAt}`; // Older releases persisted the reservation id without a uniqueness suffix. - taskExecutor.createRunningTaskRun({ + taskExecutor.createRunningTaskRunCore({ runtime: "cron", sourceId: "legacy-job", ownerKey: "", @@ -941,7 +941,7 @@ describe("cron task run terminal records", () => { startedAt, }); expect(tryFindCronTaskRunIdForRecovery(state, "legacy-job", startedAt)).toBe(legacyRunId); - finalizeTaskRunByRunId({ + finalizeTaskRunByRunIdCore({ runId: legacyRunId, runtime: "cron", status: "timed_out", diff --git a/src/cron/service/task-runs.ts b/src/cron/service/task-runs.ts index 48d6dc872481..8aaf2da116bd 100644 --- a/src/cron/service/task-runs.ts +++ b/src/cron/service/task-runs.ts @@ -18,12 +18,12 @@ function resolveCurrentDefaultAgentId(state: CronServiceState): string | undefin } import { CRON_TASK_KIND } from "../../tasks/cron-task-contract.js"; import { - createRunningTaskRun, + createRunningTaskRunCore, finalizeTaskRunById, - finalizeTaskRunByRunId, + finalizeTaskRunByRunIdCore, findTaskByRunId, listTaskRecordsUnsorted, - recordTaskRunProgressByRunId, + recordTaskRunProgressByRunIdCore, } from "../../tasks/task-executor.js"; import type { JsonValue, TaskRecord, TaskStatus } from "../../tasks/task-registry.types.js"; import { createCronExecutionId } from "../run-id.js"; @@ -105,7 +105,7 @@ export function tryUpdateCronTaskRunSession( return; } try { - const updated = recordTaskRunProgressByRunId({ + const updated = recordTaskRunProgressByRunIdCore({ runId: taskRunId, runtime: "cron", childSessionKey, @@ -249,7 +249,7 @@ function tryCreateCronTaskRunRecord(params: { const effectiveJobAgentId = params.job ? resolveCronJobEffectiveAgentId(params.job, resolveCurrentDefaultAgentId(params.state)) : undefined; - const task = createRunningTaskRun({ + const task = createRunningTaskRunCore({ runtime: "cron", taskKind: CRON_TASK_KIND, sourceId: params.jobId, @@ -310,7 +310,7 @@ export function tryFinishCronTaskRunWithoutHistory( } const error = result.status === "error" ? normalizeCronRunErrorText(result.error) : undefined; try { - finalizeTaskRunByRunId({ + finalizeTaskRunByRunIdCore({ runId: result.taskRunId, runtime: "cron", status: @@ -383,7 +383,7 @@ export function tryFinishCronTaskRun( "succeeded" | "failed" | "timed_out" | "cancelled" > = cronRunStatusToTaskStatus(entry), ) => - finalizeTaskRunByRunId({ + finalizeTaskRunByRunIdCore({ runId, runtime: "cron", status, diff --git a/src/cron/service/timer.test.ts b/src/cron/service/timer.test.ts index f87929faa5bd..3aea905e8486 100644 --- a/src/cron/service/timer.test.ts +++ b/src/cron/service/timer.test.ts @@ -323,7 +323,7 @@ describe("cron service timer seam coverage", () => { let terminalStatePersisted = false; let finalizedAfterPersist = false; const save = cronStoreModule.saveCronJobsStore; - const finalize = taskExecutor.finalizeTaskRunByRunId; + const finalize = taskExecutor.finalizeTaskRunByRunIdCore; const saveSpy = vi .spyOn(cronStoreModule, "saveCronJobsStore") .mockImplementation(async (...args) => { @@ -337,7 +337,7 @@ describe("cron service timer seam coverage", () => { } }); const finalizeSpy = vi - .spyOn(taskExecutor, "finalizeTaskRunByRunId") + .spyOn(taskExecutor, "finalizeTaskRunByRunIdCore") .mockImplementation((params) => { finalizedAfterPersist = terminalStatePersisted; return finalize(params); @@ -800,7 +800,7 @@ describe("cron service timer seam coverage", () => { }); const createTaskRecordSpy = vi - .spyOn(taskExecutor, "createRunningTaskRun") + .spyOn(taskExecutor, "createRunningTaskRunCore") .mockImplementation(() => { throw ledgerError; }); diff --git a/src/gateway/gateway-cli-backend.live-helpers.ts b/src/gateway/gateway-cli-backend.live-helpers.ts index 285b0ec7d665..44c3c9ee5db5 100644 --- a/src/gateway/gateway-cli-backend.live-helpers.ts +++ b/src/gateway/gateway-cli-backend.live-helpers.ts @@ -317,7 +317,7 @@ export function withClaudeMcpConfigOverrides(args: string[], mcpConfigPath: stri return next; } -export async function getFreeGatewayPort(): Promise { +export async function getCliBackendPortBlock(): Promise { return await getFreePortBlockWithPermissionFallback({ offsets: [0, 1, 2, 4], fallbackBase: 40_000, diff --git a/src/gateway/gateway-cli-backend.live.test.ts b/src/gateway/gateway-cli-backend.live.test.ts index 8d33d1cc916c..16d61370594e 100644 --- a/src/gateway/gateway-cli-backend.live.test.ts +++ b/src/gateway/gateway-cli-backend.live.test.ts @@ -23,7 +23,7 @@ import { buildClaudeCliResumeContinuityProbe, createBootstrapWorkspace, ensurePairedTestGatewayClientIdentity, - getFreeGatewayPort, + getCliBackendPortBlock, matchesCliBackendReply, parseImageMode, parseJsonStringArray, @@ -297,7 +297,7 @@ describeLive("gateway live (cli backend)", () => { const token = `test-${randomUUID()}`; setTestEnvValue("OPENCLAW_GATEWAY_TOKEN", token); - const port = await getFreeGatewayPort(); + const port = await getCliBackendPortBlock(); logCliBackendLiveStep("env-ready", { port }); const rawModel = process.env.OPENCLAW_LIVE_CLI_BACKEND_MODEL ?? DEFAULT_MODEL; diff --git a/src/gateway/gateway-codex-bind.live.test.ts b/src/gateway/gateway-codex-bind.live.test.ts index ddbe6c56318c..560ea7088ec2 100644 --- a/src/gateway/gateway-codex-bind.live.test.ts +++ b/src/gateway/gateway-codex-bind.live.test.ts @@ -27,7 +27,7 @@ import { sleep } from "../utils.js"; import type { GatewayClient } from "./client.js"; import { connectTestGatewayClient, - getFreeGatewayPort, + getCliBackendPortBlock, } from "./gateway-cli-backend.live-helpers.js"; import { restoreLiveEnv, snapshotLiveEnv, type LiveEnvSnapshot } from "./live-env-test-helpers.js"; import { startGatewayServer } from "./server.js"; @@ -395,7 +395,7 @@ describeLive("gateway live (native Codex conversation binding)", () => { const workspace = path.join(tempRoot, "workspace"); const configPath = path.join(tempRoot, "openclaw.json"); const token = `test-${randomUUID()}`; - const port = await getFreeGatewayPort(); + const port = await getCliBackendPortBlock(); const sessionKey = "main"; const accountId = "default"; const slackUserId = `U${randomUUID().replace(/-/g, "").slice(0, 10).toUpperCase()}`; diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index addfd90c0d69..599f01a4e45e 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -4576,7 +4576,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { "OPENCLAW_LOG_LEVEL", "OPENCLAW_AGENT_DIR", ]); - const { startGatewayServer } = await import("./server.impl.js"); + const { startGatewayServerCore } = await import("./server.impl.js"); let runtimeEnv: ReturnType | undefined; let cleanupTempStateDir: string | undefined; let cleanupTempAgentDir: string | undefined; @@ -4692,7 +4692,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { `${params.label}: gateway-port`, ); server = await withGatewayLiveProbeTimeout( - startGatewayServer(port, { + startGatewayServerCore(port, { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, @@ -5734,7 +5734,7 @@ describeLive("gateway live (dev agent, profile keys)", () => { clearRuntimeConfigSnapshot(); const runtimeEnv = enterProductionEnvForLiveRun(); const previousEnv = snapshotLiveEnv(["OPENCLAW_AGENT_DIR"]); - const { startGatewayServer } = await import("./server.impl.js"); + const { startGatewayServerCore } = await import("./server.impl.js"); process.env.OPENCLAW_SKIP_CHANNELS = "1"; process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; @@ -5833,7 +5833,7 @@ describeLive("gateway live (dev agent, profile keys)", () => { "zai-fallback: gateway-port", ); server = await withGatewayLiveProbeTimeout( - startGatewayServer(port, { + startGatewayServerCore(port, { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, diff --git a/src/gateway/gateway-trajectory-export.live.test.ts b/src/gateway/gateway-trajectory-export.live.test.ts index 7e59bdbb0be3..5a8fdb1b425a 100644 --- a/src/gateway/gateway-trajectory-export.live.test.ts +++ b/src/gateway/gateway-trajectory-export.live.test.ts @@ -13,7 +13,7 @@ import { connectTestGatewayClient, createBootstrapWorkspace, ensurePairedTestGatewayClientIdentity, - getFreeGatewayPort, + getCliBackendPortBlock, } from "./gateway-cli-backend.live-helpers.js"; import { restoreLiveEnv, snapshotLiveEnv, type LiveEnvSnapshot } from "./live-env-test-helpers.js"; import { loadSessionEntry } from "./session-utils.js"; @@ -470,7 +470,7 @@ describeLive("gateway live trajectory export", () => { const { workspaceDir } = await createBootstrapWorkspace(tempDir); const configPath = path.join(tempDir, "openclaw.json"); const token = `test-${randomUUID()}`; - const port = await getFreeGatewayPort(); + const port = await getCliBackendPortBlock(); const modelKey = process.env.OPENCLAW_LIVE_CODEX_HARNESS_MODEL ?? DEFAULT_CODEX_MODEL; clearRuntimeConfigSnapshot(); diff --git a/src/gateway/gateway-wizard-cancel.e2e.test.ts b/src/gateway/gateway-wizard-cancel.e2e.test.ts index 542af27707f8..3c908bd1a24d 100644 --- a/src/gateway/gateway-wizard-cancel.e2e.test.ts +++ b/src/gateway/gateway-wizard-cancel.e2e.test.ts @@ -13,7 +13,7 @@ import { startGatewayServer } from "./server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "./test-helpers.e2e.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "./test-helpers.env.js"; @@ -77,7 +77,7 @@ describe("gateway wizard cancellation lifecycle", () => { setTestEnvValue("OPENCLAW_DISABLE_BUNDLED_PLUGINS", "1"); setTestEnvValue("OPENCLAW_TEST_MINIMAL_GATEWAY", "1"); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { bind: "loopback", auth: { mode: "token", token }, diff --git a/src/gateway/gateway.test.ts b/src/gateway/gateway.test.ts index a2c01d97ef94..6d2f6be946c1 100644 --- a/src/gateway/gateway.test.ts +++ b/src/gateway/gateway.test.ts @@ -25,7 +25,7 @@ import { connectDeviceAuthReq, disconnectGatewayClient, connectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, startGatewayWithClient, } from "./test-helpers.e2e.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "./test-helpers.env.js"; @@ -79,7 +79,7 @@ async function removeGatewayTempHome(tempHome: string): Promise { } async function startLoopbackTokenGateway(token: string) { - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { bind: "loopback", auth: { mode: "token", token }, @@ -203,7 +203,7 @@ describe("gateway e2e", () => { logging: { level: "info" }, }; await createConfigIO({ configPath }).writeConfigFile(initialConfig); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); server = await startGatewayServer(port, { bind: "loopback", controlUiEnabled: false, @@ -316,7 +316,7 @@ describe("gateway e2e", () => { authSource === "explicit-override" ? { mode: "off" as const, serviceName: "svc:startup" } : undefined; - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); server = await startGatewayServer(port, { bind: "loopback", ...(callerAuthOverride ? { auth: callerAuthOverride } : {}), @@ -432,7 +432,7 @@ describe("gateway e2e", () => { logging: { level: "info" }, }); setTestEnvValue("OPENCLAW_TEST_GATEWAY_OVERRIDE_TOKEN", oldToken); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); server = await startGatewayServer(port, { bind: "loopback", auth: { @@ -499,7 +499,7 @@ describe("gateway e2e", () => { logging: { level: "info" }, }; await configIO.writeConfigFile(initialConfig); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { bind: "lan", controlUiEnabled: false, @@ -724,7 +724,7 @@ module.exports = { clearConfigCache(); const wizardToken = nextGatewayId("wiz-token"); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { bind: "loopback", auth: { mode: "token", token: wizardToken }, @@ -805,7 +805,7 @@ module.exports = { await server.close({ reason: "wizard e2e complete" }); } - const port2 = await getFreeGatewayPort(); + const port2 = await getGatewayE2ePortBlock(); const server2 = await startGatewayServer(port2, { bind: "loopback", controlUiEnabled: false, @@ -844,7 +844,7 @@ module.exports = { minimalGateway: true, }); const wizardToken = nextGatewayId("wiz-contained-exit"); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { bind: "loopback", auth: { mode: "token", token: wizardToken }, @@ -912,7 +912,7 @@ module.exports = { minimalGateway: true, }); const wizAuth = nextGatewayId("wiz-chan"); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const channelRuns: Array = []; const server = await startGatewayServer(port, { bind: "loopback", diff --git a/src/gateway/operator-approvals-client.e2e.test.ts b/src/gateway/operator-approvals-client.e2e.test.ts index fccb23fe8dc2..509f94fdc7ca 100644 --- a/src/gateway/operator-approvals-client.e2e.test.ts +++ b/src/gateway/operator-approvals-client.e2e.test.ts @@ -22,7 +22,7 @@ import { startGatewayServer } from "./server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "./test-helpers.e2e.js"; import { configureManualGatewayBackgroundEnv, @@ -93,7 +93,7 @@ describe("operator approval gateway client e2e", () => { setTestEnvValue("OPENCLAW_STATE_DIR", stateDir); configureManualGatewayBackgroundEnv(tempHome); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const token = "approval-client-e2e-token"; const url = `ws://127.0.0.1:${port}`; setTestEnvValue("OPENCLAW_GATEWAY_PORT", String(port)); @@ -209,7 +209,7 @@ describe("operator approval gateway client e2e", () => { }); expect(requesterIdentity.deviceId).not.toBe(reviewerIdentity.deviceId); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const token = "approval-surfaces-e2e-token"; const url = `ws://127.0.0.1:${port}`; setTestEnvValue("OPENCLAW_GATEWAY_PORT", String(port)); diff --git a/src/gateway/server-methods/channels.status.test.ts b/src/gateway/server-methods/channels.status.test.ts index 115e753f37d3..b6b115618088 100644 --- a/src/gateway/server-methods/channels.status.test.ts +++ b/src/gateway/server-methods/channels.status.test.ts @@ -26,7 +26,7 @@ const mocks = vi.hoisted(() => ({ applyPluginAutoEnable: vi.fn(), listChannelPlugins: vi.fn(), buildChannelUiCatalog: vi.fn(), - buildChannelAccountSnapshot: vi.fn(), + resolveChannelAccountSnapshot: vi.fn(), getChannelActivity: vi.fn(), })); @@ -55,7 +55,7 @@ vi.mock("../../channels/plugins/catalog.js", () => ({ })); vi.mock("../../channels/plugins/status.js", () => ({ - buildChannelAccountSnapshot: mocks.buildChannelAccountSnapshot, + resolveChannelAccountSnapshot: mocks.resolveChannelAccountSnapshot, })); vi.mock("../../infra/channel-activity.js", () => ({ @@ -180,7 +180,7 @@ describe("channelsHandlers channels.status", () => { systemImages: { whatsapp: undefined }, entries: { whatsapp: { id: "whatsapp" } }, }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: true, }); @@ -201,7 +201,7 @@ describe("channelsHandlers channels.status", () => { config: {}, }); const snapshotArgs = requireRecord( - requireFirstCallArg(mocks.buildChannelAccountSnapshot), + requireFirstCallArg(mocks.resolveChannelAccountSnapshot), "snapshot args", ); expect(snapshotArgs.cfg).toBe(autoEnabledConfig); @@ -337,7 +337,7 @@ describe("channelsHandlers channels.status", () => { throw new Error("probe failed"); }); mocks.applyPluginAutoEnable.mockReturnValue({ config: autoEnabledConfig, changes: [] }); - mocks.buildChannelAccountSnapshot.mockImplementation(async ({ accountId, probe }) => ({ + mocks.resolveChannelAccountSnapshot.mockImplementation(async ({ accountId, probe }) => ({ accountId, configured: true, probe, @@ -366,7 +366,7 @@ describe("channelsHandlers channels.status", () => { createChannelPlugin({ id: "hanging", probeAccount: hangingProbe }), createChannelPlugin({ id: "healthy", probeAccount: healthyProbe }), ]); - mocks.buildChannelAccountSnapshot.mockImplementation(async ({ accountId, probe }) => ({ + mocks.resolveChannelAccountSnapshot.mockImplementation(async ({ accountId, probe }) => ({ accountId, configured: true, probe, @@ -400,7 +400,7 @@ describe("channelsHandlers channels.status", () => { it("falls back to account-derived channel summaries when summary building fails", async () => { const autoEnabledConfig = { autoEnabled: true }; mocks.applyPluginAutoEnable.mockReturnValue({ config: autoEnabledConfig, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", configured: true, }); @@ -425,7 +425,7 @@ describe("channelsHandlers channels.status", () => { it("annotates terminal-disconnect accounts with terminal-disconnect health state", async () => { mocks.applyPluginAutoEnable.mockReturnValue({ config: { autoEnabled: true }, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", enabled: true, configured: true, @@ -457,7 +457,7 @@ describe("channelsHandlers channels.status", () => { it("annotates unhealthy channel snapshots and includes event-loop health", async () => { const now = Date.now(); mocks.applyPluginAutoEnable.mockReturnValue({ config: { autoEnabled: true }, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", enabled: true, configured: true, @@ -506,7 +506,7 @@ describe("channelsHandlers channels.status", () => { it("preserves channel-authored health state when shared health is healthy", async () => { mocks.applyPluginAutoEnable.mockReturnValue({ config: { autoEnabled: true }, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", enabled: true, configured: true, @@ -522,7 +522,7 @@ describe("channelsHandlers channels.status", () => { it("preserves channel-authored conflict when recorded blocked lifecycle is unhealthy", async () => { mocks.applyPluginAutoEnable.mockReturnValue({ config: { autoEnabled: true }, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", enabled: true, configured: true, @@ -546,7 +546,7 @@ describe("channelsHandlers channels.status", () => { it("derives blocked health from recorded lifecycle", async () => { mocks.applyPluginAutoEnable.mockReturnValue({ config: { autoEnabled: true }, changes: [] }); - mocks.buildChannelAccountSnapshot.mockResolvedValue({ + mocks.resolveChannelAccountSnapshot.mockResolvedValue({ accountId: "default", enabled: true, configured: true, diff --git a/src/gateway/server-methods/channels.ts b/src/gateway/server-methods/channels.ts index 53ff1bffbd93..e129608ce914 100644 --- a/src/gateway/server-methods/channels.ts +++ b/src/gateway/server-methods/channels.ts @@ -17,7 +17,7 @@ import { listChannelPlugins, normalizeChannelId, } from "../../channels/plugins/index.js"; -import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js"; +import { resolveChannelAccountSnapshot } from "../../channels/plugins/status.js"; import type { ChannelPlugin } from "../../channels/plugins/types.plugin.js"; import type { ChannelAccountSnapshot } from "../../channels/plugins/types.public.js"; import { readConfigFileSnapshot } from "../../config/config.js"; @@ -449,7 +449,7 @@ export const channelsHandlers: GatewayRequestHandlers = { } } const runtimeSnapshot = resolveRuntimeSnapshot(channelId, accountId, defaultAccountId); - const snapshot = await buildChannelAccountSnapshot({ + const snapshot = await resolveChannelAccountSnapshot({ plugin, cfg, accountId, diff --git a/src/gateway/server-methods/plugin-approval-turn-source-routing.e2e.test.ts b/src/gateway/server-methods/plugin-approval-turn-source-routing.e2e.test.ts index 64963c0e1576..dbb6f4a957da 100644 --- a/src/gateway/server-methods/plugin-approval-turn-source-routing.e2e.test.ts +++ b/src/gateway/server-methods/plugin-approval-turn-source-routing.e2e.test.ts @@ -20,7 +20,7 @@ import { startGatewayServer } from "../server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../test-helpers.e2e.js"; import { configureManualGatewayBackgroundEnv, @@ -61,7 +61,7 @@ describe("plugin.approval.request delivery routing (real gateway)", () => { setTestEnvValue("OPENCLAW_STATE_DIR", stateDir); configureManualGatewayBackgroundEnv(tempHome); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const token = "plugin-approval-turn-source-e2e-token"; const url = `ws://127.0.0.1:${port}`; setTestEnvValue("OPENCLAW_GATEWAY_PORT", String(port)); diff --git a/src/gateway/server-methods/tasks.ts b/src/gateway/server-methods/tasks.ts index 47a487a915d7..1eedbcb8af07 100644 --- a/src/gateway/server-methods/tasks.ts +++ b/src/gateway/server-methods/tasks.ts @@ -130,9 +130,9 @@ export const tasksHandlers: GatewayRequestHandlers = { } const taskId = params.taskId; const reason = normalizeOptionalString(params.reason); - const { cancelDetachedTaskRunById } = + const { cancelDetachedTaskRunByIdCore } = await import("../../tasks/task-executor-cancel.runtime.js"); - const result = await cancelDetachedTaskRunById({ + const result = await cancelDetachedTaskRunByIdCore({ cfg: context.getRuntimeConfig(), taskId, ...(reason ? { reason } : {}), diff --git a/src/gateway/server-model-catalog.ts b/src/gateway/server-model-catalog.ts index 26b74e69cb59..4481134989f8 100644 --- a/src/gateway/server-model-catalog.ts +++ b/src/gateway/server-model-catalog.ts @@ -39,7 +39,7 @@ async function resolveLoader( } // Isolated gateway tests share process module state with lifecycle-owner tests. -export async function resetPreparedModelCatalogForTest(): Promise { +export async function resetPreparedModelCatalogStateForTest(): Promise { const [{ resetPreparedModelRuntimeSnapshotsForTest }, { resetModelCatalogBuilderCacheForTest }] = await Promise.all([ import("../agents/prepared-model-runtime.test-support.js"), diff --git a/src/gateway/server-network-runtime.e2e.test.ts b/src/gateway/server-network-runtime.e2e.test.ts index cb4796462e9e..eaf19d48f66e 100644 --- a/src/gateway/server-network-runtime.e2e.test.ts +++ b/src/gateway/server-network-runtime.e2e.test.ts @@ -10,7 +10,7 @@ import { resetAgentEventsForTest } from "../infra/agent-events.js"; import { PROXY_ENV_KEYS } from "../infra/net/proxy-env.js"; import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js"; import { startGatewayServer } from "./server.js"; -import { getFreeGatewayPort } from "./test-helpers.e2e.js"; +import { getGatewayE2ePortBlock } from "./test-helpers.e2e.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "./test-helpers.env.js"; const NETWORK_GATEWAY_ENV_KEYS = [ @@ -98,7 +98,7 @@ describe("gateway network runtime", () => { ); setTestEnvValue("OPENCLAW_CONFIG_PATH", configPath); - server = await startGatewayServer(await getFreeGatewayPort(), { + server = await startGatewayServer(await getGatewayE2ePortBlock(), { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, @@ -154,7 +154,7 @@ describe("gateway network runtime", () => { await fs.writeFile(configPath, raw, { mode: 0o600 }); setTestEnvValue("OPENCLAW_CONFIG_PATH", configPath); - server = await startGatewayServer(await getFreeGatewayPort(), { + server = await startGatewayServer(await getGatewayE2ePortBlock(), { controlUiEnabled: false, }); diff --git a/src/gateway/server-start.ts b/src/gateway/server-start.ts index 4a6d87eb2bbe..14fc094320d0 100644 --- a/src/gateway/server-start.ts +++ b/src/gateway/server-start.ts @@ -24,10 +24,9 @@ const loadWorkerPlacementStartupModule = createLazyRuntimeModule( () => import("./server-worker-placement-startup.js"), ); -export async function resetPreparedModelCatalogForTest(): Promise { - const { resetPreparedModelCatalogForTest: resetPreparedModelCatalogForTestLocal } = - await loadGatewayModelCatalogModule(); - await resetPreparedModelCatalogForTestLocal(); +export async function resetPreparedModelCatalogForTestCore(): Promise { + const { resetPreparedModelCatalogStateForTest } = await loadGatewayModelCatalogModule(); + await resetPreparedModelCatalogStateForTest(); } const loadGatewayStartupEarlyModule = createLazyRuntimeModule( @@ -102,7 +101,7 @@ async function stopTaskRegistryMaintenanceOnDemand(): Promise { stopTaskRegistryMaintenance(); } -export async function startGatewayServer( +export async function startGatewayServerCore( port = 18789, opts: GatewayServerOptions = {}, ): Promise { diff --git a/src/gateway/server-startup-copied-auth-secretref.test.ts b/src/gateway/server-startup-copied-auth-secretref.test.ts index cbee1a474949..015408e2834b 100644 --- a/src/gateway/server-startup-copied-auth-secretref.test.ts +++ b/src/gateway/server-startup-copied-auth-secretref.test.ts @@ -12,12 +12,12 @@ import { clearSecretsRuntimeSnapshot, getActiveSecretsRuntimeSnapshot, } from "../secrets/runtime.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; installGatewayTestHooks({ scope: "suite" }); describe("Gateway startup copied auth SecretRef isolation", () => { - let server: Awaited> | undefined; + let server: Awaited> | undefined; let agentDir: string | undefined; afterEach(async () => { @@ -57,7 +57,7 @@ describe("Gateway startup copied auth SecretRef isolation", () => { await writeConfigFile(config); const port = await getFreePort(); - server = await startGatewayServer(port, { auth: { mode: "none" } }); + server = await startTestGatewayServer(port, { auth: { mode: "none" } }); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); diff --git a/src/gateway/server-startup-plugin-quarantine.test.ts b/src/gateway/server-startup-plugin-quarantine.test.ts index 725d13e1b789..2d48f48e59a9 100644 --- a/src/gateway/server-startup-plugin-quarantine.test.ts +++ b/src/gateway/server-startup-plugin-quarantine.test.ts @@ -13,13 +13,13 @@ import { getFreePort, installGatewayTestHooks, setTestPluginRegistry, - startGatewayServer, + startTestGatewayServer, } from "./test-helpers.js"; installGatewayTestHooks({ scope: "suite" }); describe("Gateway startup plugin quarantine", () => { - let server: Awaited> | undefined; + let server: Awaited> | undefined; const tempDirs: string[] = []; afterEach(async () => { @@ -158,7 +158,7 @@ describe("Gateway startup plugin quarantine", () => { }); const port = await getFreePort(); - server = await startGatewayServer(port, { auth: { mode: "none" } }); + server = await startTestGatewayServer(port, { auth: { mode: "none" } }); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); diff --git a/src/gateway/server-startup-secret-owner-isolation.test.ts b/src/gateway/server-startup-secret-owner-isolation.test.ts index b033875abd03..ab75248df6fd 100644 --- a/src/gateway/server-startup-secret-owner-isolation.test.ts +++ b/src/gateway/server-startup-secret-owner-isolation.test.ts @@ -18,7 +18,7 @@ import { withEnvAsync } from "../test-utils/env.js"; import { getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, testState, } from "./test-helpers.js"; import "./server-startup-secret-diagnostics.test-support.js"; @@ -125,7 +125,7 @@ async function startVaultAclFixture() { } describe("Gateway startup SecretRef owner isolation", () => { - let server: Awaited> | undefined; + let server: Awaited> | undefined; afterEach(async () => { await server?.close(); @@ -272,7 +272,7 @@ describe("Gateway startup SecretRef owner isolation", () => { testState.gatewayAuth = undefined; const port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); @@ -435,7 +435,7 @@ describe("Gateway startup SecretRef owner isolation", () => { }); const port = await getFreePort(); - server = await startGatewayServer(port, { auth: { mode: "none" } }); + server = await startTestGatewayServer(port, { auth: { mode: "none" } }); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); @@ -508,7 +508,7 @@ describe("Gateway startup SecretRef owner isolation", () => { }); const port = await getFreePort(); - server = await startGatewayServer(port, { auth: { mode: "none" } }); + server = await startTestGatewayServer(port, { auth: { mode: "none" } }); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); @@ -582,7 +582,7 @@ describe("Gateway startup SecretRef owner isolation", () => { await writeConfig(config); const port = await getFreePort(); - server = await startGatewayServer(port, { auth: { mode: "none" } }); + server = await startTestGatewayServer(port, { auth: { mode: "none" } }); const ready = await fetch(`http://127.0.0.1:${port}/readyz`); expect(ready.status).toBe(200); @@ -631,7 +631,7 @@ describe("Gateway startup SecretRef owner isolation", () => { }); testState.gatewayAuth = undefined; - await expect(startGatewayServer(await getFreePort())).rejects.toThrow( + await expect(startTestGatewayServer(await getFreePort())).rejects.toThrow( /Startup failed: required secrets are unavailable/, ); }); diff --git a/src/gateway/server-startup-web-fetch-bind.test.ts b/src/gateway/server-startup-web-fetch-bind.test.ts index 1bf8c1d2bbf2..7b7e13cc76c4 100644 --- a/src/gateway/server-startup-web-fetch-bind.test.ts +++ b/src/gateway/server-startup-web-fetch-bind.test.ts @@ -4,7 +4,7 @@ import http from "node:http"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; import { readClientResponseBody } from "./test-http-response.js"; const webFetchProviderDiscovery = vi.hoisted(() => ({ @@ -94,7 +94,7 @@ async function writeConfig(config: OpenClawConfig): Promise { describe("gateway startup web fetch config", () => { let port: number; let previousMinimal: string | undefined; - let server: Awaited> | undefined; + let server: Awaited> | undefined; beforeAll(async () => { previousMinimal = process.env.OPENCLAW_TEST_MINIMAL_GATEWAY; @@ -122,7 +122,7 @@ describe("gateway startup web fetch config", () => { } as OpenClawConfig); port = await getFreePort(); - server = await startGatewayServer(port, { + server = await startTestGatewayServer(port, { auth: { mode: "none" }, }); }); diff --git a/src/gateway/server.agent.gateway-server-agent-a.test.ts b/src/gateway/server.agent.gateway-server-agent-a.test.ts index da59bc7881d8..870e06ad32e8 100644 --- a/src/gateway/server.agent.gateway-server-agent-a.test.ts +++ b/src/gateway/server.agent.gateway-server-agent-a.test.ts @@ -14,7 +14,7 @@ import { createDirectOutboundTestAdapter, } from "../test-utils/channel-plugins.js"; import { waitForAgentCommandCall } from "./agent-command.test-helpers.js"; -import { resetPreparedModelCatalogForTest } from "./server-model-catalog.js"; +import { resetPreparedModelCatalogStateForTest } from "./server-model-catalog.js"; import { setRegistry } from "./server.agent.gateway-server-agent.mocks.js"; import { createRegistry } from "./server.e2e-registry-helpers.js"; import { installConnectedSessionStoreGatewaySuite } from "./test-helpers.connected-session-store.js"; @@ -101,7 +101,7 @@ async function setGatewayModelCatalogForTest( testState.sessionStorePath = gatewaySuite.sessionStorePath; agentDiscoveryMock.enabled = true; agentDiscoveryMock.models = models; - await resetPreparedModelCatalogForTest(); + await resetPreparedModelCatalogStateForTest(); const [ { refreshPreparedModelRuntimeSnapshots }, { clearRuntimeConfigSnapshot, getRuntimeConfig }, diff --git a/src/gateway/server.auth.compat-baseline.test.ts b/src/gateway/server.auth.compat-baseline.test.ts index dc4c2f173641..4d240f2392b7 100644 --- a/src/gateway/server.auth.compat-baseline.test.ts +++ b/src/gateway/server.auth.compat-baseline.test.ts @@ -18,7 +18,7 @@ import { originForPort, rpcReq, restoreGatewayToken, - startGatewayServer, + startTestGatewayServer, testState, installGatewayTestHooks, } from "./server.auth.test-helpers.js"; @@ -137,7 +137,7 @@ async function expectLocalCliSharedAuthScopesPreserved( describe("gateway auth compatibility baseline", () => { describe("token mode", () => { - let server: Awaited>; + let server: Awaited>; let port = 0; let prevToken: string | undefined; @@ -146,7 +146,7 @@ describe("gateway auth compatibility baseline", () => { testState.gatewayAuth = { mode: "token", token: "secret" }; process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); }); afterAll(async () => { @@ -299,7 +299,7 @@ describe("gateway auth compatibility baseline", () => { }); describe("password mode", () => { - let server: Awaited>; + let server: Awaited>; let port = 0; let prevToken: string | undefined; @@ -308,7 +308,7 @@ describe("gateway auth compatibility baseline", () => { testState.gatewayAuth = { mode: "password", password: "secret" }; delete process.env.OPENCLAW_GATEWAY_TOKEN; port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); }); afterAll(async () => { @@ -356,7 +356,7 @@ describe("gateway auth compatibility baseline", () => { }); describe("none mode", () => { - let server: Awaited>; + let server: Awaited>; let port = 0; let prevToken: string | undefined; @@ -365,7 +365,7 @@ describe("gateway auth compatibility baseline", () => { testState.gatewayAuth = { mode: "none" }; delete process.env.OPENCLAW_GATEWAY_TOKEN; port = await getFreePort(); - server = await startGatewayServer(port, { controlUiEnabled: true }); + server = await startTestGatewayServer(port, { controlUiEnabled: true }); }); afterAll(async () => { diff --git a/src/gateway/server.auth.control-ui.suite.ts b/src/gateway/server.auth.control-ui.suite.ts index e061e01f1220..c745f4445b6f 100644 --- a/src/gateway/server.auth.control-ui.suite.ts +++ b/src/gateway/server.auth.control-ui.suite.ts @@ -22,7 +22,7 @@ import { restoreGatewayToken, rpcReq, startRateLimitedTokenServerWithPairedDeviceToken, - startGatewayServer, + startTestGatewayServer, startServer, startServerWithClient, TEST_OPERATOR_CLIENT, @@ -166,7 +166,7 @@ export function registerControlUiAndPairingSuite(): void { const withControlUiGatewayServer = async ( fn: (ctx: { port: number; - server: Awaited>; + server: Awaited>; }) => Promise, ): Promise => { return await withGatewayServer(fn, { diff --git a/src/gateway/server.auth.default-token.suite.ts b/src/gateway/server.auth.default-token.suite.ts index 8a050e267afa..7e71ba4f7152 100644 --- a/src/gateway/server.auth.default-token.suite.ts +++ b/src/gateway/server.auth.default-token.suite.ts @@ -25,7 +25,7 @@ import { resolvePreauthHandshakeTimeoutMs, rpcReq, sendRawConnectReq, - startGatewayServer, + startTestGatewayServer, TEST_OPERATOR_CLIENT, waitForWsClose, withGatewayServer, @@ -34,12 +34,12 @@ import { export function registerDefaultAuthTokenSuite(): void { describe("default auth (token)", () => { - let server: Awaited> | undefined; + let server: Awaited> | undefined; let port: number; beforeAll(async () => { port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); }); afterAll(async () => { diff --git a/src/gateway/server.auth.modes.suite.ts b/src/gateway/server.auth.modes.suite.ts index 05f736fdfe11..9357193e8eac 100644 --- a/src/gateway/server.auth.modes.suite.ts +++ b/src/gateway/server.auth.modes.suite.ts @@ -11,7 +11,7 @@ import { originForPort, rpcReq, restoreGatewayToken, - startGatewayServer, + startTestGatewayServer, testState, testTailscaleWhois, } from "./server.auth.test-helpers.js"; @@ -26,13 +26,13 @@ async function requestModels(port: number, secret: string): Promise { export function registerAuthModesSuite(): void { describe("password auth", () => { - let server: Awaited>; + let server: Awaited>; let port: number; beforeAll(async () => { testState.gatewayAuth = { mode: "password", password: "secret" }; // pragma: allowlist secret port = await getFreePort(); - server = await startGatewayServer(port, { openAiChatCompletionsEnabled: true }); + server = await startTestGatewayServer(port, { openAiChatCompletionsEnabled: true }); }); beforeEach(() => { @@ -81,7 +81,7 @@ export function registerAuthModesSuite(): void { }); describe("token auth", () => { - let server: Awaited>; + let server: Awaited>; let port: number; let prevToken: string | undefined; @@ -90,7 +90,7 @@ export function registerAuthModesSuite(): void { process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; testState.gatewayAuth = { mode: "token", token: "secret" }; port = await getFreePort(); - server = await startGatewayServer(port, { openAiChatCompletionsEnabled: true }); + server = await startTestGatewayServer(port, { openAiChatCompletionsEnabled: true }); }); beforeEach(() => { @@ -171,7 +171,7 @@ export function registerAuthModesSuite(): void { }); describe("explicit none auth", () => { - let server: Awaited>; + let server: Awaited>; let port: number; let prevToken: string | undefined; @@ -180,7 +180,7 @@ export function registerAuthModesSuite(): void { delete process.env.OPENCLAW_GATEWAY_TOKEN; testState.gatewayAuth = { mode: "none" }; port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); }); beforeEach(() => { @@ -227,7 +227,7 @@ export function registerAuthModesSuite(): void { const port = await getFreePort(); try { - await expect(startGatewayServer(port, { auth })).rejects.toThrow(testCase.expected); + await expect(startTestGatewayServer(port, { auth })).rejects.toThrow(testCase.expected); } finally { if (previous === undefined) { delete process.env[testCase.envKey]; @@ -242,7 +242,7 @@ export function registerAuthModesSuite(): void { const port = await getFreePort(); await expect( - startGatewayServer(port, { + startTestGatewayServer(port, { bind: "lan", host: "0.0.0.0", auth: { mode: "none" }, @@ -255,7 +255,7 @@ export function registerAuthModesSuite(): void { }); describe("tailscale auth", () => { - let server: Awaited>; + let server: Awaited>; let port: number; const tailscaleOrigin = "https://gateway.tailnet.ts.net"; @@ -273,7 +273,7 @@ export function registerAuthModesSuite(): void { afterWrite: { mode: "auto" }, }); port = await getFreePort(); - server = await startGatewayServer(port); + server = await startTestGatewayServer(port); }); afterAll(async () => { diff --git a/src/gateway/server.auth.test-helpers.ts b/src/gateway/server.auth.test-helpers.ts index f8edd4010b24..892543450514 100644 --- a/src/gateway/server.auth.test-helpers.ts +++ b/src/gateway/server.auth.test-helpers.ts @@ -18,7 +18,7 @@ import { installGatewayTestHooks, onceMessage, rpcReq, - startGatewayServer, + startTestGatewayServer, startServer, startServerWithClient, trackConnectChallengeNonce, @@ -393,7 +393,7 @@ export { restoreGatewayToken, rpcReq, sendRawConnectReq, - startGatewayServer, + startTestGatewayServer, startRateLimitedTokenServerWithPairedDeviceToken, startServer, startServerWithClient, diff --git a/src/gateway/server.board-generated-identity.test.ts b/src/gateway/server.board-generated-identity.test.ts index 88ac6dc21c2c..457f235e9def 100644 --- a/src/gateway/server.board-generated-identity.test.ts +++ b/src/gateway/server.board-generated-identity.test.ts @@ -11,7 +11,7 @@ import { import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js"; import { READ_SCOPE, WRITE_SCOPE } from "./method-scopes.js"; import { connectGatewayClient, disconnectGatewayClient } from "./test-helpers.e2e.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; installGatewayTestHooks({ scope: "suite" }); @@ -48,7 +48,7 @@ it( const events: string[] = []; const start = async () => { const port = await getFreePort(); - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { auth: { mode: "none" }, bind: "loopback", controlUiEnabled: false, @@ -74,10 +74,10 @@ it( timeoutMs: 30_000, }); - let firstServer: Awaited> | undefined; + let firstServer: Awaited> | undefined; let firstClient: Awaited> | undefined; let secondClient: Awaited> | undefined; - let restartedServer: Awaited> | undefined; + let restartedServer: Awaited> | undefined; let restartedClient: Awaited> | undefined; try { const first = await start(); diff --git a/src/gateway/server.context-prewarm.remote-proof.test.ts b/src/gateway/server.context-prewarm.remote-proof.test.ts index da41660bbd95..50d4c25d414b 100644 --- a/src/gateway/server.context-prewarm.remote-proof.test.ts +++ b/src/gateway/server.context-prewarm.remote-proof.test.ts @@ -11,7 +11,7 @@ import { resetContextWindowCacheForTest } from "../agents/context-runtime-state. import { resetPreparedModelRuntimeSnapshotsForTest } from "../agents/prepared-model-runtime.test-support.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { connectGatewayClient, disconnectGatewayClient } from "./test-helpers.e2e.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; installGatewayTestHooks(); @@ -35,7 +35,7 @@ describe("Gateway context cache remote proof", () => { })); const port = await getFreePort(); const token = "context-prewarm-proof-token"; - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, diff --git a/src/gateway/server.e2e-ws-harness.ts b/src/gateway/server.e2e-ws-harness.ts index b742e85d2370..b8aa09d74f41 100644 --- a/src/gateway/server.e2e-ws-harness.ts +++ b/src/gateway/server.e2e-ws-harness.ts @@ -5,7 +5,7 @@ import { captureEnv } from "../test-utils/env.js"; import { connectOk, getFreePort, - startGatewayServer, + startTestGatewayServer, trackConnectChallengeNonce, } from "./test-helpers.js"; @@ -16,7 +16,7 @@ type GatewayWsClient = { export type GatewayServerHarness = { port: number; - server: Awaited>; + server: Awaited>; openClient: (opts?: Parameters[1]) => Promise; close: () => Promise; }; @@ -27,7 +27,7 @@ export async function startGatewayServerHarness(): Promise const clients = new Set(); delete process.env.OPENCLAW_GATEWAY_TOKEN; const port = await getFreePort(); - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { auth: { mode: "none" }, bind: "loopback", controlUiEnabled: false, diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index fdbb98cef6df..8662a3de288b 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -9,4 +9,4 @@ export { type GatewayServer, type GatewayServerOptions, } from "./server-public.js"; -export { resetPreparedModelCatalogForTest, startGatewayServer } from "./server-start.js"; +export { resetPreparedModelCatalogForTestCore, startGatewayServerCore } from "./server-start.js"; diff --git a/src/gateway/server.minimal-channel-pin.test.ts b/src/gateway/server.minimal-channel-pin.test.ts index 0b7386b7b8c8..53e5973bc90d 100644 --- a/src/gateway/server.minimal-channel-pin.test.ts +++ b/src/gateway/server.minimal-channel-pin.test.ts @@ -10,7 +10,7 @@ import { } from "../plugins/runtime.js"; import { createOutboundTestPlugin } from "../test-utils/channel-plugins.js"; import { createRegistry } from "./server.e2e-registry-helpers.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; installGatewayTestHooks({ scope: "suite" }); @@ -44,7 +44,7 @@ test("minimal gateway tracks later channel registry updates", async () => { resetPluginRuntimeStateForTest(); process.env.VITEST = "1"; const port = await getFreePort(); - const server = await startGatewayServer(port); + const server = await startTestGatewayServer(port); try { expect(getChannelPlugin("whatsapp")).not.toBe(replacementPlugin); setActivePluginRegistry(replacementRegistry); diff --git a/src/gateway/server.models-voicewake-misc.test.ts b/src/gateway/server.models-voicewake-misc.test.ts index 01994df0df34..d6b825d7d424 100644 --- a/src/gateway/server.models-voicewake-misc.test.ts +++ b/src/gateway/server.models-voicewake-misc.test.ts @@ -12,7 +12,7 @@ import { createOutboundTestPlugin } from "../test-utils/channel-plugins.js"; import { withEnvAsync } from "../test-utils/env.js"; import { createTempHomeEnv } from "../test-utils/temp-home.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; -import { resetPreparedModelCatalogForTest } from "./server-model-catalog.js"; +import { resetPreparedModelCatalogStateForTest } from "./server-model-catalog.js"; import { createRegistry } from "./server.e2e-registry-helpers.js"; import { connectOk, @@ -24,7 +24,7 @@ import { resetTestPluginRegistry, setTestPluginRegistry, startConnectedServerWithClient, - startGatewayServer, + startTestGatewayServer, startServerWithClient, trackConnectChallengeNonce, } from "./test-helpers.js"; @@ -240,7 +240,7 @@ describe("gateway server models + voicewake", () => { const setAgentCatalog = async (entries: AgentCatalogFixtureEntry[]) => { agentDiscoveryMock.enabled = true; agentDiscoveryMock.models = entries; - await resetPreparedModelCatalogForTest(); + await resetPreparedModelCatalogStateForTest(); const [ { refreshPreparedModelRuntimeSnapshots }, { clearRuntimeConfigSnapshot: clearIoRuntimeConfigSnapshot, getRuntimeConfig }, @@ -739,7 +739,7 @@ describe("gateway server misc", () => { test("releases port after close", async () => { const releasePort = await getFreePort(); - const releaseServer = await startGatewayServer(releasePort); + const releaseServer = await startTestGatewayServer(releasePort); await releaseServer.close(); const probe = createServer(); diff --git a/src/gateway/server.sessions-send.test.ts b/src/gateway/server.sessions-send.test.ts index a4ae7b5a4713..9ca85a1934c8 100644 --- a/src/gateway/server.sessions-send.test.ts +++ b/src/gateway/server.sessions-send.test.ts @@ -19,7 +19,7 @@ import { agentCommand, getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, setTestPluginRegistry, testState, writeSessionStore, @@ -29,7 +29,7 @@ const { createOpenClawTools } = await import("../agents/openclaw-tools.js"); installGatewayTestHooks({ scope: "suite" }); -let server: Awaited>; +let server: Awaited>; let gatewayPort: number; const gatewayToken = "test-gateway-token-1234567890"; let envSnapshot: ReturnType; @@ -138,7 +138,7 @@ beforeAll(async () => { testState.gatewayAuth = { mode: "token", token: gatewayToken }; process.env.OPENCLAW_GATEWAY_PORT = String(gatewayPort); process.env.OPENCLAW_GATEWAY_TOKEN = gatewayToken; - server = await startGatewayServer(gatewayPort); + server = await startTestGatewayServer(gatewayPort); }); beforeEach(() => { diff --git a/src/gateway/server.shared-auth-rotation.test.ts b/src/gateway/server.shared-auth-rotation.test.ts index c30fef932985..d58d415b998a 100644 --- a/src/gateway/server.shared-auth-rotation.test.ts +++ b/src/gateway/server.shared-auth-rotation.test.ts @@ -16,7 +16,7 @@ import { getFreePort, installGatewayTestHooks, rpcReq, - startGatewayServer, + startTestGatewayServer, testState, trackConnectChallengeNonce, } from "./test-helpers.js"; @@ -250,7 +250,7 @@ async function expectIssuerMetadataPreservedOnReconnect(params: { browserClient? } describe("gateway shared auth rotation", () => { - let server: Awaited>; + let server: Awaited>; let sharedTokenRotationCase: { closed: Awaited>; ok: boolean; @@ -259,7 +259,7 @@ describe("gateway shared auth rotation", () => { beforeAll(async () => { port = await getFreePort(); testState.gatewayAuth = { mode: "token", token: OLD_TOKEN }; - server = await startGatewayServer(port, { controlUiEnabled: true }); + server = await startTestGatewayServer(port, { controlUiEnabled: true }); const ws = await openAuthenticatedGatewayWs(port, OLD_TOKEN); try { @@ -330,7 +330,7 @@ describe("gateway shared auth rotation", () => { }); describe("gateway shared auth rotation with unchanged SecretRefs", () => { - let secretRefServer: Awaited>; + let secretRefServer: Awaited>; let secretRefPort = 0; beforeAll(async () => { @@ -358,7 +358,7 @@ describe("gateway shared auth rotation with unchanged SecretRefs", () => { )}\n`, "utf-8", ); - secretRefServer = await startGatewayServer(secretRefPort, { controlUiEnabled: true }); + secretRefServer = await startTestGatewayServer(secretRefPort, { controlUiEnabled: true }); }); beforeEach(() => { diff --git a/src/gateway/server.shared-token-hot-reload.test.ts b/src/gateway/server.shared-token-hot-reload.test.ts index 6fc69508075a..4a50112b66dd 100644 --- a/src/gateway/server.shared-token-hot-reload.test.ts +++ b/src/gateway/server.shared-token-hot-reload.test.ts @@ -9,7 +9,7 @@ import { getFreePort, installGatewayTestHooks, rpcReq, - startGatewayServer, + startTestGatewayServer, testState, } from "./test-helpers.js"; @@ -20,7 +20,7 @@ const SECRET_REF_TOKEN_ID = "OPENCLAW_SHARED_TOKEN_HOT_RELOAD_SECRET_REF"; const OLD_TOKEN = "shared-token-hot-reload-old"; const NEW_TOKEN = "shared-token-hot-reload-new"; -let server: Awaited>; +let server: Awaited>; let port = 0; function buildSharedTokenReloadConfig(): Record { @@ -50,7 +50,7 @@ beforeAll(async () => { `${JSON.stringify(buildSharedTokenReloadConfig(), null, 2)}\n`, "utf-8", ); - server = await startGatewayServer(port, { controlUiEnabled: true }); + server = await startTestGatewayServer(port, { controlUiEnabled: true }); }); beforeEach(() => { diff --git a/src/gateway/server.shared-token-session-rotation.test.ts b/src/gateway/server.shared-token-session-rotation.test.ts index 851c6e9535b8..03170893259c 100644 --- a/src/gateway/server.shared-token-session-rotation.test.ts +++ b/src/gateway/server.shared-token-session-rotation.test.ts @@ -12,7 +12,7 @@ import { getFreePort, installGatewayTestHooks, rpcReq, - startGatewayServer, + startTestGatewayServer, testState, } from "./test-helpers.js"; @@ -22,7 +22,7 @@ const ORIGINAL_GATEWAY_AUTH = testState.gatewayAuth; const OLD_TOKEN = "shared-token-session-old"; const NEW_TOKEN = "shared-token-session-new"; -let server: Awaited>; +let server: Awaited>; let port = 0; let configSetRotationCase: { closed: Awaited>; @@ -55,7 +55,7 @@ beforeAll(async () => { )}\n`, "utf-8", ); - server = await startGatewayServer(port, { controlUiEnabled: true }); + server = await startTestGatewayServer(port, { controlUiEnabled: true }); const ws = await openAuthenticatedGatewayWs(port, OLD_TOKEN); try { diff --git a/src/gateway/server.startup-websocket-race.test.ts b/src/gateway/server.startup-websocket-race.test.ts index cdb656059bb7..2e0e5f7e7af8 100644 --- a/src/gateway/server.startup-websocket-race.test.ts +++ b/src/gateway/server.startup-websocket-race.test.ts @@ -3,10 +3,10 @@ import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { WebSocket } from "ws"; import { tryListenOnPort } from "../infra/ports-probe.js"; -import { getFreePort, installGatewayTestHooks, startGatewayServer } from "./test-helpers.js"; +import { getFreePort, installGatewayTestHooks, startTestGatewayServer } from "./test-helpers.js"; import { createGatewayRuntimeStateForTest } from "./test-helpers.server-runtime-state.js"; -type StartGatewayServer = typeof import("./test-helpers.js").startGatewayServer; +type StartGatewayServer = typeof import("./test-helpers.js").startTestGatewayServer; type GatewayServerForTest = Awaited>; installGatewayTestHooks({ scope: "suite" }); @@ -81,7 +81,7 @@ describe("gateway startup websocket readiness", () => { let client: WebSocket | undefined; try { const port = await getFreePort(); - server = await startGatewayServer(port, { + server = await startTestGatewayServer(port, { auth: { mode: "none" }, }); @@ -112,7 +112,7 @@ describe("gateway startup websocket readiness", () => { const clients: WebSocket[] = []; try { const port = await getFreePort(); - server = await startGatewayServer(port, { + server = await startTestGatewayServer(port, { host: "127.0.0.2", auth: { mode: "none" }, }); @@ -138,7 +138,7 @@ describe("gateway startup websocket readiness", () => { const port = await getFreePort(); await expect( - startGatewayServer(port, { + startTestGatewayServer(port, { bind: "lan", host: "192.0.2.1", auth: { mode: "token", token: "test-token" }, diff --git a/src/gateway/server.ts b/src/gateway/server.ts index dda298cba733..dfcabcd42691 100644 --- a/src/gateway/server.ts +++ b/src/gateway/server.ts @@ -29,14 +29,14 @@ async function loadServerImpl() { /** Starts the gateway server after lazily loading the full server implementation. */ export async function startGatewayServer( - ...args: Parameters -): ReturnType { + ...args: Parameters +): ReturnType { const mod = await loadServerImpl(); - return await mod.startGatewayServer(...args); + return await mod.startGatewayServerCore(...args); } /** Clears prepared model-catalog generations between tests. */ export async function resetPreparedModelCatalogForTest(): Promise { const mod = await loadServerImpl(); - await mod.resetPreparedModelCatalogForTest(); + await mod.resetPreparedModelCatalogForTestCore(); } diff --git a/src/gateway/server/ws-connection/authenticated-request-dispatch.server.test.ts b/src/gateway/server/ws-connection/authenticated-request-dispatch.server.test.ts index a820ce79929e..ad68a098c72b 100644 --- a/src/gateway/server/ws-connection/authenticated-request-dispatch.server.test.ts +++ b/src/gateway/server/ws-connection/authenticated-request-dispatch.server.test.ts @@ -12,7 +12,7 @@ import { getFreePort, installGatewayTestHooks, onceMessage, - startGatewayServer, + startTestGatewayServer, trackConnectChallengeNonce, } from "../../test-helpers.js"; import { @@ -289,7 +289,7 @@ describe("authenticated WebSocket request trace dispatch", () => { const token = "gateway-request-trace-test-token"; const port = await getFreePort(); - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { auth: { mode: "token", token }, bind: "loopback", controlUiEnabled: false, diff --git a/src/gateway/session-transcript-readers.ts b/src/gateway/session-transcript-readers.ts index a07b09fb5f94..fc37294701a3 100644 --- a/src/gateway/session-transcript-readers.ts +++ b/src/gateway/session-transcript-readers.ts @@ -24,7 +24,7 @@ import { ArchivedTranscriptReader, attachOpenClawTranscriptMeta, buildSessionPreviewItems, - readLatestSessionUsageFromTranscriptAsync as readLatestSessionUsageFromTranscriptAsyncFile, + readLatestSessionUsageFromTranscriptFileAsync, } from "./session-utils.fs.js"; import type { SessionPreviewItem } from "./session-utils.types.js"; @@ -433,7 +433,7 @@ export async function readLatestSessionUsageFromTranscriptAsync( path.isAbsolute(artifactFile) && artifactFile.endsWith(".jsonl") ) { - return await readLatestSessionUsageFromTranscriptAsyncFile( + return await readLatestSessionUsageFromTranscriptFileAsync( scope.sessionId, concreteStorePath, artifactFile, diff --git a/src/gateway/session-utils.fs.test.ts b/src/gateway/session-utils.fs.test.ts index 70140919368d..3e305aef9375 100644 --- a/src/gateway/session-utils.fs.test.ts +++ b/src/gateway/session-utils.fs.test.ts @@ -18,7 +18,7 @@ import { createToolSummaryPreviewTranscriptLines } from "./session-preview.test- import { ArchivedTranscriptReader, buildSessionPreviewItems, - readLatestSessionUsageFromTranscriptAsync, + readLatestSessionUsageFromTranscriptFileAsync, resolveSessionTranscriptCandidates, type ReadRecentSessionMessagesOptions, type ReadSessionMessagesAsyncOptions, @@ -1420,7 +1420,7 @@ describe("readLatestSessionUsageFromTranscript", () => { const readFileSpy = vi.spyOn(fs, "readFileSync"); try { - const snapshot = await readLatestSessionUsageFromTranscriptAsync(sessionId, storePath); + const snapshot = await readLatestSessionUsageFromTranscriptFileAsync(sessionId, storePath); expectUsageFields(snapshot, { modelProvider: "anthropic", model: "claude-sonnet-4-6", @@ -1464,12 +1464,15 @@ describe("readLatestSessionUsageFromTranscript", () => { }, }; writeTranscript(tmpDir, sessionId, [oldCumulative]); - const legacySnapshot = await readLatestSessionUsageFromTranscriptAsync(sessionId, storePath); + const legacySnapshot = await readLatestSessionUsageFromTranscriptFileAsync( + sessionId, + storePath, + ); expect(legacySnapshot?.contextUsage).toEqual({ state: "unavailable" }); expect(legacySnapshot?.totalTokens).toBeUndefined(); writeTranscript(tmpDir, sessionId, [oldCumulative, unavailable]); - const unavailableSnapshot = await readLatestSessionUsageFromTranscriptAsync( + const unavailableSnapshot = await readLatestSessionUsageFromTranscriptFileAsync( sessionId, storePath, ); @@ -1489,7 +1492,7 @@ describe("readLatestSessionUsageFromTranscript", () => { }, }, ]); - expectUsageFields(await readLatestSessionUsageFromTranscriptAsync(sessionId, storePath), { + expectUsageFields(await readLatestSessionUsageFromTranscriptFileAsync(sessionId, storePath), { totalTokens: 86_876, totalTokensFresh: true, }); @@ -1515,7 +1518,7 @@ describe("readLatestSessionUsageFromTranscript", () => { estimateStringChars(userText) + estimateStringChars(assistantText), ); - expectUsageFields(await readLatestSessionUsageFromTranscriptAsync(sessionId, storePath), { + expectUsageFields(await readLatestSessionUsageFromTranscriptFileAsync(sessionId, storePath), { modelProvider: "openai-completions", model: "local-llama", totalTokens: expectedTotalTokens, diff --git a/src/gateway/session-utils.fs.ts b/src/gateway/session-utils.fs.ts index 4d3fccc937f4..6d75fb256519 100644 --- a/src/gateway/session-utils.fs.ts +++ b/src/gateway/session-utils.fs.ts @@ -1258,7 +1258,7 @@ function extractAggregateUsageFromTranscriptLines( return snapshot; } -export async function readLatestSessionUsageFromTranscriptAsync( +export async function readLatestSessionUsageFromTranscriptFileAsync( sessionId: string, storePath: string | undefined, sessionFile?: string, diff --git a/src/gateway/test-helpers.e2e.ts b/src/gateway/test-helpers.e2e.ts index b3dc477b05f3..a4e7390e4a86 100644 --- a/src/gateway/test-helpers.e2e.ts +++ b/src/gateway/test-helpers.e2e.ts @@ -29,7 +29,7 @@ import { startGatewayServer } from "./server.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "./test-helpers.env.js"; /** Reserve a deterministic free port block for Gateway E2E tests. */ -export async function getFreeGatewayPort(): Promise { +export async function getGatewayE2ePortBlock(): Promise { return await getDeterministicFreePortBlock({ offsets: [0, 1, 2, 3, 4] }); } @@ -278,7 +278,7 @@ export async function startGatewayWithClient(params: { clearConfigCache(); clearSessionStoreCacheForTest(); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const startedServer = await startGatewayServer(port, { bind: "loopback", auth: { mode: "token", token: params.token }, diff --git a/src/gateway/test-helpers.server.ts b/src/gateway/test-helpers.server.ts index ac8ace2085d8..96ed385e6ae8 100644 --- a/src/gateway/test-helpers.server.ts +++ b/src/gateway/test-helpers.server.ts @@ -700,7 +700,7 @@ export function onceMessage( }); } -export async function startGatewayServer(port: number, opts?: GatewayServerOptions) { +export async function startTestGatewayServer(port: number, opts?: GatewayServerOptions) { // Tests mutate testState-backed config before server startup; discard earlier // helper reads so startup observes the current fixture state. resetConfigRuntimeState(); @@ -741,13 +741,13 @@ export async function startGatewayServer(port: number, opts?: GatewayServerOptio export async function startGatewayServerWithRetries(params: { port: number; opts?: GatewayServerOptions; -}): Promise<{ port: number; server: Awaited> }> { +}): Promise<{ port: number; server: Awaited> }> { let port = params.port; for (let attempt = 0; attempt < 10; attempt++) { try { return { port, - server: await startGatewayServer(port, params.opts), + server: await startTestGatewayServer(port, params.opts), }; } catch (err) { const code = (err as { cause?: { code?: string } }).cause?.code; @@ -801,7 +801,10 @@ async function openTrackedWebSocket(params: { } export async function withGatewayServer( - fn: (ctx: { port: number; server: Awaited> }) => Promise, + fn: (ctx: { + port: number; + server: Awaited>; + }) => Promise, opts?: { port?: number; serverOptions?: GatewayServerOptions }, ): Promise { const started = await startGatewayServerWithRetries({ @@ -820,7 +823,7 @@ export async function createGatewaySuiteHarness(opts?: { serverOptions?: GatewayServerOptions; }): Promise<{ port: number; - server: Awaited>; + server: Awaited>; openWs: (headers?: Record) => Promise; close: () => Promise; }> { diff --git a/src/gateway/test-helpers.ts b/src/gateway/test-helpers.ts index f7ef3f745f49..9e137e9aa9b2 100644 --- a/src/gateway/test-helpers.ts +++ b/src/gateway/test-helpers.ts @@ -25,7 +25,7 @@ export { readConnectChallengeNonce, rpcReq, startConnectedServerWithClient, - startGatewayServer, + startTestGatewayServer, startGatewayServerWithRetries, startServer, startServerWithClient, diff --git a/src/infra/channel-summary.ts b/src/infra/channel-summary.ts index 3a2090ac2306..58bd6811e677 100644 --- a/src/infra/channel-summary.ts +++ b/src/infra/channel-summary.ts @@ -3,10 +3,7 @@ import { sanitizeForLog } from "../../packages/terminal-core/src/ansi.js"; import { theme } from "../../packages/terminal-core/src/theme.js"; import { resolveInspectedChannelAccount } from "../channels/account-inspection.js"; import { hasConfiguredUnavailableCredentialStatus } from "../channels/account-snapshot-fields.js"; -import { - buildChannelAccountSnapshot, - formatChannelAllowFrom, -} from "../channels/account-summary.js"; +import { buildChannelAccountSummary, formatChannelAllowFrom } from "../channels/account-summary.js"; import { formatChannelStatusState } from "../channels/plugins/status-state.js"; import type { ChannelPlugin } from "../channels/plugins/types.plugin.js"; import type { ChannelAccountSnapshot } from "../channels/plugins/types.public.js"; @@ -147,7 +144,7 @@ export async function buildChannelSummary( sourceConfig, accountId, }); - const snapshot = buildChannelAccountSnapshot({ + const snapshot = buildChannelAccountSummary({ plugin, account, cfg: effective, diff --git a/src/infra/provider-usage.fetch.shared.ts b/src/infra/provider-usage.fetch.shared.ts index 7e1494118dbb..11fe36777f86 100644 --- a/src/infra/provider-usage.fetch.shared.ts +++ b/src/infra/provider-usage.fetch.shared.ts @@ -5,7 +5,7 @@ import { } from "@openclaw/normalization-core/number-coercion"; import { readProviderJsonResponse } from "../agents/provider-http-errors.js"; import { parseFiniteNumber as parseFiniteNumberish } from "./parse-finite-number.js"; -import { resolveProviderUsageDisplayName } from "./provider-usage.shared.js"; +import { providerUsageLabel } from "./provider-usage.shared.js"; import type { ProviderUsageSnapshot, UsageProviderId } from "./provider-usage.types.js"; /** Fetches JSON-compatible provider usage endpoints with an abort timeout. */ @@ -49,7 +49,7 @@ export function buildUsageErrorSnapshot( ): ProviderUsageSnapshot { return { provider, - displayName: resolveProviderUsageDisplayName(provider), + displayName: providerUsageLabel(provider) ?? provider, windows: [], error, }; diff --git a/src/infra/provider-usage.load.ts b/src/infra/provider-usage.load.ts index cb608ffdeeb6..5175ed59fad9 100644 --- a/src/infra/provider-usage.load.ts +++ b/src/infra/provider-usage.load.ts @@ -9,9 +9,9 @@ import { resolveFetch } from "./fetch.js"; import { resolveProxyFetchFromEnv } from "./net/proxy-fetch.js"; import { type ProviderAuth, resolveProviderAuths } from "./provider-usage.auth.js"; import { - DEFAULT_TIMEOUT_MS, + PROVIDER_USAGE_TIMEOUT_MS, ignoredErrors, - resolveProviderUsageDisplayName, + providerUsageLabel, withTimeout, } from "./provider-usage.shared.js"; import type { @@ -30,7 +30,7 @@ async function fetchProviderUsageSnapshotFallback(params: { void params.fetchFn; return { provider: params.auth.provider, - displayName: resolveProviderUsageDisplayName(params.auth.provider), + displayName: providerUsageLabel(params.auth.provider) ?? params.auth.provider, windows: [], error: "Unsupported provider", }; @@ -94,7 +94,7 @@ export async function loadProviderUsageSummary( opts: UsageSummaryOptions = {}, ): Promise { const now = opts.now ?? Date.now(); - const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS; + const timeoutMs = opts.timeoutMs ?? PROVIDER_USAGE_TIMEOUT_MS; const config = opts.config ?? getRuntimeConfig(); const env = opts.env ?? process.env; const fetchFn = opts.fetch @@ -107,12 +107,12 @@ export async function loadProviderUsageSummary( const descriptors: ProviderUsagePluginDescriptor[] = opts.providers ? opts.providers.map((provider) => ({ provider, - displayName: resolveProviderUsageDisplayName(provider), + displayName: providerUsageLabel(provider) ?? provider, })) : opts.auth ? opts.auth.map((auth) => ({ provider: auth.provider, - displayName: resolveProviderUsageDisplayName(auth.provider), + displayName: providerUsageLabel(auth.provider) ?? auth.provider, })) : listProviderUsagePluginDescriptors({ config, @@ -138,7 +138,7 @@ export async function loadProviderUsageSummary( const failureSnapshot = (error: string): ProviderUsageSnapshot => ({ provider: auth.provider, displayName: - displayNames.get(auth.provider) ?? resolveProviderUsageDisplayName(auth.provider), + displayNames.get(auth.provider) ?? providerUsageLabel(auth.provider) ?? auth.provider, windows: [], error, }); @@ -156,7 +156,7 @@ export async function loadProviderUsageSummary( { provider: auth.provider, displayName: - displayNames.get(auth.provider) ?? resolveProviderUsageDisplayName(auth.provider), + displayNames.get(auth.provider) ?? providerUsageLabel(auth.provider) ?? auth.provider, windows: [], error: "Timeout", }, diff --git a/src/infra/provider-usage.shared.ts b/src/infra/provider-usage.shared.ts index 99a07b9f419f..9dd714e829d7 100644 --- a/src/infra/provider-usage.shared.ts +++ b/src/infra/provider-usage.shared.ts @@ -4,7 +4,7 @@ import { resolveTimerTimeoutMs } from "../shared/number-coercion.js"; import type { UsageProviderId } from "./provider-usage.types.js"; /** Default timeout for provider usage collection. */ -export const DEFAULT_TIMEOUT_MS = 5000; +export const PROVIDER_USAGE_TIMEOUT_MS = 5000; export const PROVIDER_LABELS = { anthropic: "Claude", @@ -27,10 +27,6 @@ export function providerUsageLabel(provider: string): string | undefined { return labels[provider]; } -export function resolveProviderUsageDisplayName(provider: string): string { - return providerUsageLabel(provider) ?? provider; -} - /** Returns true for providers whose usage endpoint is only meaningful with OAuth/token auth. */ export function isOAuthOnlyUsageProvider(provider: UsageProviderId): boolean { return provider === "openai"; diff --git a/src/infra/update-runner-command.ts b/src/infra/update-runner-command.ts index 181568511c01..6988b7de9639 100644 --- a/src/infra/update-runner-command.ts +++ b/src/infra/update-runner-command.ts @@ -9,7 +9,7 @@ import type { UpdateStepResult, } from "./update-runner-types.js"; -export const DEFAULT_TIMEOUT_MS = 20 * 60_000; +export const UPDATE_RUNNER_TIMEOUT_MS = 20 * 60_000; export const MAX_LOG_CHARS = 8000; function mergeCommandEnvironments( diff --git a/src/infra/update-runner-install-surface.ts b/src/infra/update-runner-install-surface.ts index 1ac1fabd2071..7f0cec75d623 100644 --- a/src/infra/update-runner-install-surface.ts +++ b/src/infra/update-runner-install-surface.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { uniqueStrings } from "@openclaw/normalization-core/string-normalization"; import { detectGlobalInstallManagerForRoot } from "./update-global.js"; import { resolveUpdateInstallRoot, updateInstallRootsMatch } from "./update-install-root.js"; -import { buildUpdateCommandRunner, DEFAULT_TIMEOUT_MS } from "./update-runner-command.js"; +import { buildUpdateCommandRunner, UPDATE_RUNNER_TIMEOUT_MS } from "./update-runner-command.js"; import type { CommandRunner, UpdateInstallSurface, @@ -113,7 +113,7 @@ export async function resolveUpdateInstallSurface( opts: Pick = {}, ): Promise { const { runCommand } = await buildUpdateCommandRunner(opts.runCommand); - const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS; + const timeoutMs = opts.timeoutMs ?? UPDATE_RUNNER_TIMEOUT_MS; const candidates = buildStartDirs(opts); const packageRoot = await findPackageRoot(candidates); diff --git a/src/infra/update-runner.ts b/src/infra/update-runner.ts index 292a660239d5..6cafc6fa1bce 100644 --- a/src/infra/update-runner.ts +++ b/src/infra/update-runner.ts @@ -2,7 +2,7 @@ import { readPackageVersion } from "./package-json.js"; // Runs OpenClaw package update checks, package steps, and restart handoff. import { detectGlobalInstallManagerForRoot } from "./update-global.js"; import { resolveUpdateInstallRoot, updateInstallRootsMatch } from "./update-install-root.js"; -import { buildUpdateCommandRunner, DEFAULT_TIMEOUT_MS } from "./update-runner-command.js"; +import { buildUpdateCommandRunner, UPDATE_RUNNER_TIMEOUT_MS } from "./update-runner-command.js"; import { resolveUpdateDoctorExecutionPolicy } from "./update-runner-doctor.js"; import { runGitUpdate } from "./update-runner-git.js"; import { runGlobalUpdate } from "./update-runner-global.js"; @@ -28,7 +28,7 @@ export { resolveUpdateDoctorExecutionPolicy, resolveUpdateInstallSurface }; export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise { const startedAt = Date.now(); const { defaultCommandEnv, runCommand } = await buildUpdateCommandRunner(opts.runCommand); - const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS; + const timeoutMs = opts.timeoutMs ?? UPDATE_RUNNER_TIMEOUT_MS; const candidates = buildStartDirs(opts); const pkgRoot = await findPackageRoot(candidates); diff --git a/src/media-understanding/image-runtime.ts b/src/media-understanding/image-runtime.ts index 9896b605cce8..be36cac20845 100644 --- a/src/media-understanding/image-runtime.ts +++ b/src/media-understanding/image-runtime.ts @@ -6,16 +6,18 @@ const loadImageRuntime = createLazyRuntimeModule(() => import("./image.js")); const bindImageRuntime = createLazyRuntimeMethodBinder(loadImageRuntime); /** Describes one image through the configured media runtime. */ -export const describeImageWithModel = bindImageRuntime((runtime) => runtime.describeImageWithModel); +export const describeImageWithModel = bindImageRuntime( + (runtime) => runtime.describeImageWithModelCore, +); /** Describes multiple images through the configured media runtime. */ export const describeImagesWithModel = bindImageRuntime( - (runtime) => runtime.describeImagesWithModel, + (runtime) => runtime.describeImagesWithModelCore, ); /** Describes one image after applying the runtime payload transform. */ export const describeImageWithModelPayloadTransform = bindImageRuntime( - (runtime) => runtime.describeImageWithModelPayloadTransform, + (runtime) => runtime.describeImageWithModelPayloadTransformCore, ); /** Describes multiple images after applying the runtime payload transform. */ export const describeImagesWithModelPayloadTransform = bindImageRuntime( - (runtime) => runtime.describeImagesWithModelPayloadTransform, + (runtime) => runtime.describeImagesWithModelPayloadTransformCore, ); diff --git a/src/media-understanding/image.runtime-profile.test.ts b/src/media-understanding/image.runtime-profile.test.ts index 3591c43eff2f..4807b6661130 100644 --- a/src/media-understanding/image.runtime-profile.test.ts +++ b/src/media-understanding/image.runtime-profile.test.ts @@ -176,9 +176,9 @@ vi.mock("../infra/net/fetch-guard.js", async () => { }; }); -const { describeImageWithModel } = await import("./image.js"); +const { describeImageWithModelCore } = await import("./image.js"); -describe("describeImageWithModel", () => { +describe("describeImageWithModelCore", () => { afterEach(() => { vi.useRealTimers(); vi.unstubAllEnvs(); @@ -300,7 +300,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "flash ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "google", @@ -355,7 +355,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "flash lite ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "google", @@ -415,7 +415,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "profile-scoped image ok" }], }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "github-copilot", @@ -469,7 +469,7 @@ describe("describeImageWithModel", () => { })), }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "github-copilot", @@ -554,7 +554,7 @@ describe("describeImageWithModel", () => { })), }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "github-copilot", @@ -593,7 +593,7 @@ describe("describeImageWithModel", () => { ); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "github-copilot", @@ -630,7 +630,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "A solid red square." }], }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -676,7 +676,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "ok" }], }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "agent-plan", @@ -713,7 +713,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "ok" }], }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "fake", @@ -759,7 +759,7 @@ describe("describeImageWithModel", () => { }, }; - await describeImageWithModel({ + await describeImageWithModelCore({ cfg, agentId: "vision-agent", agentDir: "/tmp/openclaw-agent", @@ -817,7 +817,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "committed runtime" }], }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: requestedCfg, agentDir: "/tmp/requested-agent", workspaceDir: "/tmp/requested-workspace", @@ -873,7 +873,7 @@ describe("describeImageWithModel", () => { createStores: () => ({ authStorage: preparedAuthStorage, modelRegistry: {} }), } as never; - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg, agentDir: "/tmp/parent-agent", workspaceDir: "/tmp/parent-workspace", diff --git a/src/media-understanding/image.runtime-timeout.test.ts b/src/media-understanding/image.runtime-timeout.test.ts index 8bdf84c6cdf0..58d09b07b44d 100644 --- a/src/media-understanding/image.runtime-timeout.test.ts +++ b/src/media-understanding/image.runtime-timeout.test.ts @@ -165,9 +165,9 @@ vi.mock("../infra/net/fetch-guard.js", async () => { }; }); -const { describeImageWithModel } = await import("./image.js"); +const { describeImageWithModelCore } = await import("./image.js"); -describe("describeImageWithModel", () => { +describe("describeImageWithModelCore", () => { afterEach(() => { vi.useRealTimers(); vi.unstubAllEnvs(); @@ -269,7 +269,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "lmstudio", @@ -305,7 +305,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "codex ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -371,7 +371,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "codex ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -412,7 +412,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "openrouter ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openrouter", @@ -465,7 +465,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "dashscope ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "qwen", @@ -584,7 +584,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "retry ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider, @@ -643,7 +643,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -675,7 +675,7 @@ describe("describeImageWithModel", () => { }); completeMock.mockImplementation(() => new Promise(() => {})); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -713,7 +713,7 @@ describe("describeImageWithModel", () => { }); completeMock.mockImplementation(() => new Promise(() => {})); const controller = new AbortController(); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -767,7 +767,7 @@ describe("describeImageWithModel", () => { ); completeMock.mockImplementation(() => new Promise(() => {})); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -801,7 +801,7 @@ describe("describeImageWithModel", () => { vi.useFakeTimers(); resolveModelAsyncMock.mockImplementationOnce(() => new Promise(() => {})); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -835,7 +835,7 @@ describe("describeImageWithModel", () => { }), ); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -880,7 +880,7 @@ describe("describeImageWithModel", () => { }), ); const controller = new AbortController(); - const result = describeImageWithModel({ + const result = describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", diff --git a/src/media-understanding/image.test.ts b/src/media-understanding/image.test.ts index 1f03f6ba9496..2a26237d8b42 100644 --- a/src/media-understanding/image.test.ts +++ b/src/media-understanding/image.test.ts @@ -175,9 +175,9 @@ vi.mock("../infra/net/fetch-guard.js", async () => { }; }); -const { describeImageWithModel, describeImagesWithModel } = await import("./image.js"); +const { describeImageWithModelCore, describeImagesWithModelCore } = await import("./image.js"); -describe("describeImageWithModel", () => { +describe("describeImageWithModelCore", () => { afterEach(() => { vi.useRealTimers(); vi.unstubAllEnvs(); @@ -278,7 +278,7 @@ describe("describeImageWithModel", () => { it("routes minimax-portal image models through the MiniMax VLM endpoint", async () => { const timeoutSpy = vi.spyOn(AbortSignal, "timeout"); const authStore = { version: 1, profiles: {} }; - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "minimax-portal", @@ -333,7 +333,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImagesWithModel({ + describeImagesWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "minimax-portal", @@ -368,7 +368,7 @@ describe("describeImageWithModel", () => { ), }); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "minimax-portal", @@ -398,7 +398,7 @@ describe("describeImageWithModel", () => { }); unwrapSecretSentinelsForProviderEgressMock.mockReturnValueOnce("test-token"); - await describeImageWithModel({ + await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "minimax-portal", @@ -439,7 +439,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "generic ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "minimax-portal", @@ -509,7 +509,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "an orange tabby cat" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "amazon-bedrock", @@ -545,7 +545,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", workspaceDir: "/tmp/openclaw-workspace", @@ -583,7 +583,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: { models: { providers: { @@ -629,7 +629,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: { models: { providers: { @@ -679,7 +679,7 @@ describe("describeImageWithModel", () => { }); await expect( - describeImageWithModel({ + describeImageWithModelCore({ cfg: { models: { providers: { @@ -724,7 +724,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "workspace ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentId: "vision-agent", agentDir: "/tmp/openclaw-agent", @@ -812,7 +812,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "normalized ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "openai", @@ -885,7 +885,7 @@ describe("describeImageWithModel", () => { const streamFn = vi.fn(() => streamResult); registerProviderStreamForModelMock.mockReturnValueOnce(streamFn); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: {}, agentDir: "/tmp/openclaw-agent", provider: "ollama", @@ -937,7 +937,7 @@ describe("describeImageWithModel", () => { content: [{ type: "text", text: "local vision ok" }], }); - const result = await describeImageWithModel({ + const result = await describeImageWithModelCore({ cfg: { models: { providers: { diff --git a/src/media-understanding/image.ts b/src/media-understanding/image.ts index 4704abfc5ab7..b1ca9145350f 100644 --- a/src/media-understanding/image.ts +++ b/src/media-understanding/image.ts @@ -600,30 +600,30 @@ function toImagesDescriptionRequest(params: ImageDescriptionRequest): ImagesDesc }; } -export async function describeImagesWithModel( +export async function describeImagesWithModelCore( params: ImagesDescriptionRequest, ): Promise { return await describeImagesWithModelInternal(params); } -export async function describeImagesWithModelPayloadTransform( +export async function describeImagesWithModelPayloadTransformCore( params: ImagesDescriptionRequest, onPayload: ProviderStreamOptions["onPayload"], ): Promise { return await describeImagesWithModelInternal(params, { onPayload }); } -export async function describeImageWithModel( +export async function describeImageWithModelCore( params: ImageDescriptionRequest, ): Promise { - return await describeImagesWithModel(toImagesDescriptionRequest(params)); + return await describeImagesWithModelCore(toImagesDescriptionRequest(params)); } -export async function describeImageWithModelPayloadTransform( +export async function describeImageWithModelPayloadTransformCore( params: ImageDescriptionRequest, onPayload: ProviderStreamOptions["onPayload"], ): Promise { - return await describeImagesWithModelPayloadTransform( + return await describeImagesWithModelPayloadTransformCore( toImagesDescriptionRequest(params), onPayload, ); diff --git a/src/plugins/install-persistence.test.ts b/src/plugins/install-persistence.test.ts index c24555d65f6e..ac98b6f8c118 100644 --- a/src/plugins/install-persistence.test.ts +++ b/src/plugins/install-persistence.test.ts @@ -14,7 +14,7 @@ import { replaceConfigFile, refreshPluginRegistry, resetPluginsCliTestState, - runtimeLogs, + pluginsCliRuntimeLogs, setInstalledPluginIndexInstallRecords, writeConfigFile, writePersistedInstalledPluginIndexInstallRecordsWithLease, @@ -37,7 +37,7 @@ function requireMockCallArg( } function expectRuntimeLogIncludes(fragment: string) { - expect(runtimeLogs.join("\n")).toContain(fragment); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(fragment); } function createManifestRecord( @@ -285,7 +285,7 @@ describe("persistPluginInstall", () => { applyPluginUninstallDirectoryRemoval.mock.invocationCallOrder[0] ?? Number.MAX_SAFE_INTEGER; const refreshOrder = refreshPluginRegistry.mock.invocationCallOrder[0] ?? 0; expect(cleanupOrder).toBeLessThan(refreshOrder); - expect(runtimeLogs.join("\n")).toContain( + expect(pluginsCliRuntimeLogs.join("\n")).toContain( "Removed previous plugin install directory: /tmp/openclaw/extensions/codex", ); }); @@ -480,16 +480,16 @@ describe("persistPluginInstall", () => { effectiveOnly: true, onlyPluginIds: ["discord"], }); - expect(runtimeLogs.join("\n")).toContain( + expect(pluginsCliRuntimeLogs.join("\n")).toContain( 'Warning: installed plugin "discord" is not the active source', ); - expect(runtimeLogs.join("\n")).toContain( + expect(pluginsCliRuntimeLogs.join("\n")).toContain( "active config source: /tmp/openclaw-upstream/extensions/discord/index.ts", ); - expect(runtimeLogs.join("\n")).toContain( + expect(pluginsCliRuntimeLogs.join("\n")).toContain( "installed npm source: /tmp/openclaw/npm/node_modules/@openclaw/discord/index.ts", ); - expect(runtimeLogs.join("\n")).toContain("openclaw plugins doctor"); + expect(pluginsCliRuntimeLogs.join("\n")).toContain("openclaw plugins doctor"); }); it("does not warn when the config-selected source is inside the npm install path", async () => { @@ -533,7 +533,7 @@ describe("persistPluginInstall", () => { }, }); - expect(runtimeLogs.join("\n")).not.toContain("is not the active source"); + expect(pluginsCliRuntimeLogs.join("\n")).not.toContain("is not the active source"); }); it("invalidates runtime cache even when registry refresh fails", async () => { diff --git a/src/plugins/install-persistence.warning-sink.test.ts b/src/plugins/install-persistence.warning-sink.test.ts index 88f12e32e0ac..7654c4eee3db 100644 --- a/src/plugins/install-persistence.warning-sink.test.ts +++ b/src/plugins/install-persistence.warning-sink.test.ts @@ -7,7 +7,7 @@ import { planPluginUninstall, refreshPluginRegistry, resetPluginsCliTestState, - runtimeLogs, + pluginsCliRuntimeLogs, setInstalledPluginIndexInstallRecords, } from "../cli/plugins-cli-test-helpers.js"; @@ -57,7 +57,7 @@ describe("plugin install persistence warning audiences", () => { expect(warn).toHaveBeenCalledExactlyOnceWith( 'Installed plugin "workboard" without enabling it because it requires configuration first. Configure it, then run `openclaw plugins enable workboard`.', ); - expect(runtimeLogs).toEqual([ + expect(pluginsCliRuntimeLogs).toEqual([ "Installed plugin: workboard", "Restart the gateway to load plugins.", ]); @@ -138,10 +138,10 @@ describe("plugin install persistence warning audiences", () => { if (audience === "terminal") { expect(warn).not.toHaveBeenCalled(); - expect(runtimeLogs.join("\n")).toContain(cleanupDetail); - expect(runtimeLogs.join("\n")).toContain(refreshDetail); - expect(runtimeLogs.join("\n")).toContain(configuredSource); - expect(runtimeLogs.join("\n")).toContain(install.installPath); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(cleanupDetail); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(refreshDetail); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(configuredSource); + expect(pluginsCliRuntimeLogs.join("\n")).toContain(install.installPath); return; } @@ -153,7 +153,7 @@ describe("plugin install persistence warning audiences", () => { expect(warnings.join("\n")).not.toContain("/private/"); expect(warnings.join("\n")).not.toContain("PRIVATE_NPM_MARKER"); expect(warnings.join("\n")).not.toContain("PRIVATE_REFRESH_MARKER"); - expect(runtimeLogs).toEqual([ + expect(pluginsCliRuntimeLogs).toEqual([ "Installed plugin: workboard", "Restart the gateway to load plugins.", ]); diff --git a/src/tasks/detached-task-runtime.ts b/src/tasks/detached-task-runtime.ts index 74e13b1a20ea..0d36a77f0568 100644 --- a/src/tasks/detached-task-runtime.ts +++ b/src/tasks/detached-task-runtime.ts @@ -11,14 +11,14 @@ import type { import { getRegisteredDetachedTaskLifecycleRuntime } from "./detached-task-runtime-state.js"; import { cancelTaskById as cancelDetachedTaskRunByIdInCore } from "./runtime-internal.js"; import { - completeTaskRunByRunId as completeTaskRunByRunIdFromExecutor, - createQueuedTaskRun as createQueuedTaskRunFromExecutor, - createRunningTaskRun as createRunningTaskRunFromExecutor, - failTaskRunByRunId as failTaskRunByRunIdFromExecutor, - finalizeTaskRunByRunId as finalizeTaskRunByRunIdFromExecutor, - recordTaskRunProgressByRunId as recordTaskRunProgressByRunIdFromExecutor, - setDetachedTaskDeliveryStatusByRunId as setDetachedTaskDeliveryStatusByRunIdFromExecutor, - startTaskRunByRunId as startTaskRunByRunIdFromExecutor, + completeTaskRunByRunIdCore, + createQueuedTaskRunCore, + createRunningTaskRunCore, + failTaskRunByRunIdCore, + finalizeTaskRunByRunIdCore, + recordTaskRunProgressByRunIdCore, + setDetachedTaskDeliveryStatusByRunIdCore, + startTaskRunByRunIdCore, } from "./task-executor.js"; import type { TaskRecord } from "./task-registry.types.js"; import { findTaskByRunIdForStatus, listTasksForSessionKeyForStatus } from "./task-status-access.js"; @@ -54,14 +54,14 @@ function findCoreTaskRun(params: DetachedTaskFindParams): TaskRecord | undefined // Default runtime keeps detached task APIs usable before plugins install custom lifecycle hooks. const DEFAULT_DETACHED_TASK_LIFECYCLE_RUNTIME: DetachedTaskLifecycleRuntime = { - createQueuedTaskRun: createQueuedTaskRunFromExecutor, - createRunningTaskRun: createRunningTaskRunFromExecutor, - startTaskRunByRunId: startTaskRunByRunIdFromExecutor, - recordTaskRunProgressByRunId: recordTaskRunProgressByRunIdFromExecutor, - finalizeTaskRunByRunId: finalizeTaskRunByRunIdFromExecutor, - completeTaskRunByRunId: completeTaskRunByRunIdFromExecutor, - failTaskRunByRunId: failTaskRunByRunIdFromExecutor, - setDetachedTaskDeliveryStatusByRunId: setDetachedTaskDeliveryStatusByRunIdFromExecutor, + createQueuedTaskRun: createQueuedTaskRunCore, + createRunningTaskRun: createRunningTaskRunCore, + startTaskRunByRunId: startTaskRunByRunIdCore, + recordTaskRunProgressByRunId: recordTaskRunProgressByRunIdCore, + finalizeTaskRunByRunId: finalizeTaskRunByRunIdCore, + completeTaskRunByRunId: completeTaskRunByRunIdCore, + failTaskRunByRunId: failTaskRunByRunIdCore, + setDetachedTaskDeliveryStatusByRunId: setDetachedTaskDeliveryStatusByRunIdCore, findTaskRun: findCoreTaskRun, cancelDetachedTaskRunById: cancelDetachedTaskRunByIdInCore, }; diff --git a/src/tasks/runtime-internal.ts b/src/tasks/runtime-internal.ts index 38db50aec46f..db50024ac7e5 100644 --- a/src/tasks/runtime-internal.ts +++ b/src/tasks/runtime-internal.ts @@ -25,7 +25,7 @@ export { deleteTaskRecordById, ensureTaskRegistryReady, findTaskByRunId, - finalizeTaskRunByRunId, + finalizeTaskRecordByRunId, getTaskById, hasActiveTaskForChildSessionKey, listFreshTasksForOwnerKey, diff --git a/src/tasks/task-executor-cancel.runtime.ts b/src/tasks/task-executor-cancel.runtime.ts index e08e5fd5881f..671a3167a613 100644 --- a/src/tasks/task-executor-cancel.runtime.ts +++ b/src/tasks/task-executor-cancel.runtime.ts @@ -8,7 +8,7 @@ import { getTaskById, } from "./runtime-internal.js"; -export async function cancelDetachedTaskRunById(params: { +export async function cancelDetachedTaskRunByIdCore(params: { cfg: OpenClawConfig; taskId: string; reason?: string; diff --git a/src/tasks/task-executor.test.ts b/src/tasks/task-executor.test.ts index 4001c4404e1a..709884ccd315 100644 --- a/src/tasks/task-executor.test.ts +++ b/src/tasks/task-executor.test.ts @@ -10,14 +10,14 @@ import { cancelFlowById, cancelFlowByIdForOwner, cancelDetachedTaskRunById, - completeTaskRunByRunId, - createQueuedTaskRun as createQueuedTaskRunOrNull, - createRunningTaskRun as createRunningTaskRunOrNull, - failTaskRunByRunId, - recordTaskRunProgressByRunId, + completeTaskRunByRunIdCore as completeTaskRunByRunId, + createQueuedTaskRunCore as createQueuedTaskRunOrNull, + createRunningTaskRunCore as createRunningTaskRunOrNull, + failTaskRunByRunIdCore as failTaskRunByRunId, + recordTaskRunProgressByRunIdCore as recordTaskRunProgressByRunId, runTaskInFlowForOwner, - setDetachedTaskDeliveryStatusByRunId, - startTaskRunByRunId, + setDetachedTaskDeliveryStatusByRunIdCore as setDetachedTaskDeliveryStatusByRunId, + startTaskRunByRunIdCore as startTaskRunByRunId, } from "./task-executor.js"; import { createManagedTaskFlow as createManagedTaskFlowOrNull, diff --git a/src/tasks/task-executor.ts b/src/tasks/task-executor.ts index b5bf1901e8e4..e66a9a9e6465 100644 --- a/src/tasks/task-executor.ts +++ b/src/tasks/task-executor.ts @@ -18,7 +18,7 @@ import { listTasksForFlowId, markTaskTerminalById as markTaskTerminalByIdInRegistry, markTaskRunningByRunId, - finalizeTaskRunByRunId as finalizeTaskRunByRunIdInRegistry, + finalizeTaskRecordByRunId, recordTaskProgressByRunId, setTaskRunDeliveryStatusByRunId, } from "./runtime-internal.js"; @@ -96,7 +96,7 @@ function ensureSingleTaskFlow(params: { } } -export function createQueuedTaskRun(params: DetachedTaskCreateParams): TaskRecord | null { +export function createQueuedTaskRunCore(params: DetachedTaskCreateParams): TaskRecord | null { const task = createTaskRecord({ ...params, status: "queued", @@ -114,7 +114,9 @@ export function getFlowTaskSummary(flowId: string): TaskRegistrySummary { return summarizeTaskRecords(listTasksForFlowId(flowId)); } -export function createRunningTaskRun(params: DetachedRunningTaskCreateParams): TaskRecord | null { +export function createRunningTaskRunCore( + params: DetachedRunningTaskCreateParams, +): TaskRecord | null { const task = createTaskRecord({ ...params, status: "running", @@ -155,7 +157,7 @@ type RunTaskInFlowParams = { progressSummary?: string | null; }; -export function startTaskRunByRunId(params: { +export function startTaskRunByRunIdCore(params: { runId: string; runtime?: TaskRuntime; sessionKey?: string; @@ -167,7 +169,7 @@ export function startTaskRunByRunId(params: { return markTaskRunningByRunId(params); } -export function recordTaskRunProgressByRunId(params: { +export function recordTaskRunProgressByRunIdCore(params: { runId: string; runtime?: TaskRuntime; sessionKey?: string; @@ -179,15 +181,15 @@ export function recordTaskRunProgressByRunId(params: { return recordTaskProgressByRunId(params); } -export function completeTaskRunByRunId(params: DetachedTaskCompleteParams) { - return finalizeTaskRunByRunId({ +export function completeTaskRunByRunIdCore(params: DetachedTaskCompleteParams) { + return finalizeTaskRunByRunIdCore({ ...params, status: "succeeded", }); } -export function finalizeTaskRunByRunId(params: DetachedTaskFinalizeParams) { - return finalizeTaskRunByRunIdInRegistry(params); +export function finalizeTaskRunByRunIdCore(params: DetachedTaskFinalizeParams) { + return finalizeTaskRecordByRunId(params); } export function finalizeTaskRunById( @@ -196,14 +198,14 @@ export function finalizeTaskRunById( return markTaskTerminalByIdInRegistry(params); } -export function failTaskRunByRunId(params: DetachedTaskFailParams) { - return finalizeTaskRunByRunId({ +export function failTaskRunByRunIdCore(params: DetachedTaskFailParams) { + return finalizeTaskRunByRunIdCore({ ...params, status: params.status ?? "failed", }); } -export function setDetachedTaskDeliveryStatusByRunId(params: { +export function setDetachedTaskDeliveryStatusByRunIdCore(params: { runId: string; runtime?: TaskRuntime; sessionKey?: string; @@ -386,13 +388,13 @@ function runTaskInFlow(params: RunTaskInFlowParams): RunTaskInFlowResult { try { task = params.status === "running" - ? createRunningTaskRun({ + ? createRunningTaskRunCore({ ...common, startedAt: params.startedAt, lastEventAt: params.lastEventAt, progressSummary: params.progressSummary, }) - : createQueuedTaskRun(common); + : createQueuedTaskRunCore(common); } catch (error) { return mapRunTaskInFlowCreateError({ error, @@ -596,5 +598,5 @@ export async function cancelDetachedTaskRunById(params: { reason?: string; }) { const runtime = await import("./task-executor-cancel.runtime.js"); - return runtime.cancelDetachedTaskRunById(params); + return runtime.cancelDetachedTaskRunByIdCore(params); } diff --git a/src/tasks/task-flow-registry.audit.test.ts b/src/tasks/task-flow-registry.audit.test.ts index fbfbd446d8c1..d8bc37069d2a 100644 --- a/src/tasks/task-flow-registry.audit.test.ts +++ b/src/tasks/task-flow-registry.audit.test.ts @@ -4,8 +4,8 @@ import { captureEnv } from "../test-utils/env.js"; import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js"; import { SUBAGENT_KILL_TASK_ERROR } from "./detached-task-runtime-contract.js"; import { - createRunningTaskRun as createRunningTaskRunOrNull, - finalizeTaskRunByRunId, + createRunningTaskRunCore as createRunningTaskRunOrNull, + finalizeTaskRunByRunIdCore as finalizeTaskRunByRunId, } from "./task-executor.js"; import { listTaskFlowAuditFindings, diff --git a/src/tasks/task-flow-registry.e2e.test.ts b/src/tasks/task-flow-registry.e2e.test.ts index 974b672f299d..c716cc6782b6 100644 --- a/src/tasks/task-flow-registry.e2e.test.ts +++ b/src/tasks/task-flow-registry.e2e.test.ts @@ -4,8 +4,8 @@ import { resetConfigRuntimeState } from "../config/config.js"; import type { RuntimeEnv } from "../runtime.js"; import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js"; import { - completeTaskRunByRunId, - createRunningTaskRun as createRunningTaskRunOrNull, + completeTaskRunByRunIdCore as completeTaskRunByRunId, + createRunningTaskRunCore as createRunningTaskRunOrNull, } from "./task-executor.js"; import { getTaskFlowByIdForOwner, listTaskFlowsForOwner } from "./task-flow-owner-access.js"; import { listTaskFlowAuditFindings } from "./task-flow-registry.audit.js"; diff --git a/src/tasks/task-flow-registry.maintenance.test.ts b/src/tasks/task-flow-registry.maintenance.test.ts index bf9286629976..a64dde86a187 100644 --- a/src/tasks/task-flow-registry.maintenance.test.ts +++ b/src/tasks/task-flow-registry.maintenance.test.ts @@ -3,7 +3,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { captureEnv } from "../test-utils/env.js"; import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js"; import { SUBAGENT_KILL_TASK_ERROR } from "./detached-task-runtime-contract.js"; -import { createRunningTaskRun as createRunningTaskRunOrNull } from "./task-executor.js"; +import { createRunningTaskRunCore as createRunningTaskRunOrNull } from "./task-executor.js"; import { createManagedTaskFlow as createManagedTaskFlowOrNull, getTaskFlowById, @@ -17,7 +17,7 @@ import { runTaskFlowRegistryMaintenance, } from "./task-flow-registry.maintenance.js"; import type { TaskFlowRecord } from "./task-flow-registry.types.js"; -import { finalizeTaskRunByRunId } from "./task-registry.js"; +import { finalizeTaskRecordByRunId } from "./task-registry.js"; import type { TaskRecord } from "./task-registry.types.js"; import { createFlowRecord as createFlowRecordOrNull, @@ -362,7 +362,7 @@ describe("task-flow-registry maintenance", () => { startedAt: 100, lastEventAt: 100, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: child.runId!, runtime: "subagent", sessionKey: child.childSessionKey, diff --git a/src/tasks/task-operations.e2e.test.ts b/src/tasks/task-operations.e2e.test.ts index e5420bd4a4a4..7555b6810126 100644 --- a/src/tasks/task-operations.e2e.test.ts +++ b/src/tasks/task-operations.e2e.test.ts @@ -18,7 +18,7 @@ import { peekSystemEvents, resetSystemEventsForTest } from "../infra/system-even import type { RuntimeEnv } from "../runtime.js"; import { closeOpenClawAgentDatabasesForTest } from "../state/openclaw-agent-db.js"; import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js"; -import { createRunningTaskRun, recordTaskRunProgressByRunId } from "./task-executor.js"; +import { createRunningTaskRunCore, recordTaskRunProgressByRunIdCore } from "./task-executor.js"; import { createTaskRecord, getTaskById, reloadTaskRegistryFromStore } from "./task-registry.js"; import { resetTaskRegistryMaintenanceRuntimeForTests, @@ -122,7 +122,7 @@ describe("task operations product boundary", () => { notifyPolicy: "silent", }); vi.setSystemTime(now - 40 * 60_000); - const stale = createRunningTaskRun({ + const stale = createRunningTaskRunCore({ runtime: "cli", requesterSessionKey: OWNER_KEY, runId: "run-a07-stale", @@ -134,7 +134,7 @@ describe("task operations product boundary", () => { vi.setSystemTime(now); vi.useRealTimers(); - const operatorTask = createRunningTaskRun({ + const operatorTask = createRunningTaskRunCore({ runtime: "cli", requesterSessionKey: OWNER_KEY, runId: "run-a07-operator", @@ -187,7 +187,7 @@ describe("task operations product boundary", () => { ]); expect(requireTask(operatorTask.taskId).notifyPolicy).toBe("state_changes"); - recordTaskRunProgressByRunId({ + recordTaskRunProgressByRunIdCore({ runId: "run-a07-operator", progressSummary: "Indexed 3 records", eventSummary: "Indexed 3 records", diff --git a/src/tasks/task-registry-cancel.ts b/src/tasks/task-registry-cancel.ts index 6a7740e31796..eba95a6ce7be 100644 --- a/src/tasks/task-registry-cancel.ts +++ b/src/tasks/task-registry-cancel.ts @@ -9,7 +9,7 @@ import { isTerminalTaskStatus } from "./task-executor-policy.js"; import { ensureLinkedTaskFlowRegistryReady } from "./task-registry-common.js"; import { maybeDeliverTaskTerminalUpdate } from "./task-registry-delivery.js"; import { updateTask } from "./task-registry-mutation.js"; -import { finalizeTaskRunByRunId, updateTaskStateByRunId } from "./task-registry-record-api.js"; +import { finalizeTaskRecordByRunId, updateTaskStateByRunId } from "./task-registry-record-api.js"; import { cloneTaskRecord } from "./task-registry-records.js"; import { ensureTaskRegistryReady, @@ -166,7 +166,7 @@ export async function cancelTaskById(params: { // Reconcile the original task scope: steer/orphan recovery may have // replaced the registry run ID without remapping durable task rows. const taskRunId = task.runId?.trim() || result.runId; - const reconciledTasks = finalizeTaskRunByRunId({ + const reconciledTasks = finalizeTaskRecordByRunId({ runId: taskRunId, runtime: "subagent", sessionKey: childSessionKey, diff --git a/src/tasks/task-registry-record-api.ts b/src/tasks/task-registry-record-api.ts index 2ae54a7adeed..06aa57f42ef1 100644 --- a/src/tasks/task-registry-record-api.ts +++ b/src/tasks/task-registry-record-api.ts @@ -482,7 +482,7 @@ export function recordTaskProgressByRunId(params: { }); } -export function finalizeTaskRunByRunId(params: { +export function finalizeTaskRecordByRunId(params: { runId: string; runtime?: TaskRuntime; sessionKey?: string; diff --git a/src/tasks/task-registry.test.ts b/src/tasks/task-registry.test.ts index bf1685ec039b..cb85da236fa6 100644 --- a/src/tasks/task-registry.test.ts +++ b/src/tasks/task-registry.test.ts @@ -36,7 +36,7 @@ import type { TaskFlowRecord } from "./task-flow-registry.types.js"; import { cancelTaskById, deleteTaskRecordById, - finalizeTaskRunByRunId, + finalizeTaskRecordByRunId, findTaskByRunId, getTaskById, isParentFlowLinkError, @@ -364,9 +364,9 @@ const cancelTask = (taskId: string) => cancelTaskById({ cfg: {} as never, taskId function finalizeSubagentTask( task: TaskRecord, - params: Omit[0], "runId" | "runtime">, + params: Omit[0], "runId" | "runtime">, ) { - return finalizeTaskRunByRunId({ runId: task.runId!, runtime: "subagent", ...params }); + return finalizeTaskRecordByRunId({ runId: task.runId!, runtime: "subagent", ...params }); } function createInMemoryTaskRegistryStore() { @@ -744,7 +744,7 @@ describe("task-registry", () => { error: SUBAGENT_KILL_TASK_ERROR, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-subagent-abort-race", runtime: "subagent", status: "succeeded", @@ -787,7 +787,7 @@ describe("task-registry", () => { error: "agent run superseded by a newer session writer", }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-subagent-superseded", runtime: "subagent", status: "succeeded", @@ -814,7 +814,7 @@ describe("task-registry", () => { startedAt: 100, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "cron:provisional:100", runtime: "cron", childSessionKey: null, @@ -988,14 +988,14 @@ describe("task-registry", () => { runId: entry.runId, task: entry.runId, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: entry.runId, runtime: entry.runtime, status: "cancelled", endedAt: 200, error: entry.error, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: entry.runId, runtime: entry.runtime, status: entry.terminalStatus, @@ -1031,7 +1031,7 @@ describe("task-registry", () => { aborted: true, }, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-timeout-then-success", runtime: "cli", status: "succeeded", @@ -1172,14 +1172,14 @@ describe("task-registry", () => { startedAt: 100, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-fail-then-success", runtime: "cli", status: "failed", endedAt: 200, error: "delivery failed", }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-fail-then-success", runtime: "cli", status: "succeeded", @@ -1214,7 +1214,7 @@ describe("task-registry", () => { endedAt: 200, }, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-success-then-fail", runtime: "cli", status: "failed", @@ -2996,7 +2996,7 @@ describe("task-registry", () => { deliveryStatus, lastEventAt: now - 60_000, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId, runtime: "acp", status, @@ -3203,7 +3203,7 @@ describe("task-registry", () => { startedAt: Date.now() - 9 * 24 * 60 * 60_000, lastEventAt: Date.now() - 8 * 24 * 60 * 60_000, }); - finalizeTaskRunByRunId({ + finalizeTaskRecordByRunId({ runId: "run-prune", runtime: "cli", status: "succeeded", diff --git a/src/tasks/task-registry.ts b/src/tasks/task-registry.ts index 547e41cfe42d..9a0a1d091cba 100644 --- a/src/tasks/task-registry.ts +++ b/src/tasks/task-registry.ts @@ -14,7 +14,7 @@ export { assertTaskCancellationReadyById, cancelTaskById } from "./task-registry export { maybeDeliverTaskTerminalUpdate } from "./task-registry-delivery.js"; export { createTaskRecord, - finalizeTaskRunByRunId, + finalizeTaskRecordByRunId, linkTaskToFlowById, markTaskLostById, markTaskRunningByRunId, diff --git a/test/e2e/qa-lab/plugins/canvas-agent-node.e2e.test.ts b/test/e2e/qa-lab/plugins/canvas-agent-node.e2e.test.ts index 7d65490e4a04..ae265eac7f30 100644 --- a/test/e2e/qa-lab/plugins/canvas-agent-node.e2e.test.ts +++ b/test/e2e/qa-lab/plugins/canvas-agent-node.e2e.test.ts @@ -14,7 +14,7 @@ import { startGatewayServer } from "../../../../src/gateway/server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../../../../src/gateway/test-helpers.e2e.js"; import { loadOrCreateDeviceIdentity } from "../../../../src/infra/device-identity.js"; import { @@ -154,7 +154,7 @@ describe("Canvas agent tool over a paired Linux node", () => { OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1", }, }); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const gatewayToken = "qa-canvas-agent-node-token"; const config: OpenClawConfig = { gateway: { diff --git a/test/e2e/qa-lab/runtime/gateway-agent-artifact-apis.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-agent-artifact-apis.e2e.test.ts index 1e0967e5e761..ef688ee72f48 100644 --- a/test/e2e/qa-lab/runtime/gateway-agent-artifact-apis.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-agent-artifact-apis.e2e.test.ts @@ -16,7 +16,7 @@ import { startGatewayServer } from "../../../../src/gateway/server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../../../../src/gateway/test-helpers.e2e.js"; import { GATEWAY_STARTUP_MUTATED_ENV_KEYS } from "../../../../src/gateway/test-helpers.env.js"; import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js"; @@ -204,7 +204,7 @@ describe("Gateway agent and artifact APIs", () => { clearConfigCache(); clearSessionStoreCacheForTest(); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); setTestEnvValue("OPENCLAW_GATEWAY_PORT", String(port)); let server = await startGatewayServer(port, { bind: "loopback", diff --git a/test/e2e/qa-lab/runtime/gateway-direct-tool-invoke.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-direct-tool-invoke.e2e.test.ts index e85dcfb3bf1e..e0b50ce43f16 100644 --- a/test/e2e/qa-lab/runtime/gateway-direct-tool-invoke.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-direct-tool-invoke.e2e.test.ts @@ -11,7 +11,7 @@ import { import { getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, testState, } from "../../../../src/gateway/test-helpers.js"; import { @@ -129,12 +129,12 @@ describe("Gateway direct tool invoke product proof", () => { ]), ); - let gateway: Awaited> | undefined; + let gateway: Awaited> | undefined; let readOnlyClient: Awaited> | undefined; let writeClient: Awaited> | undefined; try { - gateway = await startGatewayServer(port, { + gateway = await startTestGatewayServer(port, { host: "127.0.0.1", auth: { mode: "token", token: GATEWAY_TOKEN }, controlUiEnabled: false, diff --git a/test/e2e/qa-lab/runtime/gateway-exec-approvals.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-exec-approvals.e2e.test.ts index bcd230a8d693..4325e523fb37 100644 --- a/test/e2e/qa-lab/runtime/gateway-exec-approvals.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-exec-approvals.e2e.test.ts @@ -10,7 +10,7 @@ import { import { getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, } from "../../../../src/gateway/test-helpers.js"; import { loadOrCreateDeviceIdentity } from "../../../../src/infra/device-identity.js"; import { readExecApprovalsSnapshot } from "../../../../src/infra/exec-approvals.js"; @@ -43,7 +43,7 @@ describe("gateway exec approvals QA", () => { throw new Error("OPENCLAW_STATE_DIR is required for gateway QA fixtures"); } - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, diff --git a/test/e2e/qa-lab/runtime/gateway-hosted-web.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-hosted-web.e2e.test.ts index eb586743f596..d5d8e721c30f 100644 --- a/test/e2e/qa-lab/runtime/gateway-hosted-web.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-hosted-web.e2e.test.ts @@ -13,7 +13,7 @@ import { startGatewayServer } from "../../../../src/gateway/server.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../../../../src/gateway/test-helpers.e2e.js"; import { snapshotGatewayStartupEnv } from "../../../../src/gateway/test-helpers.env.js"; import { @@ -160,7 +160,7 @@ describe("Gateway hosted web surfaces", () => { async () => { clearConfigCache(); clearRuntimeConfigSnapshot(); - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const server = await startGatewayServer(port, { auth: { mode: "token", token: TOKEN }, bind: "loopback", diff --git a/test/e2e/qa-lab/runtime/gateway-http-apis.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-http-apis.e2e.test.ts index c0bacf5b5c78..c64efa2651c6 100644 --- a/test/e2e/qa-lab/runtime/gateway-http-apis.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-http-apis.e2e.test.ts @@ -10,7 +10,7 @@ import { agentCommand, getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, testState, } from "../../../../src/gateway/test-helpers.js"; import { peekSystemEventEntries } from "../../../../src/infra/system-events.js"; @@ -86,7 +86,7 @@ async function fetchJson(port: number, pathname: string, init?: RequestInit) { describe("Gateway HTTP API product proof", () => { it("serves OpenAI-compatible, tool invocation, and hook ingress APIs over TCP", async () => { const embeddingFixture = await startEmbeddingFixture(); - let gateway: Awaited> | undefined; + let gateway: Awaited> | undefined; try { const configPath = createConfigIO().configPath; @@ -123,7 +123,7 @@ describe("Gateway HTTP API product proof", () => { .mockResolvedValueOnce({ payloads: [{ text: "qa responses response" }] } as never); const port = await getFreePort(); - gateway = await startGatewayServer(port, { + gateway = await startTestGatewayServer(port, { host: "127.0.0.1", auth: { mode: "token", token: GATEWAY_TOKEN }, controlUiEnabled: false, diff --git a/test/e2e/qa-lab/runtime/gateway-plugin-approvals.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-plugin-approvals.e2e.test.ts index d10ef0570465..d32531a47bde 100644 --- a/test/e2e/qa-lab/runtime/gateway-plugin-approvals.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-plugin-approvals.e2e.test.ts @@ -11,7 +11,7 @@ import { import { getFreePort, installGatewayTestHooks, - startGatewayServer, + startTestGatewayServer, } from "../../../../src/gateway/test-helpers.js"; import { loadOrCreateDeviceIdentity } from "../../../../src/infra/device-identity.js"; import { setLoggerOverride } from "../../../../src/logging.js"; @@ -80,7 +80,7 @@ describe("gateway plugin approvals QA", () => { const port = await getFreePort(); const token = "gateway-plugin-approvals-qa-token"; const url = `ws://127.0.0.1:${port}`; - const server = await startGatewayServer(port, { + const server = await startTestGatewayServer(port, { bind: "loopback", auth: { mode: "token", token }, controlUiEnabled: false, diff --git a/test/e2e/qa-lab/runtime/gateway-usage-memory-apis.e2e.test.ts b/test/e2e/qa-lab/runtime/gateway-usage-memory-apis.e2e.test.ts index 8000a7c65ca0..7011db14081c 100644 --- a/test/e2e/qa-lab/runtime/gateway-usage-memory-apis.e2e.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-usage-memory-apis.e2e.test.ts @@ -19,7 +19,7 @@ import { loadSessionEntryReadOnly } from "../../../../src/gateway/session-utils. import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../../../../src/gateway/test-helpers.e2e.js"; import type { UsageSummary } from "../../../../src/infra/provider-usage.types.js"; import { refreshCostUsageCacheForAgent } from "../../../../src/infra/session-cost-usage-aggregation.js"; @@ -151,7 +151,7 @@ describe("gateway usage and memory APIs", () => { "projects deterministic usage and explicit memory readiness over authenticated WebSocket RPCs", { timeout: TEST_TIMEOUT_MS }, async () => { - const port = await getFreeGatewayPort(); + const port = await getGatewayE2ePortBlock(); const token = `gateway-usage-memory-${process.pid}-${process.env.VITEST_POOL_ID ?? "0"}`; const state = await createOpenClawTestState({ label: "gateway-usage-memory-apis", diff --git a/test/plugin-cron-registry-owner.e2e.test.ts b/test/plugin-cron-registry-owner.e2e.test.ts index ecd7f88b4e51..1922cf157002 100644 --- a/test/plugin-cron-registry-owner.e2e.test.ts +++ b/test/plugin-cron-registry-owner.e2e.test.ts @@ -8,7 +8,7 @@ import type { OpenClawConfig } from "../src/config/types.openclaw.js"; import { connectGatewayClient, disconnectGatewayClient, - getFreeGatewayPort, + getGatewayE2ePortBlock, } from "../src/gateway/test-helpers.e2e.js"; import { createOpenClawTestInstance, @@ -340,7 +340,7 @@ describe("plugin cron registry ownership e2e", () => { }, }, } satisfies OpenClawConfig; - const customPort = await getFreeGatewayPort(); + const customPort = await getGatewayE2ePortBlock(); const instance = await createOpenClawTestInstance({ name: "plugin-cron-registry-owner", port: customPort, diff --git a/ui/src/e2e/board-mcp-app.e2e.test.ts b/ui/src/e2e/board-mcp-app.e2e.test.ts index 74f4f9be7263..6daa2c219af3 100644 --- a/ui/src/e2e/board-mcp-app.e2e.test.ts +++ b/ui/src/e2e/board-mcp-app.e2e.test.ts @@ -3,7 +3,7 @@ import type { Server as HttpServer } from "node:http"; import { chromium, type Browser, type BrowserContext, type Page } from "playwright"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { createSandboxHostHttpServer } from "../../../src/gateway/mcp-app-sandbox-http.js"; -import { getFreeGatewayPort } from "../../../src/gateway/test-helpers.e2e.js"; +import { getGatewayE2ePortBlock } from "../../../src/gateway/test-helpers.e2e.js"; import { canRunPlaywrightChromium, controlUiBundledSettingsStorageKey, @@ -173,7 +173,7 @@ async function waitForCachedBoardFace(page: Page, face: "chat" | "dashboard"): P describeControlUiE2e("Control UI dashboard MCP Apps", () => { beforeAll(async () => { controlUi = await startControlUiE2eServer(); - sandboxPort = await getFreeGatewayPort(); + sandboxPort = await getGatewayE2ePortBlock(); sandboxServer = createSandboxHostHttpServer(); await new Promise((resolve) => { sandboxServer.listen(sandboxPort, "127.0.0.1", resolve); diff --git a/ui/src/e2e/mcp-app-conformance.e2e.test.ts b/ui/src/e2e/mcp-app-conformance.e2e.test.ts index 3c80f12e70fa..f68db49e88c4 100644 --- a/ui/src/e2e/mcp-app-conformance.e2e.test.ts +++ b/ui/src/e2e/mcp-app-conformance.e2e.test.ts @@ -28,7 +28,7 @@ import { } from "../../../src/config/config.js"; import type { OpenClawConfig } from "../../../src/config/types.openclaw.js"; import { startGatewayServer } from "../../../src/gateway/server.js"; -import { getFreeGatewayPort } from "../../../src/gateway/test-helpers.e2e.js"; +import { getGatewayE2ePortBlock } from "../../../src/gateway/test-helpers.e2e.js"; import { captureEnv, setTestEnvValue } from "../../../src/test-utils/env.js"; import { canRunPlaywrightChromium, @@ -424,7 +424,7 @@ describeConformance("MCP App Control UI and standalone host conformance", () => controlUiServer = await startControlUiE2eServer(undefined, { source: true }); const appEntryPath = require.resolve("@modelcontextprotocol/ext-apps/app-with-deps"); const appModuleSource = await fs.readFile(appEntryPath, "utf8"); - const appAssetPort = await getFreeGatewayPort(); + const appAssetPort = await getGatewayE2ePortBlock(); const fixtureAssetServer = createHttpServer((request, response) => { if (request.url !== "/app.js") { response.writeHead(404).end(); @@ -446,9 +446,9 @@ describeConformance("MCP App Control UI and standalone host conformance", () => const resourceOrigin = new URL(appModuleUrl).origin; const controlUiOrigin = new URL(controlUiServer.baseUrl).origin; await writeFixtureServer(fixturePath, appHtml(appModuleUrl), resourceOrigin); - gatewayPort = await getFreeGatewayPort(); + gatewayPort = await getGatewayE2ePortBlock(); do { - sandboxPort = await getFreeGatewayPort(); + sandboxPort = await getGatewayE2ePortBlock(); } while (sandboxPort === gatewayPort); const cfg: OpenClawConfig = { gateway: { diff --git a/ui/src/lib/chat/thinking.ts b/ui/src/lib/chat/thinking.ts index 92b81520a036..e2f6831973ae 100644 --- a/ui/src/lib/chat/thinking.ts +++ b/ui/src/lib/chat/thinking.ts @@ -1,7 +1,7 @@ import { BASE_THINKING_LEVELS, normalizeThinkLevel, - resolveThinkingDefaultForModel, + resolveThinkingDefaultForModelCore, type ThinkingCatalogEntry, } from "../../../../src/auto-reply/thinking.shared.js"; // Control UI module implements thinking behavior. @@ -104,7 +104,7 @@ export function resolveCurrentThinkingLevel( if (!provider || !model) { return "off"; } - return resolveThinkingDefaultForModel({ + return resolveThinkingDefaultForModelCore({ provider, model, catalog: models, @@ -230,7 +230,7 @@ export function resolveChatThinkingSelectState(params: { session?.thinkingDefault ?? defaultFromSessionDefaults ?? (provider && model - ? resolveThinkingDefaultForModel({ + ? resolveThinkingDefaultForModelCore({ provider, model, catalog: [...params.catalog],