diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index 2f0efde947fc..783b315bbd16 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -1,2 +1,2 @@ -5f576203a58926c97b80e2ecab7a44a2021ab487b9ecbb2365bcede01935869b plugin-sdk-api-baseline.json -674bb8dc19ddc39ed5571f38af4646ded5db3fba70eb57f33a8fd2cfe3f4d1bc plugin-sdk-api-baseline.jsonl +1a66a755b98a7d4ff29fe7ccd19cd525c41677eccf1d954b0dc7ed71902e66bf plugin-sdk-api-baseline.json +93efacdebaa86153a980ea0c1db713548aeed91ad6e76b914b899746896b1b32 plugin-sdk-api-baseline.jsonl diff --git a/scripts/plugin-sdk-surface-report.mjs b/scripts/plugin-sdk-surface-report.mjs index c6118d29349a..ebad4f710b9a 100644 --- a/scripts/plugin-sdk-surface-report.mjs +++ b/scripts/plugin-sdk-surface-report.mjs @@ -202,8 +202,8 @@ let publicDeprecatedExportsByEntrypointBudget; try { budgets = { publicEntrypoints: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_ENTRYPOINTS", 323), - publicExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS", 10405), - publicFunctionExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS", 5223), + publicExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS", 10409), + publicFunctionExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS", 5224), publicDeprecatedExports: readBudgetEnv( "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_DEPRECATED_EXPORTS", 3261, diff --git a/src/auto-reply/reply/commands-login.test.ts b/src/auto-reply/reply/commands-login.test.ts index 8cfa43fa04d1..6db3ff884e5a 100644 --- a/src/auto-reply/reply/commands-login.test.ts +++ b/src/auto-reply/reply/commands-login.test.ts @@ -1,4 +1,3 @@ -// Tests channel-native Codex login command routing and pairing-code delivery. import { beforeEach, describe, expect, it, vi } from "vitest"; import type { ModelsAuthLoginFlowOptions } from "../../commands/models/auth.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; diff --git a/src/auto-reply/reply/commands-login.ts b/src/auto-reply/reply/commands-login.ts index 6b92426784c3..9e4cc583586e 100644 --- a/src/auto-reply/reply/commands-login.ts +++ b/src/auto-reply/reply/commands-login.ts @@ -1,4 +1,3 @@ -/** Handles channel-native Codex/OpenAI login commands. */ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -29,10 +28,6 @@ function parseLoginCommand(commandBodyNormalized: string): { providerInput: stri return { providerInput }; } -function hasConfiguredCommandOwners(params: HandleCommandsParams): boolean { - return codexChannelLoginRuntime.hasConfiguredCommandOwnerAllowlist(params.cfg); -} - function hasInternalAdminScope(params: HandleCommandsParams): boolean { return ( Array.isArray(params.ctx.GatewayClientScopes) && @@ -44,7 +39,8 @@ function canStartCodexLogin(params: HandleCommandsParams): boolean { return ( params.command.isAuthorizedSender && params.command.senderIsOwner && - (hasConfiguredCommandOwners(params) || hasInternalAdminScope(params)) + (codexChannelLoginRuntime.hasConfiguredCommandOwnerAllowlist(params.cfg) || + hasInternalAdminScope(params)) ); } @@ -132,10 +128,6 @@ function resolveLoginAgentId(params: HandleCommandsParams): string | undefined { ); } -function buildFinalReply(status: string): ReplyPayload { - return { text: status }; -} - async function emitLoginMessage(params: HandleCommandsParams, text: string): Promise { const trimmed = text.trim(); if (!trimmed) { @@ -157,6 +149,12 @@ async function runChannelCodexLogin(params: { runtime?: RuntimeEnv; }): Promise { const flowKey = buildCodexLoginFlowKey(params.commandParams, params.provider); + if (!params.commandParams.opts?.onBlockReply) { + return { + text: "Codex login needs a live private response path so the code can be shown before it expires. Use the Web UI or a private chat and send `/login codex` again.", + }; + } + const reservation = codexChannelLoginRuntime.reserveFlow({ flows: activeCodexLoginFlows, flowKey, @@ -166,16 +164,6 @@ async function runChannelCodexLogin(params: { text: "A Codex login code is already active for this chat or channel. Complete it, or wait for it to expire before requesting a new one.", }; } - if (!params.commandParams.opts?.onBlockReply) { - codexChannelLoginRuntime.releaseFlow({ - flows: activeCodexLoginFlows, - flowKey, - record: reservation.record, - }); - return { - text: "Codex login needs a live private response path so the code can be shown before it expires. Use the Web UI or a private chat and send `/login codex` again.", - }; - } try { await codexChannelLoginRuntime.runDeviceLoginFlow({ @@ -188,11 +176,9 @@ async function runChannelCodexLogin(params: { unsupportedPromptMessage: "Channel /login supports only fixed Codex device-code auth.", runLoginFlow: params.runLoginFlow, }); - return buildFinalReply("Codex login complete. Try your request again now."); + return { text: "Codex login complete. Try your request again now." }; } catch { - return buildFinalReply( - "Codex login did not complete. Send `/login codex` to request a new code.", - ); + return { text: "Codex login did not complete. Send `/login codex` to request a new code." }; } finally { codexChannelLoginRuntime.releaseFlow({ flows: activeCodexLoginFlows, diff --git a/src/commands/models/auth.ts b/src/commands/models/auth.ts index 8107313b64ce..060ede3e19fd 100644 --- a/src/commands/models/auth.ts +++ b/src/commands/models/auth.ts @@ -991,7 +991,6 @@ function maybeLogOpenAICodexNativeSearchTip(runtime: RuntimeEnv, providerId: str ); } -/** Runs interactive provider auth login and persists returned profiles. */ export async function runModelsAuthLoginFlow( opts: ModelsAuthLoginFlowOptions, ): Promise { @@ -1099,7 +1098,6 @@ export async function runModelsAuthLoginFlow( }; } -/** Runs interactive provider auth login and persists returned profiles. */ export async function modelsAuthLoginCommand(opts: LoginOptions, runtime: RuntimeEnv) { if (!process.stdin.isTTY) { throw new Error( diff --git a/src/plugin-sdk/provider-auth-login-flow-runtime.ts b/src/plugin-sdk/provider-auth-login-flow-runtime.ts index 57d8efd9b516..8b25a4f605b5 100644 --- a/src/plugin-sdk/provider-auth-login-flow-runtime.ts +++ b/src/plugin-sdk/provider-auth-login-flow-runtime.ts @@ -1,4 +1,3 @@ -// Lazy runtime facade for channel-triggered provider auth login flows. import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -37,11 +36,9 @@ const bindProviderAuthLoginFlowRuntime = createLazyRuntimeMethodBinder( loadProviderAuthLoginFlowRuntime, ); -/** Runs provider login and persists returned auth profiles. Loaded lazily for channel /login. */ export const runModelsAuthLoginFlow: ProviderAuthLoginFlowRuntime["runModelsAuthLoginFlow"] = bindProviderAuthLoginFlowRuntime((runtime) => runtime.runModelsAuthLoginFlow); -/** Normalizes channel login aliases to the provider that owns Codex ChatGPT auth. */ function resolveCodexLoginProvider(rawProvider: string | undefined): string | null { const normalized = normalizeLowercaseStringOrEmpty(rawProvider ?? "codex").replace(/_/gu, "-"); if (!normalized) { @@ -50,13 +47,11 @@ function resolveCodexLoginProvider(rawProvider: string | undefined): string | nu return CODEX_LOGIN_PROVIDER_ALIASES.has(normalized) ? CODEX_LOGIN_PROVIDER : null; } -/** Checks whether command-owner login is explicitly configured. */ function hasConfiguredCommandOwnerAllowlist(cfg: OpenClawConfig): boolean { const owners = cfg.commands?.ownerAllowFrom; return Array.isArray(owners) && owners.some((owner) => normalizeOptionalString(String(owner))); } -/** Keeps a pinned auth profile only when it belongs to the requested provider. */ function resolveProviderScopedProfileId( authProfileOverride: string | undefined, provider: string, @@ -71,7 +66,6 @@ function resolveProviderScopedProfileId( : undefined; } -/** Reserves a login flow key while preserving active non-expired flow dedupe. */ function reserveCodexLoginFlow(params: { flows: Map; flowKey: string; @@ -90,7 +84,6 @@ function reserveCodexLoginFlow(params: { return { status: "reserved", record }; } -/** Releases a reserved login flow only if this caller still owns the reservation. */ function releaseCodexLoginFlow(params: { flows: Map; flowKey: string; @@ -101,7 +94,6 @@ function releaseCodexLoginFlow(params: { } } -/** Builds a fixed device-code prompter that can only emit text to the channel. */ function buildCodexDeviceLoginPrompter(params: { sendMessage: (message: string) => Promise; unsupportedPromptMessage: string; @@ -133,7 +125,6 @@ function buildCodexDeviceLoginPrompter(params: { }; } -/** Runs fixed Codex device-code login for private channel and Web UI surfaces. */ async function runCodexDeviceLoginFlow(params: { provider: string; agentId: string; @@ -160,7 +151,6 @@ async function runCodexDeviceLoginFlow(params: { }); } -/** Shared private-channel Codex login helpers for text and native command surfaces. */ export const codexChannelLoginRuntime = { resolveProvider: resolveCodexLoginProvider, hasConfiguredCommandOwnerAllowlist,