diff --git a/electron/gateway/manager.ts b/electron/gateway/manager.ts index 577e7ad37..7d23cdd77 100644 --- a/electron/gateway/manager.ts +++ b/electron/gateway/manager.ts @@ -235,8 +235,13 @@ export class GatewayManager extends EventEmitter { assertLifecycle: (phase) => { this.lifecycleController.assert(startEpoch, phase); }, - findExistingGateway: async (port, ownedPid) => { - return await findExistingGatewayProcess({ port, ownedPid }); + findExistingGateway: async (port) => { + // Always read the current process pid dynamically so that retries + // don't treat a just-spawned gateway as an orphan. The ownedPid + // snapshot captured at start() entry is stale after startProcess() + // replaces this.process — leading to the just-started pid being + // immediately killed as a false orphan on the next retry iteration. + return await findExistingGatewayProcess({ port, ownedPid: this.process?.pid }); }, connect: async (port, externalToken) => { await this.connect(port, externalToken); @@ -335,9 +340,14 @@ export class GatewayManager extends EventEmitter { } } - // Close WebSocket + // Close WebSocket — use terminate() to force-close the TCP connection + // immediately without waiting for the WebSocket close handshake. + // ws.close() sends a close frame and waits for the server to respond; + // if the gateway process is being killed concurrently, the handshake + // never completes and the connection stays ESTABLISHED indefinitely, + // accumulating leaked connections on every restart cycle. if (this.ws) { - this.ws.close(1000, 'Gateway stopped by user'); + try { this.ws.terminate(); } catch { /* ignore */ } this.ws = null; } @@ -792,7 +802,7 @@ export class GatewayManager extends EventEmitter { onMessage: (message) => { this.handleMessage(message); }, - onCloseAfterHandshake: () => { + onCloseAfterHandshake: (closeCode) => { this.connectionMonitor.clear(); if (this.status.state === 'running') { this.setStatus({ state: 'stopped' }); @@ -801,7 +811,11 @@ export class GatewayManager extends EventEmitter { // handler (`onExit`) which calls scheduleReconnect(). Triggering // reconnect from WS close as well races with the exit handler and can // cause double start() attempts or port conflicts during TCP TIME_WAIT. - if (process.platform !== 'win32') { + // + // Exception: code=1012 means the Gateway is performing an in-process + // restart (e.g. config reload). The UtilityProcess stays alive, so + // `onExit` will never fire — we MUST reconnect from the WS close path. + if (process.platform !== 'win32' || closeCode === 1012) { this.scheduleReconnect(); } } diff --git a/electron/gateway/process-launcher.ts b/electron/gateway/process-launcher.ts index b9c5e8e7d..e75254c02 100644 --- a/electron/gateway/process-launcher.ts +++ b/electron/gateway/process-launcher.ts @@ -117,6 +117,10 @@ export async function launchGatewayProcess(options: { const lastSpawnSummary = `mode=${mode}, entry="${entryScript}", args="${options.sanitizeSpawnArgs(gatewayArgs).join(' ')}", cwd="${openclawDir}"`; const runtimeEnv = { ...forkEnv }; + // Only apply the fetch/child_process preload in dev mode. + // In packaged builds Electron's UtilityProcess rejects NODE_OPTIONS + // with --require, logging "Most NODE_OPTIONs are not supported in + // packaged apps" and the preload never loads. if (!app.isPackaged) { try { const preloadPath = ensureGatewayFetchPreload(); diff --git a/electron/gateway/restart-governor.ts b/electron/gateway/restart-governor.ts index 1d5b98176..24d31c008 100644 --- a/electron/gateway/restart-governor.ts +++ b/electron/gateway/restart-governor.ts @@ -2,79 +2,60 @@ export type RestartDecision = | { allow: true } | { allow: false; - reason: 'circuit_open' | 'budget_exceeded' | 'cooldown_active'; + reason: 'cooldown_active'; retryAfterMs: number; }; type RestartGovernorOptions = { - maxRestartsPerWindow: number; - windowMs: number; - baseCooldownMs: number; - maxCooldownMs: number; - circuitOpenMs: number; - stableResetMs: number; + /** Minimum interval between consecutive restarts (ms). */ + cooldownMs: number; }; const DEFAULT_OPTIONS: RestartGovernorOptions = { - maxRestartsPerWindow: 4, - windowMs: 10 * 60 * 1000, - baseCooldownMs: 2500, - maxCooldownMs: 2 * 60 * 1000, - circuitOpenMs: 10 * 60 * 1000, - stableResetMs: 2 * 60 * 1000, + cooldownMs: 2500, }; +/** + * Lightweight restart rate-limiter. + * + * Prevents rapid-fire restarts by enforcing a simple cooldown between + * consecutive restart executions. Nothing more — no circuit breakers, + * no sliding-window budgets, no exponential back-off. Those mechanisms + * were previously present but removed because: + * + * 1. The root causes of infinite restart loops (stale ownedPid, port + * contention, leaked WebSocket connections) have been fixed at their + * source. + * 2. A 10-minute circuit-breaker lockout actively hurt the user + * experience: legitimate config changes were silently dropped. + * 3. The complexity made the restart path harder to reason about during + * debugging. + */ export class GatewayRestartGovernor { private readonly options: RestartGovernorOptions; - private restartTimestamps: number[] = []; - private circuitOpenUntil = 0; - private consecutiveRestarts = 0; private lastRestartAt = 0; - private lastRunningAt = 0; private suppressedTotal = 0; private executedTotal = 0; - private static readonly MAX_COUNTER = Number.MAX_SAFE_INTEGER; constructor(options?: Partial) { this.options = { ...DEFAULT_OPTIONS, ...options }; } - onRunning(now = Date.now()): void { - this.lastRunningAt = now; + /** No-op kept for interface compatibility with callers. */ + onRunning(_now = Date.now()): void { + // Previously used to track "stable running" for exponential back-off + // reset. No longer needed with the simplified cooldown model. } decide(now = Date.now()): RestartDecision { - this.pruneOld(now); - this.maybeResetConsecutive(now); - - if (now < this.circuitOpenUntil) { - this.suppressedTotal = this.incrementCounter(this.suppressedTotal); - return { - allow: false, - reason: 'circuit_open', - retryAfterMs: this.circuitOpenUntil - now, - }; - } - - if (this.restartTimestamps.length >= this.options.maxRestartsPerWindow) { - this.circuitOpenUntil = now + this.options.circuitOpenMs; - this.suppressedTotal = this.incrementCounter(this.suppressedTotal); - return { - allow: false, - reason: 'budget_exceeded', - retryAfterMs: this.options.circuitOpenMs, - }; - } - - const requiredCooldown = this.getCooldownMs(); if (this.lastRestartAt > 0) { const sinceLast = now - this.lastRestartAt; - if (sinceLast < requiredCooldown) { - this.suppressedTotal = this.incrementCounter(this.suppressedTotal); + if (sinceLast < this.options.cooldownMs) { + this.suppressedTotal = this.safeIncrement(this.suppressedTotal); return { allow: false, reason: 'cooldown_active', - retryAfterMs: requiredCooldown - sinceLast, + retryAfterMs: this.options.cooldownMs - sinceLast, }; } } @@ -83,11 +64,8 @@ export class GatewayRestartGovernor { } recordExecuted(now = Date.now()): void { - this.executedTotal = this.incrementCounter(this.executedTotal); + this.executedTotal = this.safeIncrement(this.executedTotal); this.lastRestartAt = now; - this.consecutiveRestarts += 1; - this.restartTimestamps.push(now); - this.pruneOld(now); } getCounters(): { executedTotal: number; suppressedTotal: number } { @@ -105,41 +83,12 @@ export class GatewayRestartGovernor { return { suppressed_total: this.suppressedTotal, executed_total: this.executedTotal, - circuit_open_until: this.circuitOpenUntil, + circuit_open_until: 0, // Always 0 — no circuit breaker }; } - private getCooldownMs(): number { - const factor = Math.pow(2, Math.max(0, this.consecutiveRestarts)); - return Math.min(this.options.baseCooldownMs * factor, this.options.maxCooldownMs); - } - - private maybeResetConsecutive(now: number): void { - if (this.lastRunningAt <= 0) return; - if (now - this.lastRunningAt >= this.options.stableResetMs) { - this.consecutiveRestarts = 0; - } - } - - private pruneOld(now: number): void { - // Detect time rewind (system clock moved backwards) and clear all - // time-based guard state to avoid stale lockouts. - if (this.restartTimestamps.length > 0 && now < this.restartTimestamps[this.restartTimestamps.length - 1]) { - this.restartTimestamps = []; - this.circuitOpenUntil = 0; - this.lastRestartAt = 0; - this.lastRunningAt = 0; - this.consecutiveRestarts = 0; - return; - } - const threshold = now - this.options.windowMs; - while (this.restartTimestamps.length > 0 && this.restartTimestamps[0] < threshold) { - this.restartTimestamps.shift(); - } - } - - private incrementCounter(current: number): number { - if (current >= GatewayRestartGovernor.MAX_COUNTER) return 0; + private safeIncrement(current: number): number { + if (current >= Number.MAX_SAFE_INTEGER) return 0; return current + 1; } } diff --git a/electron/gateway/startup-orchestrator.ts b/electron/gateway/startup-orchestrator.ts index eb3066384..ae2c3ee13 100644 --- a/electron/gateway/startup-orchestrator.ts +++ b/electron/gateway/startup-orchestrator.ts @@ -9,13 +9,13 @@ export interface ExistingGatewayInfo { type StartupHooks = { port: number; - ownedPid?: number; + ownedPid?: never; // Removed: pid is now read dynamically in findExistingGateway to avoid stale-snapshot bug shouldWaitForPortFree: boolean; maxStartAttempts?: number; resetStartupStderrLines: () => void; getStartupStderrLines: () => string[]; assertLifecycle: (phase: string) => void; - findExistingGateway: (port: number, ownedPid?: number) => Promise; + findExistingGateway: (port: number) => Promise; connect: (port: number, externalToken?: string) => Promise; onConnectedToExistingGateway: () => void; waitForPortFree: (port: number) => Promise; @@ -39,7 +39,7 @@ export async function runGatewayStartupSequence(hooks: StartupHooks): Promise setTimeout(resolve, pollInterval)); } - logger.warn(`Port ${port} still occupied after ${timeoutMs}ms, proceeding anyway`); + logger.error(`Port ${port} still occupied after ${timeoutMs}ms; aborting startup to avoid port conflict`); + throw new Error(`Port ${port} still occupied after ${timeoutMs}ms`); } async function getListeningProcessIds(port: number): Promise { @@ -256,15 +257,18 @@ export async function findExistingGatewayProcess(options: { return await new Promise<{ port: number; externalToken?: string } | null>((resolve) => { const testWs = new WebSocket(`ws://localhost:${port}/ws`); + const terminateAndResolve = (result: { port: number; externalToken?: string } | null) => { + // terminate() avoids TIME_WAIT on Windows (vs close() which does WS handshake) + try { testWs.terminate(); } catch { /* ignore */ } + resolve(result); + }; const timeout = setTimeout(() => { - testWs.close(); - resolve(null); + terminateAndResolve(null); }, 2000); testWs.on('open', () => { clearTimeout(timeout); - testWs.close(); - resolve({ port }); + terminateAndResolve({ port }); }); testWs.on('error', () => { diff --git a/electron/gateway/ws-client.ts b/electron/gateway/ws-client.ts index a9231ff9c..e2c9e5e93 100644 --- a/electron/gateway/ws-client.ts +++ b/electron/gateway/ws-client.ts @@ -24,7 +24,10 @@ export async function probeGatewayReady( settled = true; clearTimeout(timeout); try { - testWs.close(); + // Use terminate() (TCP RST) instead of close() (WS close handshake) + // to avoid leaving TIME_WAIT connections on Windows. These probe + // WebSockets are short-lived and don't need a graceful close. + testWs.terminate(); } catch { // ignore } @@ -171,7 +174,7 @@ export async function connectGatewaySocket(options: { getToken: () => Promise; onHandshakeComplete: (ws: WebSocket) => void; onMessage: (message: unknown) => void; - onCloseAfterHandshake: () => void; + onCloseAfterHandshake: (code: number) => void; challengeTimeoutMs?: number; connectTimeoutMs?: number; }): Promise { @@ -308,7 +311,7 @@ export async function connectGatewaySocket(options: { return; } cleanupHandshakeRequest(); - options.onCloseAfterHandshake(); + options.onCloseAfterHandshake(code); }); ws.on('error', (error) => { diff --git a/electron/services/providers/provider-runtime-sync.ts b/electron/services/providers/provider-runtime-sync.ts index 512d89cb6..5dc1523e6 100644 --- a/electron/services/providers/provider-runtime-sync.ts +++ b/electron/services/providers/provider-runtime-sync.ts @@ -421,13 +421,6 @@ async function buildAgentModelProviderEntry( authHeader = true; apiKey = 'minimax-oauth'; } - } else if (config.type === 'qwen-portal') { - const accountApiKey = await getApiKey(config.id); - if (accountApiKey) { - apiKey = accountApiKey; - } else { - apiKey = 'qwen-oauth'; - } } return { @@ -591,7 +584,7 @@ export async function syncDefaultProviderToRuntime( const ock = await resolveRuntimeProviderKey(provider); const providerKey = await getApiKey(providerId); const fallbackModels = await getProviderFallbackModelRefs(provider); - const oauthTypes = ['qwen-portal', 'minimax-portal', 'minimax-portal-cn']; + const oauthTypes = ['minimax-portal', 'minimax-portal-cn']; const browserOAuthRuntimeProvider = await getBrowserOAuthRuntimeProvider(provider); const isOAuthProvider = (oauthTypes.includes(provider.type) && !providerKey) || Boolean(browserOAuthRuntimeProvider); @@ -662,20 +655,15 @@ export async function syncDefaultProviderToRuntime( const defaultBaseUrl = provider.type === 'minimax-portal' ? 'https://api.minimax.io/anthropic' - : (provider.type === 'minimax-portal-cn' ? 'https://api.minimaxi.com/anthropic' : 'https://portal.qwen.ai/v1'); - const api: 'anthropic-messages' | 'openai-completions' = - (provider.type === 'minimax-portal' || provider.type === 'minimax-portal-cn') - ? 'anthropic-messages' - : 'openai-completions'; + : 'https://api.minimaxi.com/anthropic'; + const api = 'anthropic-messages' as const; let baseUrl = provider.baseUrl || defaultBaseUrl; - if ((provider.type === 'minimax-portal' || provider.type === 'minimax-portal-cn') && baseUrl) { + if (baseUrl) { baseUrl = baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic'; } - const targetProviderKey = (provider.type === 'minimax-portal' || provider.type === 'minimax-portal-cn') - ? 'minimax-portal' - : provider.type; + const targetProviderKey = 'minimax-portal'; await setOpenClawDefaultModelWithOverride(targetProviderKey, getProviderModelRef(provider), { baseUrl, diff --git a/electron/services/providers/provider-store.ts b/electron/services/providers/provider-store.ts index 02f03cbbd..36e52ed56 100644 --- a/electron/services/providers/provider-store.ts +++ b/electron/services/providers/provider-store.ts @@ -2,7 +2,6 @@ import type { ProviderAccount, ProviderConfig, ProviderType } from '../../shared import { getProviderDefinition } from '../../shared/providers/registry'; import { getClawXProviderStore } from './store-instance'; -const PROVIDER_STORE_SCHEMA_VERSION = 1; function inferAuthMode(type: ProviderType): ProviderAccount['authMode'] { if (type === 'ollama') { @@ -75,7 +74,6 @@ export async function saveProviderAccount(account: ProviderAccount): Promise; accounts[account.id] = account; store.set('providerAccounts', accounts); - store.set('schemaVersion', PROVIDER_STORE_SCHEMA_VERSION); } export async function deleteProviderAccount(accountId: string): Promise { diff --git a/electron/shared/providers/registry.ts b/electron/shared/providers/registry.ts index 434f19969..1c6b65efa 100644 --- a/electron/shared/providers/registry.ts +++ b/electron/shared/providers/registry.ts @@ -218,26 +218,27 @@ export const PROVIDER_DEFINITIONS: ProviderDefinition[] = [ }, }, { - id: 'qwen-portal', - name: 'Qwen', + id: 'modelstudio', + name: 'Model Studio', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', - requiresApiKey: false, - isOAuth: true, - defaultModelId: 'coder-model', + requiresApiKey: true, + defaultBaseUrl: 'https://coding.dashscope.aliyuncs.com/v1', + showBaseUrl: true, + defaultModelId: 'qwen3.5-plus', showModelId: true, showModelIdInDevModeOnly: true, - modelIdPlaceholder: 'coder-model', + modelIdPlaceholder: 'qwen3.5-plus', category: 'official', - envVar: 'QWEN_API_KEY', - supportedAuthModes: ['oauth_device'], - defaultAuthMode: 'oauth_device', + envVar: 'MODELSTUDIO_API_KEY', + supportedAuthModes: ['api_key'], + defaultAuthMode: 'api_key', supportsMultipleAccounts: true, providerConfig: { - baseUrl: 'https://portal.qwen.ai/v1', + baseUrl: 'https://coding.dashscope.aliyuncs.com/v1', api: 'openai-completions', - apiKeyEnv: 'QWEN_API_KEY', + apiKeyEnv: 'MODELSTUDIO_API_KEY', }, }, { diff --git a/electron/shared/providers/types.ts b/electron/shared/providers/types.ts index 27291eb32..122c5244d 100644 --- a/electron/shared/providers/types.ts +++ b/electron/shared/providers/types.ts @@ -8,7 +8,7 @@ export const PROVIDER_TYPES = [ 'siliconflow', 'minimax-portal', 'minimax-portal-cn', - 'qwen-portal', + 'modelstudio', 'ollama', 'custom', ] as const; @@ -23,7 +23,7 @@ export const BUILTIN_PROVIDER_TYPES = [ 'siliconflow', 'minimax-portal', 'minimax-portal-cn', - 'qwen-portal', + 'modelstudio', 'ollama', ] as const; diff --git a/electron/utils/device-oauth.ts b/electron/utils/device-oauth.ts index 3eef88e55..bec1c3aa7 100644 --- a/electron/utils/device-oauth.ts +++ b/electron/utils/device-oauth.ts @@ -1,11 +1,10 @@ /** * Device OAuth Manager * - * Manages Device Code OAuth flows for MiniMax and Qwen providers. + * Manages Device Code OAuth flows for MiniMax providers. * * The OAuth protocol implementations are fully self-contained in: * - ./minimax-oauth.ts (MiniMax Device Code + PKCE) - * - ./qwen-oauth.ts (Qwen Device Code + PKCE) * * This approach: * - Hardcodes client_id and endpoints (same as openai-codex-oauth.ts) @@ -24,12 +23,11 @@ import { getProviderDefaultModel } from './provider-registry'; import { proxyAwareFetch } from './proxy-fetch'; import { saveOAuthTokenToOpenClaw, setOpenClawDefaultModelWithOverride } from './openclaw-auth'; import { loginMiniMaxPortalOAuth, type MiniMaxOAuthToken, type MiniMaxRegion } from './minimax-oauth'; -import { loginQwenPortalOAuth, type QwenOAuthToken } from './qwen-oauth'; -export type OAuthProviderType = 'minimax-portal' | 'minimax-portal-cn' | 'qwen-portal'; +export type OAuthProviderType = 'minimax-portal' | 'minimax-portal-cn'; // Re-export types for consumers -export type { MiniMaxRegion, MiniMaxOAuthToken, QwenOAuthToken }; +export type { MiniMaxRegion, MiniMaxOAuthToken }; // ───────────────────────────────────────────────────────────── // DeviceOAuthManager @@ -76,8 +74,6 @@ class DeviceOAuthManager extends EventEmitter { if (provider === 'minimax-portal' || provider === 'minimax-portal-cn') { const actualRegion = provider === 'minimax-portal-cn' ? 'cn' : (region || 'global'); await this.runMiniMaxFlow(actualRegion, provider); - } else if (provider === 'qwen-portal') { - await this.runQwenFlow(); } else { throw new Error(`Unsupported OAuth provider type: ${provider}`); } @@ -152,47 +148,7 @@ class DeviceOAuthManager extends EventEmitter { }); } - // ───────────────────────────────────────────────────────── - // Qwen flow - // ───────────────────────────────────────────────────────── - private async runQwenFlow(): Promise { - const provider = this.activeProvider!; - - const token: QwenOAuthToken = await this.runWithProxyAwareFetch(() => loginQwenPortalOAuth({ - openUrl: async (url: string) => { - logger.info(`[DeviceOAuth] Qwen opening browser: ${url}`); - shell.openExternal(url).catch((err: unknown) => - logger.warn(`[DeviceOAuth] Failed to open browser:`, err) - ); - }, - note: async (message: string, _title?: string) => { - if (!this.active) return; - const { verificationUri, userCode } = this.parseNote(message); - if (verificationUri && userCode) { - this.emitCode({ provider, verificationUri, userCode, expiresIn: 300 }); - } else { - logger.info(`[DeviceOAuth] Qwen note: ${message}`); - } - }, - progress: { - update: (msg: string) => logger.info(`[DeviceOAuth] Qwen progress: ${msg}`), - stop: (msg?: string) => logger.info(`[DeviceOAuth] Qwen progress done: ${msg ?? ''}`), - }, - })); - - if (!this.active) return; - - await this.onSuccess('qwen-portal', { - access: token.access, - refresh: token.refresh, - expires: token.expires, - // Qwen returns a per-account resourceUrl as the API base URL - resourceUrl: token.resourceUrl, - // Qwen uses OpenAI Completions API format - api: 'openai-completions', - }); - } // ───────────────────────────────────────────────────────── // Success handler @@ -235,7 +191,7 @@ class DeviceOAuthManager extends EventEmitter { // or falls back to the provider's default public endpoint. const defaultBaseUrl = providerType === 'minimax-portal' ? 'https://api.minimax.io/anthropic' - : (providerType === 'minimax-portal-cn' ? 'https://api.minimaxi.com/anthropic' : 'https://portal.qwen.ai/v1'); + : 'https://api.minimaxi.com/anthropic'; let baseUrl = token.resourceUrl || defaultBaseUrl; @@ -247,11 +203,6 @@ class DeviceOAuthManager extends EventEmitter { // Ensure the base URL ends with /anthropic if (providerType.startsWith('minimax-portal') && baseUrl) { baseUrl = baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic'; - } else if (providerType === 'qwen-portal' && baseUrl) { - // Ensure Qwen API gets /v1 at the end - if (!baseUrl.endsWith('/v1')) { - baseUrl = baseUrl.replace(/\/$/, '') + '/v1'; - } } try { @@ -263,7 +214,7 @@ class DeviceOAuthManager extends EventEmitter { authHeader: providerType.startsWith('minimax-portal') ? true : undefined, // OAuth placeholder — tells Gateway to resolve credentials // from auth-profiles.json (type: 'oauth') instead of a static API key. - apiKeyEnv: tokenProviderId === 'minimax-portal' ? 'minimax-oauth' : 'qwen-oauth', + apiKeyEnv: 'minimax-oauth', }); } catch (err) { logger.warn(`[DeviceOAuth] Failed to configure openclaw models:`, err); @@ -274,7 +225,6 @@ class DeviceOAuthManager extends EventEmitter { const nameMap: Record = { 'minimax-portal': 'MiniMax (Global)', 'minimax-portal-cn': 'MiniMax (CN)', - 'qwen-portal': 'Qwen', }; const providerConfig: ProviderConfig = { id: accountId, diff --git a/electron/utils/openclaw-auth.ts b/electron/utils/openclaw-auth.ts index 1f0e1aa53..c78d8c7d6 100644 --- a/electron/utils/openclaw-auth.ts +++ b/electron/utils/openclaw-auth.ts @@ -473,7 +473,7 @@ export async function removeProviderFromOpenClaw(provider: string): Promise | undefined; const entries = (plugins?.entries ?? {}) as Record>; const pluginName = `${provider}-auth`; @@ -872,6 +872,10 @@ export async function setOpenClawDefaultModelWithOverride( * Get a set of all active provider IDs configured in openclaw.json. * Reads the file ONCE and extracts both models.providers and plugins.entries. */ +// Provider IDs that have been deprecated and should never appear as active. +// These may still linger in openclaw.json from older versions. +const DEPRECATED_PROVIDER_IDS = new Set(['qwen-portal']); + export async function getActiveOpenClawProviders(): Promise> { const activeProviders = new Set(); @@ -897,7 +901,7 @@ export async function getActiveOpenClawProviders(): Promise> { } // 3. agents.defaults.model.primary — the default model reference encodes - // the provider prefix (e.g. "qwen-portal/coder-model" → "qwen-portal"). + // the provider prefix (e.g. "modelstudio/qwen3.5-plus" → "modelstudio"). // This covers providers that are active via OAuth or env-key but don't // have an explicit models.providers entry. const agents = config.agents as Record | undefined; @@ -921,6 +925,11 @@ export async function getActiveOpenClawProviders(): Promise> { console.warn('Failed to read openclaw.json for active providers:', err); } + // Remove deprecated providers that may still linger in config/auth files. + for (const deprecated of DEPRECATED_PROVIDER_IDS) { + activeProviders.delete(deprecated); + } + return activeProviders; } @@ -1350,10 +1359,24 @@ export async function sanitizeOpenClawConfig(): Promise { toolsModified = true; } + // ── tools.exec approvals (OpenClaw 3.28+) ────────────────────── + // ClawX is a local desktop app where the user is the trusted operator. + // Exec approval prompts add unnecessary friction in this context, so we + // set security="full" (allow all commands) and ask="off" (never prompt). + // If a user has manually configured a stricter ~/.openclaw/exec-approvals.json, + // OpenClaw's minSecurity/maxAsk merge will still respect their intent. + const execConfig = (toolsConfig.exec as Record | undefined) || {}; + if (execConfig.security !== 'full' || execConfig.ask !== 'off') { + execConfig.security = 'full'; + execConfig.ask = 'off'; + toolsConfig.exec = execConfig; + toolsModified = true; + console.log('[sanitize] Set tools.exec.security="full" and tools.exec.ask="off" to disable exec approvals for ClawX desktop'); + } + if (toolsModified) { config.tools = toolsConfig; modified = true; - console.log('[sanitize] Enforced tools.profile="full" and tools.sessions.visibility="all" for OpenClaw 3.8+'); } // ── plugins.entries.feishu cleanup ────────────────────────────── @@ -1465,6 +1488,44 @@ export async function sanitizeOpenClawConfig(): Promise { modified = true; } + // ── qwen-portal → modelstudio migration ──────────────────── + // OpenClaw 2026.3.28 deprecated qwen-portal OAuth (portal.qwen.ai) + // in favor of Model Studio (DashScope API key). Clean up legacy + // qwen-portal-auth plugin entries and qwen-portal provider config. + const LEGACY_QWEN_PLUGIN_ID = 'qwen-portal-auth'; + if (Array.isArray(pluginsObj.allow)) { + const allowArr = pluginsObj.allow as string[]; + const legacyIdx = allowArr.indexOf(LEGACY_QWEN_PLUGIN_ID); + if (legacyIdx !== -1) { + allowArr.splice(legacyIdx, 1); + console.log(`[sanitize] Removed deprecated plugin from plugins.allow: ${LEGACY_QWEN_PLUGIN_ID}`); + modified = true; + } + } + if (pEntries?.[LEGACY_QWEN_PLUGIN_ID]) { + delete pEntries[LEGACY_QWEN_PLUGIN_ID]; + console.log(`[sanitize] Removed deprecated plugin from plugins.entries: ${LEGACY_QWEN_PLUGIN_ID}`); + modified = true; + } + + // Remove deprecated models.providers.qwen-portal + const LEGACY_QWEN_PROVIDER = 'qwen-portal'; + if (providers[LEGACY_QWEN_PROVIDER]) { + delete providers[LEGACY_QWEN_PROVIDER]; + console.log(`[sanitize] Removed deprecated provider: ${LEGACY_QWEN_PROVIDER}`); + modified = true; + } + + // Clean up qwen-portal OAuth auth profile (no longer functional) + const authConfig = config.auth as Record | undefined; + const authProfiles = authConfig?.profiles as Record | undefined; + if (authProfiles?.[LEGACY_QWEN_PROVIDER]) { + delete authProfiles[LEGACY_QWEN_PROVIDER]; + console.log(`[sanitize] Removed deprecated auth profile: ${LEGACY_QWEN_PROVIDER}`); + modified = true; + } + + // ── Remove bare 'feishu' when canonical feishu plugin is present ── // The Gateway binary automatically adds bare 'feishu' to plugins.allow // because the official plugin registers the 'feishu' channel. diff --git a/electron/utils/provider-keys.ts b/electron/utils/provider-keys.ts index b1da9d57a..390db5f57 100644 --- a/electron/utils/provider-keys.ts +++ b/electron/utils/provider-keys.ts @@ -1,12 +1,10 @@ const MULTI_INSTANCE_PROVIDER_TYPES = new Set(['custom', 'ollama']); export const OPENCLAW_PROVIDER_KEY_MINIMAX = 'minimax-portal'; -export const OPENCLAW_PROVIDER_KEY_QWEN = 'qwen-portal'; export const OPENCLAW_PROVIDER_KEY_MOONSHOT = 'moonshot'; -export const OAUTH_PROVIDER_TYPES = ['qwen-portal', 'minimax-portal', 'minimax-portal-cn'] as const; +export const OAUTH_PROVIDER_TYPES = ['minimax-portal', 'minimax-portal-cn'] as const; export const OPENCLAW_OAUTH_PLUGIN_PROVIDER_KEYS = [ OPENCLAW_PROVIDER_KEY_MINIMAX, - OPENCLAW_PROVIDER_KEY_QWEN, ] as const; const OAUTH_PROVIDER_TYPE_SET = new Set(OAUTH_PROVIDER_TYPES); @@ -54,27 +52,24 @@ export function isMiniMaxProviderType(type: string): boolean { export function getOAuthProviderTargetKey(type: string): string | undefined { if (!isOAuthProviderType(type)) return undefined; - return isMiniMaxProviderType(type) ? OPENCLAW_PROVIDER_KEY_MINIMAX : OPENCLAW_PROVIDER_KEY_QWEN; + return OPENCLAW_PROVIDER_KEY_MINIMAX; } -export function getOAuthProviderApi(type: string): 'anthropic-messages' | 'openai-completions' | undefined { +export function getOAuthProviderApi(type: string): 'anthropic-messages' | undefined { if (!isOAuthProviderType(type)) return undefined; - return isMiniMaxProviderType(type) ? 'anthropic-messages' : 'openai-completions'; + return 'anthropic-messages'; } export function getOAuthProviderDefaultBaseUrl(type: string): string | undefined { if (!isOAuthProviderType(type)) return undefined; if (type === OPENCLAW_PROVIDER_KEY_MINIMAX) return 'https://api.minimax.io/anthropic'; if (type === 'minimax-portal-cn') return 'https://api.minimaxi.com/anthropic'; - return 'https://portal.qwen.ai/v1'; + return undefined; } -export function normalizeOAuthBaseUrl(type: string, baseUrl?: string): string | undefined { +export function normalizeOAuthBaseUrl(_type: string, baseUrl?: string): string | undefined { if (!baseUrl) return undefined; - if (isMiniMaxProviderType(type)) { - return baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic'; - } - return baseUrl; + return baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic'; } export function usesOAuthAuthHeader(providerKey: string): boolean { @@ -83,7 +78,6 @@ export function usesOAuthAuthHeader(providerKey: string): boolean { export function getOAuthApiKeyEnv(providerKey: string): string | undefined { if (providerKey === OPENCLAW_PROVIDER_KEY_MINIMAX) return 'minimax-oauth'; - if (providerKey === OPENCLAW_PROVIDER_KEY_QWEN) return 'qwen-oauth'; return undefined; } diff --git a/electron/utils/qwen-oauth.ts b/electron/utils/qwen-oauth.ts deleted file mode 100644 index 1929ffc8b..000000000 --- a/electron/utils/qwen-oauth.ts +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Self-contained Qwen Device Code OAuth flow. - * - * Implements RFC 8628 (Device Authorization Grant) with PKCE for Qwen API. - * Zero dependency on openclaw extension modules — survives openclaw upgrades. - * - * Protocol: - * 1. POST /api/v1/oauth2/device/code → get device_code, user_code, verification_uri - * 2. Open verification_uri in browser - * 3. Poll POST /api/v1/oauth2/token with device_code until approved - * 4. Return { access, refresh, expires, resourceUrl } - */ -import { createHash, randomBytes, randomUUID } from 'node:crypto'; -import { proxyAwareFetch } from './proxy-fetch'; - -// ── Constants ──────────────────────────────────────────────── - -const QWEN_OAUTH_BASE_URL = 'https://chat.qwen.ai'; -const QWEN_OAUTH_DEVICE_CODE_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/device/code`; -const QWEN_OAUTH_TOKEN_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/token`; -const QWEN_OAUTH_CLIENT_ID = 'f0304373b74a44d2b584a3fb70ca9e56'; -const QWEN_OAUTH_SCOPE = 'openid profile email model.completion'; -const QWEN_OAUTH_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code'; - -// ── Types ──────────────────────────────────────────────────── - -export interface QwenOAuthToken { - access: string; - refresh: string; - expires: number; - resourceUrl?: string; -} - -interface QwenDeviceAuthorization { - device_code: string; - user_code: string; - verification_uri: string; - verification_uri_complete?: string; - expires_in: number; - interval?: number; -} - -type DeviceTokenResult = - | { status: 'success'; token: QwenOAuthToken } - | { status: 'pending'; slowDown?: boolean } - | { status: 'error'; message: string }; - -export interface QwenOAuthOptions { - openUrl: (url: string) => Promise; - note: (message: string, title?: string) => Promise; - progress: { update: (message: string) => void; stop: (message?: string) => void }; -} - -// ── PKCE helpers (self-contained, no openclaw dependency) ──── - -function generatePkce(): { verifier: string; challenge: string } { - const verifier = randomBytes(32).toString('base64url'); - const challenge = createHash('sha256').update(verifier).digest('base64url'); - return { verifier, challenge }; -} - -function toFormUrlEncoded(params: Record): string { - return new URLSearchParams(params).toString(); -} - -// ── OAuth flow steps ───────────────────────────────────────── - -async function requestDeviceCode(params: { challenge: string }): Promise { - const response = await proxyAwareFetch(QWEN_OAUTH_DEVICE_CODE_ENDPOINT, { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - Accept: 'application/json', - 'x-request-id': randomUUID(), - }, - body: toFormUrlEncoded({ - client_id: QWEN_OAUTH_CLIENT_ID, - scope: QWEN_OAUTH_SCOPE, - code_challenge: params.challenge, - code_challenge_method: 'S256', - }), - }); - - if (!response.ok) { - const text = await response.text(); - throw new Error(`Qwen device authorization failed: ${text || response.statusText}`); - } - - const payload = (await response.json()) as QwenDeviceAuthorization & { error?: string }; - if (!payload.device_code || !payload.user_code || !payload.verification_uri) { - throw new Error( - payload.error ?? - 'Qwen device authorization returned an incomplete payload (missing user_code or verification_uri).', - ); - } - return payload; -} - -async function pollDeviceToken(params: { - deviceCode: string; - verifier: string; -}): Promise { - const response = await proxyAwareFetch(QWEN_OAUTH_TOKEN_ENDPOINT, { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - Accept: 'application/json', - }, - body: toFormUrlEncoded({ - grant_type: QWEN_OAUTH_GRANT_TYPE, - client_id: QWEN_OAUTH_CLIENT_ID, - device_code: params.deviceCode, - code_verifier: params.verifier, - }), - }); - - if (!response.ok) { - let payload: { error?: string; error_description?: string } | undefined; - try { - payload = (await response.json()) as { error?: string; error_description?: string }; - } catch { - const text = await response.text(); - return { status: 'error', message: text || response.statusText }; - } - - if (payload?.error === 'authorization_pending') { - return { status: 'pending' }; - } - - if (payload?.error === 'slow_down') { - return { status: 'pending', slowDown: true }; - } - - return { - status: 'error', - message: payload?.error_description || payload?.error || response.statusText, - }; - } - - const tokenPayload = (await response.json()) as { - access_token?: string | null; - refresh_token?: string | null; - expires_in?: number | null; - token_type?: string; - resource_url?: string; - }; - - if (!tokenPayload.access_token || !tokenPayload.refresh_token || !tokenPayload.expires_in) { - return { status: 'error', message: 'Qwen OAuth returned incomplete token payload.' }; - } - - return { - status: 'success', - token: { - access: tokenPayload.access_token, - refresh: tokenPayload.refresh_token, - expires: Date.now() + tokenPayload.expires_in * 1000, - resourceUrl: tokenPayload.resource_url, - }, - }; -} - -// ── Public API ─────────────────────────────────────────────── - -export async function loginQwenPortalOAuth(params: QwenOAuthOptions): Promise { - const { verifier, challenge } = generatePkce(); - const device = await requestDeviceCode({ challenge }); - const verificationUrl = device.verification_uri_complete || device.verification_uri; - - await params.note( - [ - `Open ${verificationUrl} to approve access.`, - `If prompted, enter the code ${device.user_code}.`, - ].join('\n'), - 'Qwen OAuth', - ); - - try { - await params.openUrl(verificationUrl); - } catch { - // Fall back to manual copy/paste if browser open fails. - } - - const start = Date.now(); - let pollIntervalMs = device.interval ? device.interval * 1000 : 2000; - const timeoutMs = device.expires_in * 1000; - - while (Date.now() - start < timeoutMs) { - params.progress.update('Waiting for Qwen OAuth approval…'); - const result = await pollDeviceToken({ - deviceCode: device.device_code, - verifier, - }); - - if (result.status === 'success') { - return result.token; - } - - if (result.status === 'error') { - throw new Error(`Qwen OAuth failed: ${result.message}`); - } - - if (result.status === 'pending' && result.slowDown) { - pollIntervalMs = Math.min(pollIntervalMs * 1.5, 10000); - } - - await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)); - } - - throw new Error('Qwen OAuth timed out waiting for authorization.'); -} diff --git a/package.json b/package.json index 146456688..59c9731de 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@larksuite/openclaw-lark": "2026.3.29", + "@larksuite/openclaw-lark": "2026.3.30", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-label": "^2.1.8", @@ -94,7 +94,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@playwright/test": "^1.56.1", "@soimy/dingtalk": "^3.5.1", - "@tencent-connect/openclaw-qqbot": "^1.6.6", + "@tencent-connect/openclaw-qqbot": "^1.6.7", "@tencent-weixin/openclaw-weixin": "^2.1.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", @@ -105,7 +105,7 @@ "@typescript-eslint/eslint-plugin": "^8.56.0", "@typescript-eslint/parser": "^8.56.0", "@vitejs/plugin-react": "^5.1.4", - "@wecom/wecom-openclaw-plugin": "^2026.3.26", + "@wecom/wecom-openclaw-plugin": "^2026.3.30", "@whiskeysockets/baileys": "7.0.0-rc.9", "autoprefixer": "^10.4.24", "class-variance-authority": "^0.7.1", @@ -120,7 +120,7 @@ "i18next": "^25.8.11", "jsdom": "^28.1.0", "lucide-react": "^0.563.0", - "openclaw": "2026.3.24", + "openclaw": "2026.3.28", "png2icons": "^2.0.1", "postcss": "^8.5.6", "react": "^19.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41d2e0d73..c46987328 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,8 +44,8 @@ importers: specifier: ^10.0.1 version: 10.0.1(eslint@10.1.0(jiti@1.21.7)) '@larksuite/openclaw-lark': - specifier: 2026.3.29 - version: 2026.3.29(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) + specifier: 2026.3.30 + version: 2026.3.30(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) '@playwright/test': specifier: ^1.56.1 version: 1.58.2 @@ -87,10 +87,10 @@ importers: version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@soimy/dingtalk': specifier: ^3.5.1 - version: 3.5.1(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) + version: 3.5.1(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) '@tencent-connect/openclaw-qqbot': - specifier: ^1.6.6 - version: 1.6.6(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) + specifier: ^1.6.7 + version: 1.6.7(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13)) '@tencent-weixin/openclaw-weixin': specifier: ^2.1.1 version: 2.1.1 @@ -122,8 +122,8 @@ importers: specifier: ^5.1.4 version: 5.2.0(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.7)(yaml@2.8.3)) '@wecom/wecom-openclaw-plugin': - specifier: ^2026.3.26 - version: 2026.3.26 + specifier: ^2026.3.30 + version: 2026.3.30 '@whiskeysockets/baileys': specifier: 7.0.0-rc.9 version: 7.0.0-rc.9(sharp@0.34.5) @@ -167,8 +167,8 @@ importers: specifier: ^0.563.0 version: 0.563.0(react@19.2.4) openclaw: - specifier: 2026.3.24 - version: 2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13) + specifier: 2026.3.28 + version: 2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13) png2icons: specifier: ^2.0.1 version: 2.0.1 @@ -244,8 +244,8 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@agentclientprotocol/sdk@0.16.1': - resolution: {integrity: sha512-1ad+Sc/0sCtZGHthxxvgEUo5Wsbw16I+aF+YwdiLnPwkZG8KAGUEAPK6LM6Pf69lCyJPt1Aomk1d+8oE3C4ZEw==} + '@agentclientprotocol/sdk@0.17.0': + resolution: {integrity: sha512-inBMYAEd9t4E+ULZK2os9kmLG5jbPvMLbPvY71XDDem1YteW/uDwkahg6OwsGR3tvvgVhYbRJ9mJCp2VXqG4xQ==} peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -311,46 +311,82 @@ packages: resolution: {integrity: sha512-V7WiV46SfpViL0zsgh6mUesVflKbneyrpQfM15dC86fdYjLdehbM6qjiwB3d5XKXuh+Tnh6xEWOZFB71MBgSdg==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-bedrock@3.1017.0': - resolution: {integrity: sha512-kJGC5z8Bov4neUeuYjp0B6J8HlhFN7Mn+M4PVIldVn3hDr4GVn12o1Cbk6WL27QluFwCBmOJLJZgPzS8V69N9w==} + '@aws-sdk/client-bedrock@3.1020.0': + resolution: {integrity: sha512-OIM38upZjWsi62070cOm2nZAJsIeZC26KhOFDt8T6gmzbfcoz7XgkJ6eK9/JFfFagoFykUvXX0nfbcqtryWY0A==} engines: {node: '>=20.0.0'} '@aws-sdk/core@3.973.24': resolution: {integrity: sha512-vvf82RYQu2GidWAuQq+uIzaPz9V0gSCXVqdVzRosgl5rXcspXOpSD3wFreGGW6AYymPr97Z69kjVnLePBxloDw==} engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.973.26': + resolution: {integrity: sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.22': resolution: {integrity: sha512-cXp0VTDWT76p3hyK5D51yIKEfpf6/zsUvMfaB8CkyqadJxMQ8SbEeVroregmDlZbtG31wkj9ei0WnftmieggLg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.24': + resolution: {integrity: sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.24': resolution: {integrity: sha512-h694K7+tRuepSRJr09wTvQfaEnjzsKZ5s7fbESrVds02GT/QzViJ94/HCNwM7bUfFxqpPXHxulZfL6Cou0dwPg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.26': + resolution: {integrity: sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.24': resolution: {integrity: sha512-O46fFmv0RDFWiWEA9/e6oW92BnsyAXuEgTTasxHligjn2RCr9L/DK773m/NoFaL3ZdNAUz8WxgxunleMnHAkeQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.27': + resolution: {integrity: sha512-Um26EsNSUfVUX0wUXnUA1W3wzKhVy6nviEElsh5lLZUYj9bk6DXOPnpte0gt+WHubcVfVsRk40bbm4KaroTEag==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.24': resolution: {integrity: sha512-sIk8oa6AzDoUhxsR11svZESqvzGuXesw62Rl2oW6wguZx8i9cdGCvkFg+h5K7iucUZP8wyWibUbJMc+J66cu5g==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.27': + resolution: {integrity: sha512-t3ehEtHomGZwg5Gixw4fYbYtG9JBnjfAjSDabxhPEu/KLLUp0BB37/APX7MSKXQhX6ZH7pseuACFJ19NrAkNdg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.25': resolution: {integrity: sha512-m7dR0Dsva2P+VUpL+VkC0WwiDby5pgmWXkRVDB5rlwv0jXJrQJf7YMtCoM8Wjk0H9jPeCYOxOXXcIgp/qp5Alg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.28': + resolution: {integrity: sha512-rren+P6k5rShG5PX61iVi40kKdueyuMLBRTctQbyR5LooO9Ygr5L6R7ilG7RF1957NSH3KC3TU206fZuKwjSpQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.22': resolution: {integrity: sha512-Os32s8/4gTZjBk5BtoS/cuTILaj+K72d0dVG7TCJX/fC4598cxwLDmf1AEHEpER5oL3K//yETjvFaz0V8oO5Xw==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.24': + resolution: {integrity: sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.24': resolution: {integrity: sha512-PaFv7snEfypU2yXkpvfyWgddEbDLtgVe51wdZlinhc2doubBjUzJZZpgwuF2Jenl1FBydMhNpMjD6SBUM3qdSA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.27': + resolution: {integrity: sha512-CWXeGjlbBuHcm9appZUgXKP2zHDyTti0/+gXpSFJ2J3CnSwf1KWjicjN0qG2ozkMH6blrrzMrimeIOEYNl238Q==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.24': resolution: {integrity: sha512-J6H4R1nvr3uBTqD/EeIPAskrBtET4WFfNhpFySr2xW7bVZOXpQfPjrLSIx65jcNjBmLXzWq8QFLdVoGxiGG/SA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.27': + resolution: {integrity: sha512-CUY4hQIFswdQNEsRGEzGBUKGMK5KpqmNDdu2ROMgI+45PLFS8H0y3Tm7kvM16uvvw3n1pVxk85tnRVUTgtaa1w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/eventstream-handler-node@3.972.11': resolution: {integrity: sha512-2IrLrOruRr1NhTK0vguBL1gCWv1pu4bf4KaqpsA+/vCJpFEbvXFawn71GvCzk1wyjnDUsemtKypqoKGv4cSGbA==} engines: {node: '>=20.0.0'} @@ -371,10 +407,18 @@ packages: resolution: {integrity: sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-recursion-detection@3.972.9': + resolution: {integrity: sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-user-agent@3.972.25': resolution: {integrity: sha512-QxiMPofvOt8SwSynTOmuZfvvPM1S9QfkESBxB22NMHTRXCJhR5BygLl8IXfC4jELiisQgwsgUby21GtXfX3f/g==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-user-agent@3.972.27': + resolution: {integrity: sha512-TIRLO5UR2+FVUGmhYoAwVkKhcVzywEDX/5LzR9tjy1h8FQAXOtFg2IqgmwvxU7y933rkTn9rl6AdgcAUgQ1/Kg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-websocket@3.972.13': resolution: {integrity: sha512-Gp6EWIqHX5wmsOR5ZxWyyzEU8P0xBdSxkm6VHEwXwBqScKZ7QWRoj6ZmHpr+S44EYb5tuzGya4ottsogSu2W3A==} engines: {node: '>= 14.0.0'} @@ -383,6 +427,14 @@ packages: resolution: {integrity: sha512-fSESKvh1VbfjtV3QMnRkCPZWkUbQof6T/DOpiLp33yP2wA+rbwwnZeG3XT3Ekljgw2I8X4XaQPnw+zSR8yxJ5Q==} engines: {node: '>=20.0.0'} + '@aws-sdk/nested-clients@3.996.17': + resolution: {integrity: sha512-7B0HIX0tEFmOSJuWzdHZj1WhMXSryM+h66h96ZkqSncoY7J6wq61KOu4Kr57b/YnJP3J/EeQYVFulgR281h+7A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.10': + resolution: {integrity: sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/region-config-resolver@3.972.9': resolution: {integrity: sha512-eQ+dFU05ZRC/lC2XpYlYSPlXtX3VT8sn5toxN2Fv7EXlMoA2p9V7vUBKqHunfD4TRLpxUq8Y8Ol/nCqiv327Ng==} engines: {node: '>=20.0.0'} @@ -395,6 +447,10 @@ packages: resolution: {integrity: sha512-xqssisjxtK64VhyqKm6+mlGF/un0q/t2xYCMj1tfW/BrL3yZ+pAAS+zGwkjMiMhvtVcAV/h5UeLNWLHuEPwDKw==} engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.1020.0': + resolution: {integrity: sha512-T61KA/VKl0zVUubdxigr1ut7SEpwE1/4CIKb14JDLyTAOne2yWKtQE1dDCSHl0UqrZNwW/bTt+EBHfQbslZJdw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.973.6': resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} engines: {node: '>=20.0.0'} @@ -423,10 +479,23 @@ packages: aws-crt: optional: true + '@aws-sdk/util-user-agent-node@3.973.13': + resolution: {integrity: sha512-s1dCJ0J9WU9UPkT3FFqhKTSquYTkqWXGRaapHFyWwwJH86ZussewhNST5R5TwXVL1VSHq4aJVl9fWK+svaRVCQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@aws-sdk/xml-builder@3.972.15': resolution: {integrity: sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA==} engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.16': + resolution: {integrity: sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.2.4': resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} engines: {node: '>=18.0.0'} @@ -1076,12 +1145,15 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} - '@larksuite/openclaw-lark@2026.3.29': - resolution: {integrity: sha512-dDUN7UWZBDVEfB7OGGwVBApE3uWgsVDiiJQV/MI0BrJODus3f4Eh65SU0PYLud5DbZ5uN7UcWFbn+5b3BQwOcw==} + '@larksuite/openclaw-lark@2026.3.30': + resolution: {integrity: sha512-PAOcXOwEK5BsXASDSXCGCzqhF0TBmF0qzNmEKuPQWleqeeUNpEv55bHeCNWOGFRu8K+HXJn+phamZ/8Vr1r4lw==} engines: {node: '>=22'} hasBin: true peerDependencies: openclaw: '>=2026.3.22' + peerDependenciesMeta: + openclaw: + optional: true '@larksuiteoapi/node-sdk@1.60.0': resolution: {integrity: sha512-MS1eXx7K6HHIyIcCBkJLb21okoa8ZatUGQWZaCCUePm6a37RWFmT6ZKlKvHxAanSX26wNuNlwP0RhgscsE+T6g==} @@ -1203,29 +1275,37 @@ packages: resolution: {integrity: sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==} hasBin: true - '@mariozechner/pi-agent-core@0.61.1': - resolution: {integrity: sha512-ELZsyx6INGBYXPAbYTAiRWtkmnwAlcXOOVPY434BE605TBdpzMrXF5gNckKdEyCCWYJiLzSKpHaAzWwB7Vx2nA==} + '@mariozechner/pi-agent-core@0.63.1': + resolution: {integrity: sha512-h0B20xfs/iEVR2EC4gwiE8hKI1TPeB8REdRJMgV+uXKH7gpeIZ9+s8Dp9nX35ZR0QUjkNey2+ULk2DxQtdg14Q==} engines: {node: '>=20.0.0'} - '@mariozechner/pi-ai@0.61.1': - resolution: {integrity: sha512-BOk8xwluIgauX93qgC9qyrWteKKnk6pNDM8szE1m/EJKMhcJ/jIJpgAUQgj4yXiwSMtcZm30h2Po97gqqXTIIg==} + '@mariozechner/pi-ai@0.63.1': + resolution: {integrity: sha512-wjgwY+yfrFO6a9QdAfjWpH7iSrDean6GsKDDMohNcLCy6PreMxHOZvNM0NwJARL1tZoZovr7ikAQfLGFZbnjsw==} engines: {node: '>=20.0.0'} hasBin: true - '@mariozechner/pi-coding-agent@0.61.1': - resolution: {integrity: sha512-w0QTn+LFFdyFhpaaYDOacGwBjW4MKYrl40b6LPfKDuVJ+9fDfHl3kWkbx6xJb9brk6M5lEFMheC82UIQdkeK3Q==} + '@mariozechner/pi-coding-agent@0.63.1': + resolution: {integrity: sha512-XSoMyLtuMA7ePK1UBWqSJ/BBdtBdJUHY9nbtnNyG6GeW7Gbgd+iqljIuwmAUf8wlYL981UIfYM/WIPQ6t/dIxw==} engines: {node: '>=20.6.0'} hasBin: true - '@mariozechner/pi-tui@0.61.1': - resolution: {integrity: sha512-J3EI1gU5knUf1dXiHJsimDP4IRXLG7QJ1NVykU/yWOJoBPAgG6/qjjPPRcaUA7MYMUfKi+Z/zzGOyQSCVAajPA==} + '@mariozechner/pi-tui@0.63.1': + resolution: {integrity: sha512-G5p+eh1EPkFCNaaggX6vRrqttnDscK6npgmEOknoCQXZtch8XNgh9Lf3VJ0A2lZXSgR7IntG5dfXHPH/Ki64wA==} engines: {node: '>=20.0.0'} + '@matrix-org/matrix-sdk-crypto-nodejs@0.4.0': + resolution: {integrity: sha512-+qqgpn39XFSbsD0dFjssGO9vHEP7sTyfs8yTpt8vuqWpUpF20QMwpCZi0jpYw7GxjErNTsMshopuo8677DfGEA==} + engines: {node: '>= 22'} + + '@matrix-org/matrix-sdk-crypto-wasm@18.0.0': + resolution: {integrity: sha512-88+n+dvxLI1cjS10UIlKXVYK7TGWbpAnnaDC9fow7ch/hCvdu3dFhJ3tS3/13N9s9+1QFXB4FFuommj+tHJPhQ==} + engines: {node: '>= 18'} + '@mistralai/mistralai@1.14.1': resolution: {integrity: sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==} - '@modelcontextprotocol/sdk@1.27.1': - resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + '@modelcontextprotocol/sdk@1.28.0': + resolution: {integrity: sha512-gmloF+i+flI8ouQK7MWW4mOwuMh4RePBuPFAEPC6+pdqyWOUMDOixb6qZ69owLJpz6XmyllCouc4t8YWO+E2Nw==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -2062,6 +2142,10 @@ packages: resolution: {integrity: sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w==} engines: {node: '>=18.0.0'} + '@smithy/core@3.23.13': + resolution: {integrity: sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.12': resolution: {integrity: sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==} engines: {node: '>=18.0.0'} @@ -2114,14 +2198,26 @@ packages: resolution: {integrity: sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA==} engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.4.28': + resolution: {integrity: sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.44': resolution: {integrity: sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA==} engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.45': + resolution: {integrity: sha512-td1PxpwDIaw5/oP/xIRxBGxJKoF1L4DBAwbZ8wjMuXBYOP/r2ZE/Ocou+mBHx/yk9knFEtDBwhSrYVn+Mz4pHw==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.15': resolution: {integrity: sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg==} engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.16': + resolution: {integrity: sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-stack@4.2.12': resolution: {integrity: sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==} engines: {node: '>=18.0.0'} @@ -2134,6 +2230,10 @@ packages: resolution: {integrity: sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A==} engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.5.1': + resolution: {integrity: sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw==} + engines: {node: '>=18.0.0'} + '@smithy/property-provider@4.2.12': resolution: {integrity: sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==} engines: {node: '>=18.0.0'} @@ -2166,6 +2266,10 @@ packages: resolution: {integrity: sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ==} engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.12.8': + resolution: {integrity: sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.13.1': resolution: {integrity: sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==} engines: {node: '>=18.0.0'} @@ -2202,10 +2306,18 @@ packages: resolution: {integrity: sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.44': + resolution: {integrity: sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.47': resolution: {integrity: sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.48': + resolution: {integrity: sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg==} + engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.3.3': resolution: {integrity: sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==} engines: {node: '>=18.0.0'} @@ -2226,6 +2338,10 @@ packages: resolution: {integrity: sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==} engines: {node: '>=18.0.0'} + '@smithy/util-stream@4.5.21': + resolution: {integrity: sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q==} + engines: {node: '>=18.0.0'} + '@smithy/util-uri-escape@4.2.2': resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==} engines: {node: '>=18.0.0'} @@ -2257,8 +2373,8 @@ packages: '@telegraf/types@7.1.0': resolution: {integrity: sha512-kGevOIbpMcIlCDeorKGpwZmdH7kHbqlk/Yj6dEpJMKEQw5lk0KVQY0OLXaCswy8GqlIVLd5625OB+rAntP9xVw==} - '@tencent-connect/openclaw-qqbot@1.6.6': - resolution: {integrity: sha512-Zn0oj0gGukvywRWB7/m2Bq82capwYsjUv+d+wAPZTBbJioR5A7J/z4U8o2YJOvw6e2vW67LkPmqTFf9qJkDDUg==} + '@tencent-connect/openclaw-qqbot@1.6.7': + resolution: {integrity: sha512-0SynvYuS+/QZ5nmX1mTw46zR07Hiqzeo9SZqZPy2T39gLpxbg2Ifey01BfZDhM+KbRzIG+M0k2/R8jj0OzFxVA==} hasBin: true peerDependencies: openclaw: '*' @@ -2340,6 +2456,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/events@3.0.3': + resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} + '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} @@ -2508,8 +2627,8 @@ packages: '@wecom/aibot-node-sdk@1.0.4': resolution: {integrity: sha512-kZkrmlArq0NZyBvtOKw40m5nWTN1WlaA7XtqAo/1hn6N80P4c2mF99t3p1AMzj+dPo6OYvbsaelE8lbVWhkcBg==} - '@wecom/wecom-openclaw-plugin@2026.3.26': - resolution: {integrity: sha512-I7ZNO2UYQ0YyrRGhpqRKJgo7cCO3ONZtTO/C8sOUcg0KpELqEE2HVYP/7l5eWRB7v1HT0RI/SPnG3UTviGqAXA==} + '@wecom/wecom-openclaw-plugin@2026.3.30': + resolution: {integrity: sha512-nEFEliWjQhoBwiSuMniC4P6U8kSLTlGu3EV+jojIVMeL/z1m2PSu17w0u33YwYDvpJH/59GwipEQGmle+VO4aQ==} '@whiskeysockets/baileys@7.0.0-rc.9': resolution: {integrity: sha512-YFm5gKXfDP9byCXCW3OPHKXLzrAKzolzgVUlRosHHgwbnf2YOO3XknkMm6J7+F0ns8OA0uuSBhgkRHTDtqkacw==} @@ -2580,6 +2699,9 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + another-json@0.2.0: + resolution: {integrity: sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2703,6 +2825,9 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -2764,6 +2889,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + buffer-alloc-unsafe@1.1.0: resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} @@ -3404,6 +3532,10 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -3494,6 +3626,10 @@ packages: resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} + file-type@22.0.0: + resolution: {integrity: sha512-cmBmnYo8Zymabm2+qAP7jTFbKF10bQpYmxoGfuZbRFRcq00BRddJdGNH/P7GA1EMpJy5yQbqa9B7yROb3z8Ziw==} + engines: {node: '>=22'} + filelist@1.0.6: resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} @@ -3752,8 +3888,8 @@ packages: highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hono@4.12.8: - resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} + hono@4.12.9: + resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} engines: {node: '>=16.9.0'} hookified@1.15.1: @@ -4044,6 +4180,10 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -4113,6 +4253,10 @@ packages: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} @@ -4188,6 +4332,16 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + matrix-events-sdk@0.0.1: + resolution: {integrity: sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==} + + matrix-js-sdk@41.2.0: + resolution: {integrity: sha512-kVLDKm/bUlwlHoDKRemshs27LCnOnNpmsVKtbCOM5F5D/E1SkrKldou+vQ/lk4PyXTvu9/qglkd2m0pBwJ5opg==} + engines: {node: '>=22.0.0'} + + matrix-widget-api@1.17.0: + resolution: {integrity: sha512-5FHoo3iEP3Bdlv5jsYPWOqj+pGdFQNLWnJLiB0V7Ygne7bb+Gsj3ibyFyHWC6BVw+Z+tSW4ljHpO17I9TwStwQ==} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -4490,6 +4644,11 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-downloader-helper@2.1.11: + resolution: {integrity: sha512-882fH2C9AWdiPCwz/2beq5t8FGMZK9Dx8TJUOIxzMCbvG7XUKM5BuJwN5f0NKo4SCQK6jR4p2TPm54mYGdGchQ==} + engines: {node: '>=14.18'} + hasBin: true + node-edge-tts@1.2.10: resolution: {integrity: sha512-bV2i4XU54D45+US0Zm1HcJRkifuB3W438dWyuJEHLQdKxnuqlI1kim2MOvR6Q3XUQZvfF9PoDyR1Rt7aeXhPdQ==} hasBin: true @@ -4556,6 +4715,10 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + oidc-client-ts@3.5.0: + resolution: {integrity: sha512-l2q8l9CTCTOlbX+AnK4p3M+4CEpKpyQhle6blQkdFhm0IsBqsxm15bYaSa11G7pWdsYr6epdsRZxJpCyCRbT8A==} + engines: {node: '>=18'} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -4587,8 +4750,8 @@ packages: zod: optional: true - openclaw@2026.3.24: - resolution: {integrity: sha512-Bjk1+AiTsjbBaAl4NI0pQjtmG0Y2BFVcQg7veOJ15T7+orBN8RYBK/9cdqejIENDV5Mm7IPgls2WImYsd5aJOQ==} + openclaw@2026.3.28: + resolution: {integrity: sha512-n7ZS3zdimB2H/GfnylyG8xWXVrmlsSPHZdNEIEPe54Sl5XYuYD5yxilGYV0DWowgtsM5ysFEQMMMArdC/O77Jw==} engines: {node: '>=22.14.0'} hasBin: true peerDependencies: @@ -5176,6 +5339,10 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + sdp-transform@3.0.0: + resolution: {integrity: sha512-gfYVRGxjHkGF2NPeUWHw5u6T/KGFtS5/drPms73gaSuMaVHKCY3lpLnGDfswVQO0kddeePoti09AwhYP4zA8dQ==} + hasBin: true + semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} @@ -5449,10 +5616,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tar@7.5.12: - resolution: {integrity: sha512-9TsuLcdhOn4XztcQqhNyq1KOwOOED/3k58JAvtULiYqbO8B/0IBAAIE1hj0Svmm58k27TmcigyDI0deMlgG3uw==} - engines: {node: '>=18'} - tar@7.5.13: resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} engines: {node: '>=18'} @@ -5609,6 +5772,9 @@ packages: resolution: {integrity: sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==} engines: {node: '>=20.18.1'} + unhomoglyph@1.0.6: + resolution: {integrity: sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -5990,7 +6156,7 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@agentclientprotocol/sdk@0.16.1(zod@4.3.6)': + '@agentclientprotocol/sdk@0.17.0(zod@4.3.6)': dependencies: zod: 4.3.6 @@ -6125,43 +6291,43 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-bedrock@3.1017.0': + '@aws-sdk/client-bedrock@3.1020.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.24 - '@aws-sdk/credential-provider-node': 3.972.25 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.28 '@aws-sdk/middleware-host-header': 3.972.8 '@aws-sdk/middleware-logger': 3.972.8 - '@aws-sdk/middleware-recursion-detection': 3.972.8 - '@aws-sdk/middleware-user-agent': 3.972.25 - '@aws-sdk/region-config-resolver': 3.972.9 - '@aws-sdk/token-providers': 3.1017.0 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.27 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/token-providers': 3.1020.0 '@aws-sdk/types': 3.973.6 '@aws-sdk/util-endpoints': 3.996.5 '@aws-sdk/util-user-agent-browser': 3.972.8 - '@aws-sdk/util-user-agent-node': 3.973.11 + '@aws-sdk/util-user-agent-node': 3.973.13 '@smithy/config-resolver': 4.4.13 - '@smithy/core': 3.23.12 + '@smithy/core': 3.23.13 '@smithy/fetch-http-handler': 5.3.15 '@smithy/hash-node': 4.2.12 '@smithy/invalid-dependency': 4.2.12 '@smithy/middleware-content-length': 4.2.12 - '@smithy/middleware-endpoint': 4.4.27 - '@smithy/middleware-retry': 4.4.44 - '@smithy/middleware-serde': 4.2.15 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.45 + '@smithy/middleware-serde': 4.2.16 '@smithy/middleware-stack': 4.2.12 '@smithy/node-config-provider': 4.3.12 - '@smithy/node-http-handler': 4.5.0 + '@smithy/node-http-handler': 4.5.1 '@smithy/protocol-http': 5.3.12 - '@smithy/smithy-client': 4.12.7 + '@smithy/smithy-client': 4.12.8 '@smithy/types': 4.13.1 '@smithy/url-parser': 4.2.12 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.43 - '@smithy/util-defaults-mode-node': 4.2.47 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 '@smithy/util-endpoints': 3.3.3 '@smithy/util-middleware': 4.2.12 '@smithy/util-retry': 4.2.12 @@ -6186,6 +6352,22 @@ snapshots: '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 + '@aws-sdk/core@3.973.26': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/xml-builder': 3.972.16 + '@smithy/core': 3.23.13 + '@smithy/node-config-provider': 4.3.12 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/signature-v4': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-base64': 4.3.2 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.22': dependencies: '@aws-sdk/core': 3.973.24 @@ -6194,6 +6376,14 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.24': dependencies: '@aws-sdk/core': 3.973.24 @@ -6207,6 +6397,19 @@ snapshots: '@smithy/util-stream': 4.5.20 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.26': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/node-http-handler': 4.5.1 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-stream': 4.5.21 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.972.24': dependencies: '@aws-sdk/core': 3.973.24 @@ -6226,6 +6429,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.972.27': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-login': 3.972.27 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.27 + '@aws-sdk/credential-provider-web-identity': 3.972.27 + '@aws-sdk/nested-clients': 3.996.17 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-login@3.972.24': dependencies: '@aws-sdk/core': 3.973.24 @@ -6239,6 +6461,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-login@3.972.27': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.17 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-node@3.972.25': dependencies: '@aws-sdk/credential-provider-env': 3.972.22 @@ -6256,6 +6491,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.972.28': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-ini': 3.972.27 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.27 + '@aws-sdk/credential-provider-web-identity': 3.972.27 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-process@3.972.22': dependencies: '@aws-sdk/core': 3.973.24 @@ -6265,6 +6517,15 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.972.24': dependencies: '@aws-sdk/core': 3.973.24 @@ -6278,6 +6539,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.972.27': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.17 + '@aws-sdk/token-providers': 3.1020.0 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.24': dependencies: '@aws-sdk/core': 3.973.24 @@ -6290,6 +6564,18 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.27': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.17 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/eventstream-handler-node@3.972.11': dependencies: '@aws-sdk/types': 3.973.6 @@ -6325,6 +6611,14 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.972.9': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.972.25': dependencies: '@aws-sdk/core': 3.973.24 @@ -6336,6 +6630,17 @@ snapshots: '@smithy/util-retry': 4.2.12 tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.972.27': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@smithy/core': 3.23.13 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-retry': 4.2.12 + tslib: 2.8.1 + '@aws-sdk/middleware-websocket@3.972.13': dependencies: '@aws-sdk/types': 3.973.6 @@ -6394,6 +6699,57 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/nested-clients@3.996.17': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.27 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.13 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.13 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/hash-node': 4.2.12 + '@smithy/invalid-dependency': 4.2.12 + '@smithy/middleware-content-length': 4.2.12 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.45 + '@smithy/middleware-serde': 4.2.16 + '@smithy/middleware-stack': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/node-http-handler': 4.5.1 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.12 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.10': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/config-resolver': 4.4.13 + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@aws-sdk/region-config-resolver@3.972.9': dependencies: '@aws-sdk/types': 3.973.6 @@ -6426,6 +6782,18 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.1020.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.17 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/types@3.973.6': dependencies: '@smithy/types': 4.13.1 @@ -6466,12 +6834,27 @@ snapshots: '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.973.13': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.27 + '@aws-sdk/types': 3.973.6 + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-config-provider': 4.2.2 + tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.15': dependencies: '@smithy/types': 4.13.1 fast-xml-parser: 5.5.8 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.16': + dependencies: + '@smithy/types': 4.13.1 + fast-xml-parser: 5.5.8 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.2.4': {} '@babel/code-frame@7.29.0': @@ -6897,14 +7280,14 @@ snapshots: '@floating-ui/utils@0.2.11': {} - '@google/genai@1.46.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))': + '@google/genai@1.46.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))': dependencies: google-auth-library: 10.6.2 p-retry: 4.6.2 protobufjs: 7.5.4 ws: 8.20.0 optionalDependencies: - '@modelcontextprotocol/sdk': 1.27.1(zod@4.3.6) + '@modelcontextprotocol/sdk': 1.28.0(zod@4.3.6) transitivePeerDependencies: - bufferutil - supports-color @@ -6925,9 +7308,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@hono/node-server@1.19.11(hono@4.12.8)': + '@hono/node-server@1.19.11(hono@4.12.9)': dependencies: - hono: 4.12.8 + hono: 4.12.9 '@humanfs/core@0.19.1': {} @@ -7076,13 +7459,14 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@larksuite/openclaw-lark@2026.3.29(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': + '@larksuite/openclaw-lark@2026.3.30(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': dependencies: '@larksuiteoapi/node-sdk': 1.60.0 '@sinclair/typebox': 0.34.48 image-size: 2.0.2 - openclaw: 2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13) zod: 4.3.6 + optionalDependencies: + openclaw: 2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13) transitivePeerDependencies: - bufferutil - debug @@ -7199,9 +7583,9 @@ snapshots: std-env: 3.10.0 yoctocolors: 2.1.2 - '@mariozechner/pi-agent-core@0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': + '@mariozechner/pi-agent-core@0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: - '@mariozechner/pi-ai': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-ai': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -7211,11 +7595,11 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': + '@mariozechner/pi-ai@0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: '@anthropic-ai/sdk': 0.73.0(zod@4.3.6) '@aws-sdk/client-bedrock-runtime': 3.1017.0 - '@google/genai': 1.46.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)) + '@google/genai': 1.46.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)) '@mistralai/mistralai': 1.14.1 '@sinclair/typebox': 0.34.48 ajv: 8.18.0 @@ -7235,13 +7619,14 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': + '@mariozechner/pi-coding-agent@0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: '@mariozechner/jiti': 2.6.5 - '@mariozechner/pi-agent-core': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) - '@mariozechner/pi-ai': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) - '@mariozechner/pi-tui': 0.61.1 + '@mariozechner/pi-agent-core': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-ai': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-tui': 0.63.1 '@silvia-odwyer/photon-node': 0.3.4 + ajv: 8.18.0 chalk: 5.6.2 cli-highlight: 2.1.11 diff: 8.0.4 @@ -7267,7 +7652,7 @@ snapshots: - ws - zod - '@mariozechner/pi-tui@0.61.1': + '@mariozechner/pi-tui@0.63.1': dependencies: '@types/mime-types': 2.1.4 chalk: 5.6.2 @@ -7277,6 +7662,16 @@ snapshots: optionalDependencies: koffi: 2.15.2 + '@matrix-org/matrix-sdk-crypto-nodejs@0.4.0': + dependencies: + https-proxy-agent: 7.0.6 + node-downloader-helper: 2.1.11 + transitivePeerDependencies: + - supports-color + optional: true + + '@matrix-org/matrix-sdk-crypto-wasm@18.0.0': {} + '@mistralai/mistralai@1.14.1': dependencies: ws: 8.20.0 @@ -7286,9 +7681,9 @@ snapshots: - bufferutil - utf-8-validate - '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': + '@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)': dependencies: - '@hono/node-server': 1.19.11(hono@4.12.8) + '@hono/node-server': 1.19.11(hono@4.12.9) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -7298,7 +7693,7 @@ snapshots: eventsource-parser: 3.0.6 express: 5.2.1 express-rate-limit: 8.3.1(express@5.2.1) - hono: 4.12.8 + hono: 4.12.9 jose: 6.2.2 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -8019,6 +8414,19 @@ snapshots: '@smithy/uuid': 1.1.2 tslib: 2.8.1 + '@smithy/core@3.23.13': + dependencies: + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-stream': 4.5.21 + '@smithy/util-utf8': 4.2.2 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.12': dependencies: '@smithy/node-config-provider': 4.3.12 @@ -8102,6 +8510,17 @@ snapshots: '@smithy/util-middleware': 4.2.12 tslib: 2.8.1 + '@smithy/middleware-endpoint@4.4.28': + dependencies: + '@smithy/core': 3.23.13 + '@smithy/middleware-serde': 4.2.16 + '@smithy/node-config-provider': 4.3.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-middleware': 4.2.12 + tslib: 2.8.1 + '@smithy/middleware-retry@4.4.44': dependencies: '@smithy/node-config-provider': 4.3.12 @@ -8114,6 +8533,18 @@ snapshots: '@smithy/uuid': 1.1.2 tslib: 2.8.1 + '@smithy/middleware-retry@4.4.45': + dependencies: + '@smithy/node-config-provider': 4.3.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/service-error-classification': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.12 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + '@smithy/middleware-serde@4.2.15': dependencies: '@smithy/core': 3.23.12 @@ -8121,6 +8552,13 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@smithy/middleware-serde@4.2.16': + dependencies: + '@smithy/core': 3.23.13 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@smithy/middleware-stack@4.2.12': dependencies: '@smithy/types': 4.13.1 @@ -8141,6 +8579,13 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@smithy/node-http-handler@4.5.1': + dependencies: + '@smithy/protocol-http': 5.3.12 + '@smithy/querystring-builder': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@smithy/property-provider@4.2.12': dependencies: '@smithy/types': 4.13.1 @@ -8192,6 +8637,16 @@ snapshots: '@smithy/util-stream': 4.5.20 tslib: 2.8.1 + '@smithy/smithy-client@4.12.8': + dependencies: + '@smithy/core': 3.23.13 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-stack': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-stream': 4.5.21 + tslib: 2.8.1 + '@smithy/types@4.13.1': dependencies: tslib: 2.8.1 @@ -8237,6 +8692,13 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.44': + dependencies: + '@smithy/property-provider': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.47': dependencies: '@smithy/config-resolver': 4.4.13 @@ -8247,6 +8709,16 @@ snapshots: '@smithy/types': 4.13.1 tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.48': + dependencies: + '@smithy/config-resolver': 4.4.13 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/property-provider': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + '@smithy/util-endpoints@3.3.3': dependencies: '@smithy/node-config-provider': 4.3.12 @@ -8279,6 +8751,17 @@ snapshots: '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 + '@smithy/util-stream@4.5.21': + dependencies: + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/node-http-handler': 4.5.1 + '@smithy/types': 4.13.1 + '@smithy/util-base64': 4.3.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + '@smithy/util-uri-escape@4.2.2': dependencies: tslib: 2.8.1 @@ -8297,13 +8780,13 @@ snapshots: dependencies: tslib: 2.8.1 - '@soimy/dingtalk@3.5.1(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': + '@soimy/dingtalk@3.5.1(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': dependencies: axios: 1.13.6(debug@4.4.3) dingtalk-stream: 2.1.5 form-data: 4.0.5 mammoth: 1.12.0 - openclaw: 2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13) + openclaw: 2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13) pdf-parse: 2.4.5 zod: 4.3.6 transitivePeerDependencies: @@ -8321,9 +8804,9 @@ snapshots: '@telegraf/types@7.1.0': optional: true - '@tencent-connect/openclaw-qqbot@1.6.6(openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': + '@tencent-connect/openclaw-qqbot@1.6.7(openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13))': dependencies: - openclaw: 2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13) + openclaw: 2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13) '@tencent-weixin/openclaw-weixin@2.1.1': dependencies: @@ -8420,6 +8903,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/events@3.0.3': {} + '@types/fs-extra@9.0.13': dependencies: '@types/node': 25.5.0 @@ -8648,7 +9133,7 @@ snapshots: - debug - utf-8-validate - '@wecom/wecom-openclaw-plugin@2026.3.26': + '@wecom/wecom-openclaw-plugin@2026.3.30': dependencies: '@wecom/aibot-node-sdk': 1.0.4 file-type: 21.3.4 @@ -8725,6 +9210,8 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + another-json@0.2.0: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -8871,6 +9358,8 @@ snapshots: balanced-match@4.0.4: {} + base-x@5.0.1: {} + base64-js@1.5.1: {} baseline-browser-mapping@2.10.10: {} @@ -8939,6 +9428,10 @@ snapshots: node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) + bs58@6.0.0: + dependencies: + base-x: 5.0.1 + buffer-alloc-unsafe@1.1.0: optional: true @@ -9700,6 +10193,8 @@ snapshots: eventemitter3@5.0.4: {} + events@3.3.0: {} + eventsource-parser@3.0.6: {} eventsource@3.0.7: @@ -9821,6 +10316,15 @@ snapshots: transitivePeerDependencies: - supports-color + file-type@22.0.0: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + filelist@1.0.6: dependencies: minimatch: 5.1.9 @@ -10163,7 +10667,7 @@ snapshots: highlight.js@10.7.3: {} - hono@4.12.8: {} + hono@4.12.9: {} hookified@1.15.1: {} @@ -10436,6 +10940,8 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 + jwt-decode@4.0.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -10500,6 +11006,8 @@ snapshots: is-unicode-supported: 2.1.0 yoctocolors: 2.1.2 + loglevel@1.9.2: {} + long@4.0.0: {} long@5.3.2: {} @@ -10587,6 +11095,30 @@ snapshots: math-intrinsics@1.1.0: {} + matrix-events-sdk@0.0.1: {} + + matrix-js-sdk@41.2.0: + dependencies: + '@babel/runtime': 7.29.2 + '@matrix-org/matrix-sdk-crypto-wasm': 18.0.0 + another-json: 0.2.0 + bs58: 6.0.0 + content-type: 1.0.5 + jwt-decode: 4.0.0 + loglevel: 1.9.2 + matrix-events-sdk: 0.0.1 + matrix-widget-api: 1.17.0 + oidc-client-ts: 3.5.0 + p-retry: 7.1.1 + sdp-transform: 3.0.0 + unhomoglyph: 1.0.6 + uuid: 13.0.0 + + matrix-widget-api@1.17.0: + dependencies: + '@types/events': 3.0.3 + events: 3.3.0 + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -11081,6 +11613,9 @@ snapshots: node-domexception@1.0.0: {} + node-downloader-helper@2.1.11: + optional: true + node-edge-tts@1.2.10: dependencies: https-proxy-agent: 7.0.6 @@ -11148,6 +11683,10 @@ snapshots: obug@2.1.1: {} + oidc-client-ts@3.5.0: + dependencies: + jwt-decode: 4.0.0 + on-exit-leak-free@2.1.2: {} on-finished@2.4.1: @@ -11171,20 +11710,20 @@ snapshots: ws: 8.20.0 zod: 4.3.6 - openclaw@2026.3.24(@napi-rs/canvas@0.1.97)(encoding@0.1.13): + openclaw@2026.3.28(@napi-rs/canvas@0.1.97)(encoding@0.1.13): dependencies: - '@agentclientprotocol/sdk': 0.16.1(zod@4.3.6) + '@agentclientprotocol/sdk': 0.17.0(zod@4.3.6) '@anthropic-ai/vertex-sdk': 0.14.4(encoding@0.1.13)(zod@4.3.6) - '@aws-sdk/client-bedrock': 3.1017.0 + '@aws-sdk/client-bedrock': 3.1020.0 '@clack/prompts': 1.1.0 '@homebridge/ciao': 1.3.5 '@line/bot-sdk': 10.6.0 '@lydell/node-pty': 1.2.0-beta.3 - '@mariozechner/pi-agent-core': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) - '@mariozechner/pi-ai': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) - '@mariozechner/pi-coding-agent': 0.61.1(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) - '@mariozechner/pi-tui': 0.61.1 - '@modelcontextprotocol/sdk': 1.27.1(zod@4.3.6) + '@mariozechner/pi-agent-core': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-ai': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-coding-agent': 0.63.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + '@mariozechner/pi-tui': 0.63.1 + '@modelcontextprotocol/sdk': 1.28.0(zod@4.3.6) '@mozilla/readability': 0.6.0 '@napi-rs/canvas': 0.1.97 '@sinclair/typebox': 0.34.48 @@ -11196,9 +11735,9 @@ snapshots: croner: 10.0.1 dotenv: 17.3.1 express: 5.2.1 - file-type: 21.3.4 + file-type: 22.0.0 gaxios: 7.1.4 - hono: 4.12.8 + hono: 4.12.9 ipaddr.js: 2.3.0 jiti: 2.6.1 json5: 2.2.3 @@ -11206,6 +11745,7 @@ snapshots: linkedom: 0.18.12 long: 5.3.2 markdown-it: 14.1.1 + matrix-js-sdk: 41.2.0 node-edge-tts: 1.2.10 osc-progress: 0.3.0 pdfjs-dist: 5.5.207 @@ -11213,7 +11753,7 @@ snapshots: qrcode-terminal: 0.12.0 sharp: 0.34.5 sqlite-vec: 0.1.7 - tar: 7.5.12 + tar: 7.5.13 tslog: 4.10.2 undici: 7.24.6 uuid: 13.0.0 @@ -11221,6 +11761,7 @@ snapshots: yaml: 2.8.3 zod: 4.3.6 optionalDependencies: + '@matrix-org/matrix-sdk-crypto-nodejs': 0.4.0 openshell: 0.1.0(encoding@0.1.13) transitivePeerDependencies: - '@cfworker/json-schema' @@ -11884,6 +12425,8 @@ snapshots: scheduler@0.27.0: {} + sdp-transform@3.0.0: {} + semver-compare@1.0.0: optional: true @@ -12216,14 +12759,6 @@ snapshots: - tsx - yaml - tar@7.5.12: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.3 - minizlib: 3.1.0 - yallist: 5.0.0 - tar@7.5.13: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -12373,6 +12908,8 @@ snapshots: undici@7.24.6: {} + unhomoglyph@1.0.6: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 diff --git a/src/assets/providers/index.ts b/src/assets/providers/index.ts index b1bd376cb..70aaa090a 100644 --- a/src/assets/providers/index.ts +++ b/src/assets/providers/index.ts @@ -20,7 +20,7 @@ export const providerIcons: Record = { siliconflow, 'minimax-portal': minimaxPortal, 'minimax-portal-cn': minimaxPortal, - 'qwen-portal': qwenPortal, + 'modelstudio': qwenPortal, ollama, custom, }; diff --git a/src/components/settings/ProvidersSettings.tsx b/src/components/settings/ProvidersSettings.tsx index 4638408f3..a9199e03d 100644 --- a/src/components/settings/ProvidersSettings.tsx +++ b/src/components/settings/ProvidersSettings.tsx @@ -1134,6 +1134,9 @@ function AddProviderDialog({ }; const availableTypes = PROVIDER_TYPE_INFO.filter((type) => { + // Skip providers that are temporarily hidden from the UI. + if (type.hidden) return false; + // MiniMax portal variants are mutually exclusive — hide BOTH variants // when either one already exists (account may have vendorId of either variant). const hasMinimax = existingVendorIds.has('minimax-portal') || existingVendorIds.has('minimax-portal-cn'); diff --git a/src/lib/providers.ts b/src/lib/providers.ts index 681d31030..4cb1af123 100644 --- a/src/lib/providers.ts +++ b/src/lib/providers.ts @@ -16,7 +16,7 @@ export const PROVIDER_TYPES = [ 'siliconflow', 'minimax-portal', 'minimax-portal-cn', - 'qwen-portal', + 'modelstudio', 'ollama', 'custom', ] as const; @@ -32,7 +32,7 @@ export const BUILTIN_PROVIDER_TYPES = [ 'siliconflow', 'minimax-portal', 'minimax-portal-cn', - 'qwen-portal', + 'modelstudio', 'ollama', ] as const; @@ -79,6 +79,8 @@ export interface ProviderTypeInfo { codePlanPresetBaseUrl?: string; codePlanPresetModelId?: string; codePlanDocsUrl?: string; + /** If true, this provider is not shown in the "Add Provider" dialog. */ + hidden?: boolean; } export type ProviderAuthMode = @@ -172,7 +174,7 @@ export const PROVIDER_TYPE_INFO: ProviderTypeInfo[] = [ { id: 'moonshot', name: 'Moonshot (CN)', icon: '🌙', placeholder: 'sk-...', model: 'Kimi', requiresApiKey: true, defaultBaseUrl: 'https://api.moonshot.cn/v1', defaultModelId: 'kimi-k2.5', docsUrl: 'https://platform.moonshot.cn/' }, { id: 'siliconflow', name: 'SiliconFlow (CN)', icon: '🌊', placeholder: 'sk-...', model: 'Multi-Model', requiresApiKey: true, defaultBaseUrl: 'https://api.siliconflow.cn/v1', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'deepseek-ai/DeepSeek-V3', defaultModelId: 'deepseek-ai/DeepSeek-V3', docsUrl: 'https://docs.siliconflow.cn/cn/userguide/introduction' }, { id: 'minimax-portal', name: 'MiniMax (Global)', icon: '☁️', placeholder: 'sk-...', model: 'MiniMax', requiresApiKey: false, isOAuth: true, supportsApiKey: true, defaultModelId: 'MiniMax-M2.7', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'MiniMax-M2.7', apiKeyUrl: 'https://platform.minimax.io' }, - { id: 'qwen-portal', name: 'Qwen (Global)', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', requiresApiKey: false, isOAuth: true, defaultModelId: 'coder-model', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'coder-model' }, + { id: 'modelstudio', name: 'Model Studio', icon: '☁️', placeholder: 'sk-...', model: 'Qwen', requiresApiKey: true, defaultBaseUrl: 'https://coding.dashscope.aliyuncs.com/v1', showBaseUrl: true, defaultModelId: 'qwen3.5-plus', showModelId: true, showModelIdInDevModeOnly: true, modelIdPlaceholder: 'qwen3.5-plus', apiKeyUrl: 'https://bailian.console.aliyun.com/', hidden: true }, { id: 'ark', name: 'ByteDance Ark', icon: 'A', placeholder: 'your-ark-api-key', model: 'Doubao', requiresApiKey: true, defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'ep-20260228000000-xxxxx', docsUrl: 'https://www.volcengine.com/', codePlanPresetBaseUrl: 'https://ark.cn-beijing.volces.com/api/coding/v3', codePlanPresetModelId: 'ark-code-latest', codePlanDocsUrl: 'https://www.volcengine.com/docs/82379/1928261?lang=zh' }, { id: 'ollama', name: 'Ollama', icon: '🦙', placeholder: 'Not required', requiresApiKey: false, defaultBaseUrl: 'http://localhost:11434/v1', showBaseUrl: true, showModelId: true, modelIdPlaceholder: 'qwen3:latest' }, { diff --git a/src/stores/gateway.ts b/src/stores/gateway.ts index 21d644dd1..c3bf7789b 100644 --- a/src/stores/gateway.ts +++ b/src/stores/gateway.ts @@ -10,6 +10,7 @@ import type { GatewayStatus } from '../types/gateway'; let gatewayInitPromise: Promise | null = null; let gatewayEventUnsubscribers: Array<() => void> | null = null; +let gatewayReconcileTimer: ReturnType | null = null; const gatewayEventDedupe = new Map(); const GATEWAY_EVENT_DEDUPE_TTL_MS = 30_000; const LOAD_SESSIONS_MIN_INTERVAL_MS = 1_200; @@ -283,6 +284,45 @@ export const useGatewayStore = create((set, get) => ({ }, )); gatewayEventUnsubscribers = unsubscribers; + + // Periodic reconciliation safety net: every 30 seconds, check if the + // renderer's view of gateway state has drifted from main process truth. + // This catches any future one-off IPC delivery failures without adding + // a constant polling load (single lightweight IPC invoke per interval). + // Clear any previous timer first to avoid leaks during HMR reloads. + if (gatewayReconcileTimer !== null) { + clearInterval(gatewayReconcileTimer); + } + gatewayReconcileTimer = setInterval(() => { + const ipc = window.electron?.ipcRenderer; + if (!ipc) return; + ipc.invoke('gateway:status') + .then((result: unknown) => { + const latest = result as GatewayStatus; + const current = get().status; + if (latest.state !== current.state) { + console.info( + `[gateway-store] reconciled stale state: ${current.state} → ${latest.state}`, + ); + set({ status: latest }); + } + }) + .catch(() => { /* ignore */ }); + }, 30_000); + } + + // Re-fetch status after IPC listeners are registered to close the race + // window: if the gateway transitioned (e.g. starting → running) between + // the initial fetch and the IPC listener setup, that event was lost. + // A second fetch guarantees we pick up the latest state. + try { + const refreshed = await hostApiFetch('/api/gateway/status'); + const current = get().status; + if (refreshed.state !== current.state) { + set({ status: refreshed }); + } + } catch { + // Best-effort; the IPC listener will eventually reconcile. } } catch (error) { console.error('Failed to initialize Gateway:', error); diff --git a/tests/unit/gateway-restart-governor.test.ts b/tests/unit/gateway-restart-governor.test.ts index a1dfdfbfd..a3060bfed 100644 --- a/tests/unit/gateway-restart-governor.test.ts +++ b/tests/unit/gateway-restart-governor.test.ts @@ -2,15 +2,13 @@ import { describe, expect, it } from 'vitest'; import { GatewayRestartGovernor } from '@electron/gateway/restart-governor'; describe('GatewayRestartGovernor', () => { - it('suppresses restart during exponential cooldown window', () => { - const governor = new GatewayRestartGovernor({ - baseCooldownMs: 1000, - maxCooldownMs: 8000, - maxRestartsPerWindow: 10, - windowMs: 60000, - stableResetMs: 60000, - circuitOpenMs: 60000, - }); + it('allows first restart unconditionally', () => { + const governor = new GatewayRestartGovernor(); + expect(governor.decide(1000).allow).toBe(true); + }); + + it('suppresses restart during cooldown window', () => { + const governor = new GatewayRestartGovernor({ cooldownMs: 1000 }); expect(governor.decide(1000).allow).toBe(true); governor.recordExecuted(1000); @@ -18,76 +16,26 @@ describe('GatewayRestartGovernor', () => { const blocked = governor.decide(1500); expect(blocked.allow).toBe(false); expect(blocked.allow ? '' : blocked.reason).toBe('cooldown_active'); - expect(blocked.allow ? 0 : blocked.retryAfterMs).toBeGreaterThan(0); + expect(blocked.allow ? 0 : blocked.retryAfterMs).toBe(500); - expect(governor.decide(3000).allow).toBe(true); + // After cooldown expires, restart is allowed again + expect(governor.decide(2001).allow).toBe(true); }); - it('opens circuit after restart budget is exceeded', () => { - const governor = new GatewayRestartGovernor({ - maxRestartsPerWindow: 2, - windowMs: 60000, - baseCooldownMs: 0, - maxCooldownMs: 0, - stableResetMs: 120000, - circuitOpenMs: 30000, - }); + it('allows unlimited restarts as long as cooldown is respected', () => { + const governor = new GatewayRestartGovernor({ cooldownMs: 100 }); - expect(governor.decide(1000).allow).toBe(true); - governor.recordExecuted(1000); - expect(governor.decide(2000).allow).toBe(true); - governor.recordExecuted(2000); - - const budgetBlocked = governor.decide(3000); - expect(budgetBlocked.allow).toBe(false); - expect(budgetBlocked.allow ? '' : budgetBlocked.reason).toBe('budget_exceeded'); - - const circuitBlocked = governor.decide(4000); - expect(circuitBlocked.allow).toBe(false); - expect(circuitBlocked.allow ? '' : circuitBlocked.reason).toBe('circuit_open'); - - expect(governor.decide(62001).allow).toBe(true); + // 10 restarts in a row, each respecting cooldown — all should be allowed + for (let i = 0; i < 10; i++) { + const t = 1000 + i * 200; + expect(governor.decide(t).allow).toBe(true); + governor.recordExecuted(t); + } }); - it('resets consecutive backoff after stable running period', () => { - const governor = new GatewayRestartGovernor({ - baseCooldownMs: 1000, - maxCooldownMs: 8000, - maxRestartsPerWindow: 10, - windowMs: 600000, - stableResetMs: 5000, - circuitOpenMs: 60000, - }); - - governor.recordExecuted(0); - governor.recordExecuted(1000); - const blockedBeforeStable = governor.decide(2500); - expect(blockedBeforeStable.allow).toBe(false); - expect(blockedBeforeStable.allow ? '' : blockedBeforeStable.reason).toBe('cooldown_active'); - - governor.onRunning(3000); - const allowedAfterStable = governor.decide(9000); - expect(allowedAfterStable.allow).toBe(true); - }); - - it('resets time-based state when clock moves backwards', () => { - const governor = new GatewayRestartGovernor({ - maxRestartsPerWindow: 2, - windowMs: 60000, - baseCooldownMs: 1000, - maxCooldownMs: 8000, - stableResetMs: 60000, - circuitOpenMs: 30000, - }); - - governor.recordExecuted(10_000); - governor.recordExecuted(11_000); - const blocked = governor.decide(11_500); - expect(blocked.allow).toBe(false); - - // Simulate clock rewind and verify stale guard state does not lock out restarts. - const afterRewind = governor.decide(9_000); - expect(afterRewind.allow).toBe(true); + it('onRunning is a no-op but does not throw', () => { + const governor = new GatewayRestartGovernor(); + expect(() => governor.onRunning(1000)).not.toThrow(); }); it('wraps counters safely at MAX_SAFE_INTEGER', () => { @@ -103,4 +51,12 @@ describe('GatewayRestartGovernor', () => { suppressedTotal: 0, }); }); + + it('getObservability returns circuit_open_until as always 0', () => { + const governor = new GatewayRestartGovernor(); + governor.recordExecuted(1000); + const obs = governor.getObservability(); + expect(obs.circuit_open_until).toBe(0); + expect(obs.executed_total).toBe(1); + }); }); diff --git a/tests/unit/provider-model-sync.test.ts b/tests/unit/provider-model-sync.test.ts index bfc47b373..140c53926 100644 --- a/tests/unit/provider-model-sync.test.ts +++ b/tests/unit/provider-model-sync.test.ts @@ -61,14 +61,22 @@ describe('provider-model-sync', () => { }); }); - it('returns null for oauth and multi-instance providers', () => { + it('builds modelstudio payload and returns null for multi-instance providers', () => { expect( buildNonOAuthAgentProviderUpdate( - providerConfig({ type: 'qwen-portal', id: 'qwen-portal' }), - 'qwen-portal', - 'qwen-portal/coder-model', + providerConfig({ type: 'modelstudio', id: 'modelstudio' }), + 'modelstudio', + 'modelstudio/qwen3.5-plus', ), - ).toBeNull(); + ).toEqual({ + providerKey: 'modelstudio', + entry: { + baseUrl: 'https://coding.dashscope.aliyuncs.com/v1', + api: 'openai-completions', + apiKey: 'MODELSTUDIO_API_KEY', + models: [{ id: 'qwen3.5-plus', name: 'qwen3.5-plus' }], + }, + }); expect( buildNonOAuthAgentProviderUpdate( diff --git a/tests/unit/providers.test.ts b/tests/unit/providers.test.ts index e1d6cbab5..bec958a1a 100644 --- a/tests/unit/providers.test.ts +++ b/tests/unit/providers.test.ts @@ -58,7 +58,7 @@ describe('provider metadata', () => { it('keeps builtin provider sources in sync', () => { expect(BUILTIN_PROVIDER_TYPES).toEqual( - expect.arrayContaining(['anthropic', 'openai', 'google', 'openrouter', 'ark', 'moonshot', 'siliconflow', 'minimax-portal', 'minimax-portal-cn', 'qwen-portal', 'ollama']) + expect.arrayContaining(['anthropic', 'openai', 'google', 'openrouter', 'ark', 'moonshot', 'siliconflow', 'minimax-portal', 'minimax-portal-cn', 'modelstudio', 'ollama']) ); }); @@ -125,13 +125,13 @@ describe('provider metadata', () => { const google = PROVIDER_TYPE_INFO.find((provider) => provider.id === 'google'); const minimax = PROVIDER_TYPE_INFO.find((provider) => provider.id === 'minimax-portal'); const minimaxCn = PROVIDER_TYPE_INFO.find((provider) => provider.id === 'minimax-portal-cn'); - const qwen = PROVIDER_TYPE_INFO.find((provider) => provider.id === 'qwen-portal'); + const qwen = PROVIDER_TYPE_INFO.find((provider) => provider.id === 'modelstudio'); expect(openai).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'gpt-5.4' }); expect(google).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'gemini-3-pro-preview' }); expect(minimax).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'MiniMax-M2.7' }); expect(minimaxCn).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'MiniMax-M2.7' }); - expect(qwen).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'coder-model' }); + expect(qwen).toMatchObject({ showModelId: true, showModelIdInDevModeOnly: true, defaultModelId: 'qwen3.5-plus' }); expect(shouldShowProviderModelId(openai, false)).toBe(false); expect(shouldShowProviderModelId(google, false)).toBe(false); @@ -149,7 +149,7 @@ describe('provider metadata', () => { expect(resolveProviderModelForSave(google, ' ', true)).toBe('gemini-3-pro-preview'); expect(resolveProviderModelForSave(minimax, ' ', true)).toBe('MiniMax-M2.7'); expect(resolveProviderModelForSave(minimaxCn, ' ', true)).toBe('MiniMax-M2.7'); - expect(resolveProviderModelForSave(qwen, ' ', true)).toBe('coder-model'); + expect(resolveProviderModelForSave(qwen, ' ', true)).toBe('qwen3.5-plus'); }); it('saves OpenRouter model overrides by default and SiliconFlow only in dev mode', () => {