From 9a7160786a7dbd21469fad73992158e415e4686e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 30 Jan 2026 03:15:10 +0100 Subject: [PATCH] refactor: rename to openclaw --- AGENTS.md | 46 +- CHANGELOG.md | 454 +++++++----- CONTRIBUTING.md | 12 +- Dockerfile | 10 +- Dockerfile.sandbox-browser | 6 +- README.md | 353 +++++---- SECURITY.md | 16 +- Swabble/Package.resolved | 38 +- appcast.xml | 62 +- apps/android/README.md | 10 +- apps/android/app/build.gradle.kts | 8 +- apps/android/app/src/main/AndroidManifest.xml | 2 +- .../openclaw}/android/CameraHudState.kt | 2 +- .../openclaw}/android/DeviceNames.kt | 2 +- .../openclaw}/android/LocationMode.kt | 2 +- .../openclaw}/android/MainActivity.kt | 8 +- .../openclaw}/android/MainViewModel.kt | 14 +- .../molt => ai/openclaw}/android/NodeApp.kt | 2 +- .../android/NodeForegroundService.kt | 10 +- .../openclaw}/android/NodeRuntime.kt | 163 ++--- .../openclaw}/android/PermissionRequester.kt | 4 +- .../android/ScreenCaptureRequester.kt | 4 +- .../openclaw}/android/SecurePrefs.kt | 80 +-- .../openclaw}/android/SessionKey.kt | 2 +- .../openclaw}/android/VoiceWakeMode.kt | 2 +- .../molt => ai/openclaw}/android/WakeWords.kt | 2 +- .../openclaw}/android/chat/ChatController.kt | 4 +- .../openclaw}/android/chat/ChatModels.kt | 2 +- .../android/gateway/BonjourEscapes.kt | 2 +- .../android/gateway/DeviceAuthStore.kt | 4 +- .../android/gateway/DeviceIdentityStore.kt | 12 +- .../android/gateway/GatewayDiscovery.kt | 12 +- .../android/gateway/GatewayEndpoint.kt | 2 +- .../android/gateway/GatewayProtocol.kt | 2 +- .../android/gateway/GatewaySession.kt | 6 +- .../openclaw}/android/gateway/GatewayTls.kt | 2 +- .../android/node/CameraCaptureManager.kt | 8 +- .../android/node/CanvasController.kt | 10 +- .../openclaw}/android/node/JpegSizeLimiter.kt | 2 +- .../android/node/LocationCaptureManager.kt | 2 +- .../android/node/ScreenRecordManager.kt | 12 +- .../openclaw}/android/node/SmsManager.kt | 4 +- .../protocol/OpenClawCanvasA2UIAction.kt} | 6 +- .../protocol/OpenClawProtocolConstants.kt} | 16 +- .../openclaw}/android/tools/ToolDisplay.kt | 2 +- .../openclaw}/android/ui/CameraHudOverlay.kt | 2 +- .../openclaw}/android/ui/ChatSheet.kt | 6 +- .../openclaw/android/ui/OpenClawTheme.kt} | 4 +- .../openclaw}/android/ui/RootScreen.kt | 40 +- .../openclaw}/android/ui/SettingsSheet.kt | 20 +- .../openclaw}/android/ui/StatusPill.kt | 2 +- .../openclaw}/android/ui/TalkOrbOverlay.kt | 2 +- .../openclaw}/android/ui/chat/ChatComposer.kt | 6 +- .../openclaw}/android/ui/chat/ChatMarkdown.kt | 2 +- .../android/ui/chat/ChatMessageListCard.kt | 8 +- .../android/ui/chat/ChatMessageViews.kt | 10 +- .../android/ui/chat/ChatSessionsDialog.kt | 4 +- .../android/ui/chat/ChatSheetContent.kt | 6 +- .../android/ui/chat/SessionFilters.kt | 4 +- .../android/voice/StreamingMediaDataSource.kt | 2 +- .../android/voice/TalkDirectiveParser.kt | 2 +- .../android/voice/TalkModeManager.kt | 8 +- .../voice/VoiceWakeCommandExtractor.kt | 2 +- .../android/voice/VoiceWakeManager.kt | 2 +- .../app/src/main/res/values/strings.xml | 2 +- .../app/src/main/res/values/themes.xml | 2 +- .../main/res/xml/network_security_config.xml | 2 +- .../android/NodeForegroundServiceTest.kt | 2 +- .../openclaw}/android/WakeWordsTest.kt | 18 +- .../android/gateway/BonjourEscapesTest.kt | 4 +- .../CanvasControllerSnapshotParamsTest.kt | 2 +- .../android/node/JpegSizeLimiterTest.kt | 2 +- .../openclaw}/android/node/SmsManagerTest.kt | 2 +- .../protocol/OpenClawCanvasA2UIActionTest.kt} | 16 +- .../protocol/OpenClawProtocolConstantsTest.kt | 35 + .../android/ui/chat/SessionFiltersTest.kt | 4 +- .../android/voice/TalkDirectiveParserTest.kt | 2 +- .../voice/VoiceWakeCommandExtractorTest.kt | 6 +- .../protocol/ClawdbotProtocolConstantsTest.kt | 35 - apps/android/settings.gradle.kts | 2 +- apps/ios/README.md | 6 +- .../ios/Sources/Camera/CameraController.swift | 12 +- apps/ios/Sources/Chat/ChatSheet.swift | 10 +- .../Chat/IOSGatewayChatTransport.swift | 32 +- .../Gateway/GatewayConnectionController.swift | 54 +- .../Gateway/GatewayDiscoveryModel.swift | 8 +- .../Gateway/GatewaySettingsStore.swift | 111 +-- apps/ios/Sources/Info.plist | 16 +- .../Sources/Location/LocationService.swift | 10 +- apps/ios/Sources/Model/NodeAppModel.swift | 152 ++-- .../{ClawdbotApp.swift => OpenClawApp.swift} | 2 +- .../ios/Sources/Screen/ScreenController.swift | 26 +- .../Sources/Screen/ScreenRecordService.swift | 2 +- apps/ios/Sources/Screen/ScreenTab.swift | 2 +- apps/ios/Sources/Screen/ScreenWebView.swift | 2 +- apps/ios/Sources/Settings/SettingsTab.swift | 20 +- .../Settings/VoiceWakeWordsSettingsView.swift | 2 +- apps/ios/Sources/Voice/TalkModeManager.swift | 4 +- .../Sources/Voice/VoiceWakePreferences.swift | 2 +- apps/ios/SwiftSources.input.xcfilelist | 64 +- apps/ios/Tests/AppCoverageTests.swift | 2 +- .../Tests/CameraControllerClampTests.swift | 2 +- .../Tests/CameraControllerErrorTests.swift | 2 +- apps/ios/Tests/DeepLinkParserTests.swift | 16 +- .../GatewayConnectionControllerTests.swift | 20 +- .../Tests/GatewayDiscoveryModelTests.swift | 2 +- apps/ios/Tests/GatewayEndpointIDTests.swift | 14 +- .../ios/Tests/GatewaySettingsStoreTests.swift | 2 +- .../Tests/IOSGatewayChatTransportTests.swift | 4 +- apps/ios/Tests/Info.plist | 2 +- apps/ios/Tests/KeychainStoreTests.swift | 2 +- apps/ios/Tests/NodeAppModelInvokeTests.swift | 34 +- apps/ios/Tests/ScreenControllerTests.swift | 4 +- apps/ios/Tests/ScreenRecordServiceTests.swift | 2 +- .../SettingsNetworkingHelpersTests.swift | 2 +- apps/ios/Tests/SwiftUIRenderSmokeTests.swift | 6 +- .../ios/Tests/VoiceWakeGatewaySyncTests.swift | 6 +- .../VoiceWakeManagerExtractCommandTests.swift | 28 +- .../Tests/VoiceWakeManagerStateTests.swift | 10 +- .../ios/Tests/VoiceWakePreferencesTests.swift | 6 +- apps/ios/fastlane/Fastfile | 4 +- apps/ios/fastlane/SETUP.md | 2 +- apps/ios/project.yml | 64 +- .../{clawdbot-mac.png => openclaw-mac.png} | Bin apps/macos/Icon.icon/icon.json | 4 +- apps/macos/Package.swift | 56 +- apps/macos/README.md | 4 +- .../macos/Sources/Moltbot/ClawdbotPaths.swift | 38 - apps/macos/Sources/Moltbot/Constants.swift | 44 -- .../Sources/MoltbotMacCLI/TypeAliases.swift | 5 - .../{Moltbot => OpenClaw}/AboutSettings.swift | 17 +- .../{Moltbot => OpenClaw}/AgeFormatting.swift | 0 .../AgentEventStore.swift | 0 .../AgentEventsWindow.swift | 8 +- .../AgentWorkspace.swift | 8 +- .../AnthropicAuthControls.swift | 18 +- .../AnthropicOAuth.swift | 28 +- .../AnthropicOAuthCodeState.swift | 0 .../AnyCodable+Helpers.swift | 20 +- .../{Moltbot => OpenClaw}/AppState.swift | 26 +- .../AudioInputDeviceObserver.swift | 2 +- .../CLIInstallPrompter.swift | 6 +- .../{Moltbot => OpenClaw}/CLIInstaller.swift | 10 +- .../CameraCaptureService.swift | 10 +- .../CanvasA2UIActionMessageHandler.swift | 23 +- .../CanvasChromeContainerView.swift | 0 .../CanvasFileWatcher.swift | 2 +- .../{Moltbot => OpenClaw}/CanvasManager.swift | 10 +- .../{Moltbot => OpenClaw}/CanvasScheme.swift | 3 +- .../CanvasSchemeHandler.swift | 8 +- .../{Moltbot => OpenClaw}/CanvasWindow.swift | 2 +- .../CanvasWindowController+Helpers.swift | 2 +- .../CanvasWindowController+Navigation.swift | 7 +- .../CanvasWindowController+Testing.swift | 0 .../CanvasWindowController+Window.swift | 4 +- .../CanvasWindowController.swift | 40 +- .../ChannelConfigForm.swift | 0 .../ChannelsSettings+ChannelSections.swift | 0 .../ChannelsSettings+ChannelState.swift | 2 +- .../ChannelsSettings+Helpers.swift | 0 .../ChannelsSettings+View.swift | 0 .../ChannelsSettings.swift | 0 .../ChannelsStore+Config.swift | 4 +- .../ChannelsStore+Lifecycle.swift | 2 +- .../{Moltbot => OpenClaw}/ChannelsStore.swift | 2 +- .../CommandResolver.swift | 113 +-- .../ConfigFileWatcher.swift | 2 +- .../ConfigSchemaSupport.swift | 0 .../ConfigSettings.swift | 2 +- .../{Moltbot => OpenClaw}/ConfigStore.swift | 6 +- .../ConnectionModeCoordinator.swift | 2 +- .../ConnectionModeResolver.swift | 2 +- apps/macos/Sources/OpenClaw/Constants.swift | 46 ++ .../ContextMenuCardView.swift | 0 .../ContextUsageBar.swift | 0 .../ControlChannel.swift | 30 +- .../CostUsageMenuView.swift | 0 .../CritterIconRenderer.swift | 0 .../CritterStatusLabel+Behavior.swift | 0 .../CritterStatusLabel.swift | 0 .../CronJobEditor+Helpers.swift | 2 +- .../CronJobEditor+Testing.swift | 0 .../{Moltbot => OpenClaw}/CronJobEditor.swift | 8 +- .../{Moltbot => OpenClaw}/CronJobsStore.swift | 6 +- .../{Moltbot => OpenClaw}/CronModels.swift | 0 .../CronSettings+Actions.swift | 2 +- .../CronSettings+Helpers.swift | 0 .../CronSettings+Layout.swift | 0 .../CronSettings+Rows.swift | 0 .../CronSettings+Testing.swift | 2 +- .../{Moltbot => OpenClaw}/CronSettings.swift | 0 .../{Moltbot => OpenClaw}/DebugActions.swift | 13 +- .../{Moltbot => OpenClaw}/DebugSettings.swift | 28 +- .../{Moltbot => OpenClaw}/DeepLinks.swift | 8 +- .../DeviceModelCatalog.swift | 0 .../DevicePairingApprovalPrompter.swift | 6 +- .../DiagnosticsFileLog.swift | 2 +- .../DockIconManager.swift | 2 +- .../{Moltbot => OpenClaw}/ExecApprovals.swift | 6 +- .../ExecApprovalsGatewayPrompter.swift | 6 +- .../ExecApprovalsSocket.swift | 4 +- .../FileHandle+SafeRead.swift | 0 .../GatewayAutostartPolicy.swift | 0 .../GatewayConnection.swift | 22 +- .../GatewayConnectivityCoordinator.swift | 2 +- .../GatewayDiscoveryHelpers.swift | 2 +- .../GatewayDiscoveryMenu.swift | 4 +- .../GatewayDiscoveryPreferences.swift | 0 .../GatewayEndpointStore.swift | 44 +- .../GatewayEnvironment.swift | 30 +- .../GatewayLaunchAgentManager.swift | 9 +- .../GatewayProcessManager.swift | 6 +- .../GatewayRemoteConfig.swift | 0 .../GeneralSettings.swift | 30 +- .../{Moltbot => OpenClaw}/HealthStore.swift | 10 +- .../HeartbeatStore.swift | 0 .../{Moltbot => OpenClaw}/HoverHUD.swift | 0 .../{Moltbot => OpenClaw}/IconState.swift | 0 .../InstancesSettings.swift | 2 +- .../InstancesStore.swift | 8 +- .../LaunchAgentManager.swift | 23 +- .../{Moltbot => OpenClaw}/Launchctl.swift | 4 +- .../LaunchdManager.swift | 4 +- .../{Moltbot => OpenClaw}/LogLocator.swift | 19 +- .../Logging/OpenClawLogging.swift} | 18 +- .../{Moltbot => OpenClaw}/MenuBar.swift | 8 +- .../MenuContentView.swift | 12 +- .../MenuContextCardInjector.swift | 0 .../MenuHighlightedHostView.swift | 0 .../MenuHostedItem.swift | 0 .../MenuSessionsHeaderView.swift | 0 .../MenuSessionsInjector.swift | 0 .../MenuUsageHeaderView.swift | 0 .../MicLevelMonitor.swift | 2 +- .../ModelCatalogLoader.swift | 4 +- .../NSAttributedString+VoiceWake.swift | 0 .../NodeMode/MacNodeLocationService.swift | 6 +- .../NodeMode/MacNodeModeCoordinator.swift | 54 +- .../NodeMode/MacNodeRuntime.swift | 147 ++-- .../MacNodeRuntimeMainActorServices.swift | 6 +- .../NodeMode/MacNodeScreenCommands.swift | 0 .../NodePairingApprovalPrompter.swift | 10 +- .../NodeServiceManager.swift | 4 +- .../{Moltbot => OpenClaw}/NodesMenu.swift | 0 .../{Moltbot => OpenClaw}/NodesStore.swift | 2 +- .../NotificationManager.swift | 4 +- .../{Moltbot => OpenClaw}/NotifyOverlay.swift | 0 .../{Moltbot => OpenClaw}/Onboarding.swift | 18 +- .../OnboardingView+Actions.swift | 14 +- .../OnboardingView+Chat.swift | 2 +- .../OnboardingView+Layout.swift | 2 +- .../OnboardingView+Monitoring.swift | 12 +- .../OnboardingView+Pages.swift | 46 +- .../OnboardingView+Testing.swift | 10 +- .../OnboardingView+Wizard.swift | 2 +- .../OnboardingView+Workspace.swift | 4 +- .../OnboardingWidgets.swift | 2 +- .../OnboardingWizard.swift | 12 +- .../OpenClawConfigFile.swift} | 12 +- .../Sources/OpenClaw/OpenClawPaths.swift | 54 ++ .../PeekabooBridgeHostCoordinator.swift | 21 +- .../PermissionManager.swift | 6 +- .../PermissionsSettings.swift | 24 +- .../PointingHandCursor.swift | 0 .../{Moltbot => OpenClaw}/PortGuardian.swift | 12 +- .../PresenceReporter.swift | 2 +- .../Process+PipeRead.swift | 0 .../ProcessInfo+OpenClaw.swift} | 4 +- .../RemotePortTunnel.swift | 6 +- .../RemoteTunnelManager.swift | 4 +- .../LICENSE.apple-device-identifiers.txt | 0 .../Resources/DeviceModels/NOTICE.md | 0 .../DeviceModels/ios-device-identifiers.json | 0 .../DeviceModels/mac-device-identifiers.json | 0 .../Resources/Info.plist | 34 +- .../Resources/OpenClaw.icns} | Bin .../RuntimeLocator.swift | 6 +- .../ScreenRecordService.swift | 6 +- .../ScreenshotSize.swift | 0 .../SessionActions.swift | 3 +- .../{Moltbot => OpenClaw}/SessionData.swift | 4 +- .../SessionMenuLabelView.swift | 0 .../SessionMenuPreviewView.swift | 32 +- .../SessionsSettings.swift | 0 .../SettingsComponents.swift | 0 .../SettingsRootView.swift | 8 +- .../SettingsWindowOpener.swift | 0 .../{Moltbot => OpenClaw}/ShellExecutor.swift | 2 +- .../{Moltbot => OpenClaw}/SkillsModels.swift | 2 +- .../SkillsSettings.swift | 14 +- .../{Moltbot => OpenClaw}/SoundEffects.swift | 0 .../{Moltbot => OpenClaw}/StatusPill.swift | 0 .../String+NonEmpty.swift | 0 .../SystemRunSettingsView.swift | 0 .../TailscaleIntegrationSection.swift | 6 +- .../TailscaleService.swift | 2 +- .../TalkAudioPlayer.swift | 2 +- .../TalkModeController.swift | 2 +- .../TalkModeRuntime.swift | 12 +- .../{Moltbot => OpenClaw}/TalkModeTypes.swift | 0 .../{Moltbot => OpenClaw}/TalkOverlay.swift | 2 +- .../TalkOverlayView.swift | 0 .../TerminationSignalWatcher.swift | 2 +- .../{Moltbot => OpenClaw}/UsageCostData.swift | 0 .../{Moltbot => OpenClaw}/UsageData.swift | 0 .../UsageMenuLabelView.swift | 0 .../OpenClaw/UserDefaultsMigration.swift | 16 + .../{Moltbot => OpenClaw}/ViewMetrics.swift | 0 .../VisualEffectView.swift | 0 .../VoicePushToTalk.swift | 6 +- .../VoiceSessionCoordinator.swift | 2 +- .../VoiceWakeChime.swift | 2 +- .../VoiceWakeForwarder.swift | 2 +- .../VoiceWakeGlobalSettingsSync.swift | 4 +- .../VoiceWakeHelpers.swift | 0 .../VoiceWakeOverlay.swift | 4 +- .../VoiceWakeOverlayController+Session.swift | 0 .../VoiceWakeOverlayController+Testing.swift | 0 .../VoiceWakeOverlayController+Window.swift | 0 .../VoiceWakeOverlayTextViews.swift | 0 .../VoiceWakeOverlayView.swift | 0 .../VoiceWakeRuntime.swift | 2 +- .../VoiceWakeSettings.swift | 4 +- .../VoiceWakeTestCard.swift | 0 .../VoiceWakeTester.swift | 2 +- .../VoiceWakeTextUtils.swift | 0 .../WebChatManager.swift | 0 .../WebChatSwiftUI.swift | 42 +- .../WindowPlacement.swift | 0 .../WorkActivityStore.swift | 16 +- .../GatewayDiscoveryModel.swift | 21 +- .../WideAreaGatewayDiscovery.swift | 12 +- .../{MoltbotIPC => OpenClawIPC}/IPC.swift | 13 +- .../ConnectCommand.swift | 22 +- .../DiscoverCommand.swift | 6 +- .../EntryPoint.swift | 20 +- .../GatewayConfig.swift | 8 +- .../Sources/OpenClawMacCLI/TypeAliases.swift | 5 + .../WizardCommand.swift | 18 +- .../GatewayModels.swift | 0 .../ClawdbotConfigFileTests.swift | 79 -- .../AgentEventStoreTests.swift | 8 +- .../AgentWorkspaceTests.swift | 12 +- .../AnthropicAuthControlsSmokeTests.swift | 2 +- .../AnthropicAuthResolverTests.swift | 6 +- .../AnthropicOAuthCodeStateTests.swift | 2 +- .../AnyCodableEncodingTests.swift | 8 +- .../CLIInstallerTests.swift | 6 +- .../CameraCaptureServiceTests.swift | 2 +- .../CameraIPCTests.swift | 2 +- .../CanvasFileWatcherTests.swift | 4 +- .../CanvasIPCTests.swift | 2 +- .../CanvasWindowSmokeTests.swift | 8 +- .../ChannelsSettingsSmokeTests.swift | 8 +- .../CommandResolverTests.swift | 46 +- .../ConfigStoreTests.swift | 2 +- .../CoverageDumpTests.swift | 0 .../CritterIconRendererTests.swift | 2 +- .../CronJobEditorSmokeTests.swift | 2 +- .../CronModelsTests.swift | 2 +- .../DeviceModelCatalogTests.swift | 2 +- .../ExecAllowlistTests.swift | 2 +- .../ExecApprovalHelpersTests.swift | 2 +- .../ExecApprovalsGatewayPrompterTests.swift | 2 +- .../FileHandleLegacyAPIGuardTests.swift | 2 +- .../FileHandleSafeReadTests.swift | 2 +- .../GatewayAgentChannelTests.swift | 2 +- .../GatewayAutostartPolicyTests.swift | 2 +- .../GatewayChannelConfigureTests.swift | 4 +- .../GatewayChannelConnectTests.swift | 4 +- .../GatewayChannelRequestTests.swift | 4 +- .../GatewayChannelShutdownTests.swift | 4 +- .../GatewayConnectionControlTests.swift | 6 +- .../GatewayDiscoveryModelTests.swift | 12 +- .../GatewayEndpointStoreTests.swift | 10 +- .../GatewayEnvironmentTests.swift | 4 +- .../GatewayFrameDecodeTests.swift | 2 +- .../GatewayLaunchAgentManagerTests.swift | 14 +- .../GatewayProcessManagerTests.swift | 4 +- .../HealthDecodeTests.swift | 2 +- .../HealthStoreStateTests.swift | 2 +- .../HoverHUDControllerTests.swift | 2 +- .../InstancesSettingsSmokeTests.swift | 2 +- .../InstancesStoreTests.swift | 12 +- .../LogLocatorTests.swift | 8 +- .../LowCoverageHelperTests.swift | 6 +- .../LowCoverageViewSmokeTests.swift | 4 +- .../MacGatewayChatTransportMappingTests.swift | 20 +- .../MacNodeRuntimeTests.swift | 22 +- .../MasterDiscoveryMenuSmokeTests.swift | 4 +- .../MenuContentSmokeTests.swift | 2 +- .../MenuSessionsInjectorTests.swift | 2 +- .../ModelCatalogLoaderTests.swift | 2 +- .../NodeManagerPathsTests.swift | 2 +- .../NodePairingApprovalPrompterTests.swift | 2 +- .../NodePairingReconcilePolicyTests.swift | 2 +- .../OnboardingCoverageTests.swift | 2 +- .../OnboardingViewSmokeTests.swift | 4 +- .../OnboardingWizardStepViewTests.swift | 6 +- .../OpenClawConfigFileTests.swift | 79 ++ .../OpenClawOAuthStoreTests.swift} | 26 +- .../PermissionManagerLocationTests.swift | 2 +- .../PermissionManagerTests.swift | 4 +- .../Placeholder.swift | 0 .../RemotePortTunnelTests.swift | 2 +- .../RuntimeLocatorTests.swift | 2 +- .../ScreenshotSizeTests.swift | 2 +- .../SemverTests.swift | 2 +- .../SessionDataTests.swift | 2 +- .../SessionMenuPreviewTests.swift | 2 +- .../SettingsViewSmokeTests.swift | 4 +- .../SkillsSettingsSmokeTests.swift | 12 +- .../TailscaleIntegrationSectionTests.swift | 4 +- .../TalkAudioPlayerTests.swift | 2 +- .../TestIsolation.swift | 2 +- .../UtilitiesTests.swift | 10 +- .../VoicePushToTalkHotkeyTests.swift | 2 +- .../VoicePushToTalkTests.swift | 2 +- .../VoiceWakeForwarderTests.swift | 2 +- .../VoiceWakeGlobalSettingsSyncTests.swift | 10 +- .../VoiceWakeHelpersTests.swift | 2 +- .../VoiceWakeOverlayControllerTests.swift | 2 +- .../VoiceWakeOverlayTests.swift | 2 +- .../VoiceWakeOverlayViewSmokeTests.swift | 2 +- .../VoiceWakeRuntimeTests.swift | 20 +- .../VoiceWakeTesterTests.swift | 0 .../WebChatMainSessionKeyTests.swift | 6 +- .../WebChatManagerTests.swift | 2 +- .../WebChatSwiftUISmokeTests.swift | 16 +- .../WideAreaGatewayDiscoveryTests.swift | 13 +- .../WindowPlacementTests.swift | 2 +- .../WorkActivityStoreTests.swift | 6 +- .../Sources/MoltbotKit/BonjourTypes.swift | 27 - .../Sources/MoltbotKit/LocationSettings.swift | 7 - .../{MoltbotKit => OpenClawKit}/Package.swift | 30 +- .../OpenClawChatUI}/AssistantTextParser.swift | 0 .../OpenClawChatUI}/ChatComposer.swift | 34 +- .../ChatMarkdownPreprocessor.swift | 6 +- .../ChatMarkdownRenderer.swift | 2 +- .../OpenClawChatUI}/ChatMessageViews.swift | 52 +- .../Sources/OpenClawChatUI}/ChatModels.swift | 64 +- .../OpenClawChatUI}/ChatPayloadDecoding.swift | 2 +- .../OpenClawChatUI}/ChatSessions.swift | 10 +- .../Sources/OpenClawChatUI}/ChatSheets.swift | 2 +- .../Sources/OpenClawChatUI}/ChatTheme.swift | 10 +- .../OpenClawChatUI}/ChatTransport.swift | 24 +- .../Sources/OpenClawChatUI}/ChatView.swift | 32 +- .../OpenClawChatUI}/ChatViewModel.swift | 66 +- .../Sources/OpenClawKit}/AnyCodable.swift | 0 .../Sources/OpenClawKit}/AsyncTimeout.swift | 0 .../AudioStreamingProtocols.swift | 0 .../Sources/OpenClawKit}/BonjourEscapes.swift | 0 .../Sources/OpenClawKit/BonjourTypes.swift | 40 ++ .../Sources/OpenClawKit}/BridgeFrames.swift | 4 +- .../Sources/OpenClawKit}/CameraCommands.swift | 28 +- .../OpenClawKit}/CanvasA2UIAction.swift | 9 +- .../OpenClawKit}/CanvasA2UICommands.swift | 6 +- .../OpenClawKit}/CanvasA2UIJSONL.swift | 2 +- .../OpenClawKit}/CanvasCommandParams.swift | 20 +- .../Sources/OpenClawKit}/CanvasCommands.swift | 2 +- .../Sources/OpenClawKit}/Capabilities.swift | 2 +- .../Sources/OpenClawKit}/DeepLinks.swift | 6 +- .../OpenClawKit}/DeviceAuthStore.swift | 0 .../Sources/OpenClawKit}/DeviceIdentity.swift | 16 +- .../OpenClawKit}/ElevenLabsKitShim.swift | 0 .../Sources/OpenClawKit}/GatewayChannel.swift | 8 +- .../OpenClawKit}/GatewayEndpointID.swift | 0 .../Sources/OpenClawKit}/GatewayErrors.swift | 2 +- .../OpenClawKit}/GatewayNodeSession.swift | 6 +- .../OpenClawKit}/GatewayPayloadDecoding.swift | 6 +- .../Sources/OpenClawKit}/GatewayPush.swift | 2 +- .../OpenClawKit}/GatewayTLSPinning.swift | 14 +- .../OpenClawKit}/InstanceIdentity.swift | 19 +- .../Sources/OpenClawKit}/JPEGTranscoder.swift | 0 .../OpenClawKit}/LocationCommands.swift | 12 +- .../OpenClawKit/LocationSettings.swift | 7 + .../Sources/OpenClawKit}/NodeError.swift | 8 +- .../OpenClawKit/OpenClawKitResources.swift} | 6 +- .../Resources/CanvasScaffold/scaffold.html | 37 +- .../OpenClawKit}/Resources/tool-display.json | 0 .../Sources/OpenClawKit}/ScreenCommands.swift | 4 +- .../Sources/OpenClawKit}/StoragePaths.swift | 10 +- .../Sources/OpenClawKit}/SystemCommands.swift | 20 +- .../Sources/OpenClawKit}/TalkDirective.swift | 0 .../OpenClawKit}/TalkHistoryTimestamp.swift | 0 .../OpenClawKit}/TalkPromptBuilder.swift | 0 .../TalkSystemSpeechSynthesizer.swift | 0 .../Sources/OpenClawKit}/ToolDisplay.swift | 2 +- .../OpenClawProtocol}/AnyCodable.swift | 0 .../OpenClawProtocol}/GatewayModels.swift | 0 .../OpenClawProtocol}/WizardHelpers.swift | 0 .../AssistantTextParserTests.swift | 2 +- .../BonjourEscapesTests.swift | 4 +- .../CanvasA2UIActionTests.swift | 20 +- .../OpenClawKitTests}/CanvasA2UITests.swift | 14 +- .../CanvasSnapshotFormatTests.swift | 4 +- .../ChatMarkdownPreprocessorTests.swift | 2 +- .../OpenClawKitTests}/ChatThemeTests.swift | 6 +- .../ChatViewModelTests.swift | 94 +-- .../ElevenLabsTTSValidationTests.swift | 2 +- .../GatewayNodeSessionTests.swift | 4 +- .../JPEGTranscoderTests.swift | 2 +- .../TalkDirectiveTests.swift | 2 +- .../TalkHistoryTimestampTests.swift | 2 +- .../TalkPromptBuilderTests.swift | 2 +- .../ToolDisplayRegistryTests.swift | 4 +- .../Tools/CanvasA2UI/bootstrap.js | 52 +- .../Tools/CanvasA2UI/rolldown.config.mjs | 2 +- assets/chrome-extension/README.md | 10 +- assets/chrome-extension/background.js | 10 +- assets/chrome-extension/manifest.json | 6 +- assets/chrome-extension/options.html | 10 +- assets/chrome-extension/options.js | 2 +- docker-compose.yml | 26 +- docker-setup.sh | 95 +-- docs.acp.md | 44 +- docs/CNAME | 2 +- docs/_config.yml | 6 +- docs/_layouts/default.html | 18 +- docs/assets/openclaw-logo-text.png | Bin 0 -> 92131 bytes docs/assets/theme.js | 2 +- docs/automation/auth-monitoring.md | 14 +- docs/automation/cron-jobs.md | 38 +- docs/automation/cron-vs-heartbeat.md | 14 +- docs/automation/gmail-pubsub.md | 50 +- docs/automation/poll.md | 14 +- docs/automation/webhook.md | 10 +- docs/bedrock.md | 20 +- docs/brave-search.md | 2 +- docs/broadcast-groups.md | 12 +- docs/channels/bluebubbles.md | 24 +- docs/channels/discord.md | 30 +- docs/channels/googlechat.md | 32 +- docs/channels/imessage.md | 26 +- docs/channels/index.md | 8 +- docs/channels/line.md | 12 +- docs/channels/location.md | 2 +- docs/channels/matrix.md | 28 +- docs/channels/mattermost.md | 16 +- docs/channels/msteams.md | 52 +- docs/channels/nextcloud-talk.md | 14 +- docs/channels/nostr.md | 18 +- docs/channels/signal.md | 18 +- docs/channels/slack.md | 32 +- docs/channels/telegram.md | 46 +- docs/channels/tlon.md | 10 +- docs/channels/troubleshooting.md | 4 +- docs/channels/twitch.md | 28 +- docs/channels/whatsapp.md | 50 +- docs/channels/zalo.md | 16 +- docs/channels/zalouser.md | 24 +- docs/cli/acp.md | 48 +- docs/cli/agent.md | 12 +- docs/cli/agents.md | 24 +- docs/cli/approvals.md | 28 +- docs/cli/browser.md | 48 +- docs/cli/channels.md | 42 +- docs/cli/config.md | 30 +- docs/cli/configure.md | 12 +- docs/cli/cron.md | 10 +- docs/cli/dashboard.md | 8 +- docs/cli/devices.md | 26 +- docs/cli/directory.md | 24 +- docs/cli/dns.md | 11 +- docs/cli/docs.md | 10 +- docs/cli/doctor.md | 22 +- docs/cli/gateway.md | 52 +- docs/cli/health.md | 10 +- docs/cli/hooks.md | 70 +- docs/cli/index.md | 84 +-- docs/cli/logs.md | 12 +- docs/cli/memory.md | 22 +- docs/cli/message.md | 22 +- docs/cli/models.md | 30 +- docs/cli/node.md | 28 +- docs/cli/nodes.md | 28 +- docs/cli/onboard.md | 14 +- docs/cli/pairing.md | 8 +- docs/cli/plugins.md | 32 +- docs/cli/reset.md | 10 +- docs/cli/sandbox.md | 56 +- docs/cli/security.md | 10 +- docs/cli/sessions.md | 10 +- docs/cli/setup.md | 12 +- docs/cli/skills.md | 12 +- docs/cli/status.md | 14 +- docs/cli/system.md | 12 +- docs/cli/tui.md | 10 +- docs/cli/uninstall.md | 10 +- docs/cli/update.md | 40 +- docs/cli/voicecall.md | 18 +- docs/cli/webhooks.md | 10 +- docs/concepts/agent-loop.md | 10 +- docs/concepts/agent-workspace.md | 54 +- docs/concepts/agent.md | 24 +- docs/concepts/architecture.md | 4 +- docs/concepts/channel-routing.md | 10 +- docs/concepts/compaction.md | 10 +- docs/concepts/context.md | 12 +- docs/concepts/group-messages.md | 14 +- docs/concepts/groups.md | 10 +- docs/concepts/markdown-formatting.md | 6 +- docs/concepts/memory.md | 30 +- docs/concepts/messages.md | 8 +- docs/concepts/model-failover.md | 28 +- docs/concepts/model-providers.md | 42 +- docs/concepts/models.md | 48 +- docs/concepts/multi-agent.md | 62 +- docs/concepts/oauth.md | 44 +- docs/concepts/presence.md | 4 +- docs/concepts/retry.md | 2 +- docs/concepts/session-pruning.md | 2 +- docs/concepts/session-tool.md | 8 +- docs/concepts/session.md | 28 +- docs/concepts/streaming.md | 6 +- docs/concepts/system-prompt.md | 22 +- docs/concepts/timezone.md | 4 +- docs/concepts/typebox.md | 6 +- docs/concepts/typing-indicators.md | 4 +- docs/concepts/usage-tracking.md | 6 +- docs/date-time.md | 4 +- docs/debug/node-issue.md | 12 +- docs/debugging.md | 36 +- docs/diagnostics/flags.md | 14 +- docs/docs.json | 18 +- docs/environment.md | 14 +- docs/experiments/plans/cron-add-hardening.md | 2 +- .../plans/openresponses-gateway.md | 4 +- docs/experiments/research/memory.md | 24 +- docs/gateway/authentication.md | 44 +- docs/gateway/background-process.md | 4 +- docs/gateway/bonjour.md | 50 +- docs/gateway/bridge-protocol.md | 4 +- docs/gateway/cli-backends.md | 24 +- docs/gateway/configuration-examples.md | 48 +- docs/gateway/configuration.md | 295 ++++---- docs/gateway/discovery.md | 20 +- docs/gateway/doctor.md | 54 +- docs/gateway/gateway-lock.md | 2 +- docs/gateway/health.md | 22 +- docs/gateway/heartbeat.md | 10 +- docs/gateway/index.md | 126 ++-- docs/gateway/local-models.md | 4 +- docs/gateway/logging.md | 16 +- docs/gateway/multiple-gateways.md | 48 +- docs/gateway/openai-http-api.md | 24 +- docs/gateway/openresponses-http-api.md | 24 +- docs/gateway/pairing.md | 18 +- docs/gateway/protocol.md | 8 +- docs/gateway/remote-gateway-readme.md | 20 +- docs/gateway/remote.md | 8 +- .../sandbox-vs-tool-policy-vs-elevated.md | 14 +- docs/gateway/sandboxing.md | 12 +- docs/gateway/security/formal-verification.md | 14 +- docs/gateway/security/index.md | 112 ++- docs/gateway/tailscale.md | 20 +- docs/gateway/tools-invoke-http-api.md | 10 +- docs/gateway/troubleshooting.md | 224 +++--- docs/help/faq.md | 676 +++++++++--------- docs/help/troubleshooting.md | 32 +- docs/hooks.md | 124 ++-- docs/hooks/soul-evil.md | 4 +- docs/index.md | 72 +- docs/install/ansible.md | 70 +- docs/install/development-channels.md | 20 +- docs/install/docker.md | 90 +-- docs/install/index.md | 66 +- docs/install/installer.md | 48 +- docs/install/migrating.md | 72 +- docs/install/nix.md | 36 +- docs/install/node.md | 8 +- docs/install/uninstall.md | 58 +- docs/install/updating.md | 102 +-- docs/logging.md | 118 +-- docs/multi-agent-sandbox-tools.md | 30 +- docs/network.md | 2 +- docs/nodes/audio.md | 4 +- docs/nodes/camera.md | 36 +- docs/nodes/images.md | 8 +- docs/nodes/index.md | 114 +-- docs/nodes/location-command.md | 4 +- docs/nodes/media-understanding.md | 10 +- docs/nodes/talk.md | 2 +- docs/nodes/voicewake.md | 6 +- docs/northflank.mdx | 18 +- docs/perplexity.md | 4 +- docs/platforms/android.md | 28 +- docs/platforms/digitalocean.md | 52 +- docs/platforms/exe-dev.md | 32 +- docs/platforms/fly.md | 64 +- docs/platforms/gcp.md | 116 +-- docs/platforms/hetzner.md | 90 +-- docs/platforms/index.md | 16 +- docs/platforms/ios.md | 26 +- docs/platforms/linux.md | 22 +- docs/platforms/mac/bundled-gateway.md | 28 +- docs/platforms/mac/canvas.md | 28 +- docs/platforms/mac/child-process.md | 10 +- docs/platforms/mac/dev-setup.md | 20 +- docs/platforms/mac/health.md | 4 +- docs/platforms/mac/icon.md | 2 +- docs/platforms/mac/logging.md | 8 +- docs/platforms/mac/menu-bar.md | 2 +- docs/platforms/mac/peekaboo.md | 18 +- docs/platforms/mac/permissions.md | 2 +- docs/platforms/mac/release.md | 36 +- docs/platforms/mac/remote.md | 28 +- docs/platforms/mac/signing.md | 14 +- docs/platforms/mac/skills.md | 8 +- docs/platforms/mac/webchat.md | 2 +- docs/platforms/mac/xpc.md | 8 +- docs/platforms/macos-vm.md | 54 +- docs/platforms/macos.md | 32 +- docs/platforms/oracle.md | 70 +- docs/platforms/raspberry-pi.md | 44 +- docs/platforms/windows.md | 22 +- docs/plugin.md | 130 ++-- docs/plugins/agent-tools.md | 2 +- docs/plugins/manifest.md | 8 +- docs/plugins/voice-call.md | 24 +- docs/plugins/zalouser.md | 18 +- docs/prose.md | 18 +- docs/providers/anthropic.md | 32 +- docs/providers/claude-max-api-proxy.md | 8 +- docs/providers/deepgram.md | 4 +- docs/providers/github-copilot.md | 22 +- docs/providers/glm.md | 8 +- docs/providers/index.md | 6 +- docs/providers/minimax.md | 18 +- docs/providers/models.md | 6 +- docs/providers/moonshot.md | 4 +- docs/providers/ollama.md | 22 +- docs/providers/openai.md | 12 +- docs/providers/opencode.md | 6 +- docs/providers/openrouter.md | 6 +- docs/providers/qwen.md | 12 +- docs/providers/synthetic.md | 8 +- docs/providers/venice.md | 42 +- docs/providers/vercel-ai-gateway.md | 8 +- docs/providers/zai.md | 10 +- docs/railway.mdx | 16 +- docs/refactor/exec-host.md | 10 +- docs/refactor/plugin-sdk.md | 24 +- docs/refactor/strict-config.md | 22 +- docs/reference/AGENTS.default.md | 34 +- docs/reference/RELEASING.md | 56 +- docs/reference/api-usage-costs.md | 12 +- docs/reference/device-models.md | 14 +- docs/reference/rpc.md | 6 +- .../session-management-compaction.md | 38 +- docs/reference/templates/AGENTS.dev.md | 2 +- docs/reference/templates/BOOT.md | 2 +- docs/reference/templates/IDENTITY.md | 2 +- docs/reference/templates/TOOLS.dev.md | 2 +- docs/reference/templates/USER.dev.md | 4 +- docs/reference/test.md | 4 +- docs/reference/transcript-hygiene.md | 2 +- docs/render.mdx | 26 +- docs/scripts.md | 2 +- docs/security/formal-verification.md | 14 +- docs/start/getting-started.md | 58 +- docs/start/hubs.md | 4 +- docs/start/lore.md | 28 +- docs/start/onboarding.md | 14 +- docs/start/{clawd.md => openclaw.md} | 70 +- docs/start/pairing.md | 20 +- docs/start/setup.md | 44 +- docs/start/showcase.md | 64 +- docs/start/wizard.md | 60 +- docs/testing.md | 112 +-- docs/token-use.md | 14 +- docs/tools/agent-send.md | 20 +- docs/tools/browser-linux-troubleshooting.md | 32 +- docs/tools/browser-login.md | 12 +- docs/tools/browser.md | 252 +++---- docs/tools/chrome-extension.md | 34 +- docs/tools/clawdhub.md | 14 +- docs/tools/creating-skills.md | 12 +- docs/tools/exec-approvals.md | 10 +- docs/tools/exec.md | 8 +- docs/tools/firecrawl.md | 4 +- docs/tools/index.md | 26 +- docs/tools/llm-task.md | 4 +- docs/tools/lobster.md | 26 +- docs/tools/skills-config.md | 4 +- docs/tools/skills.md | 62 +- docs/tools/slash-commands.md | 16 +- docs/tools/web.md | 16 +- docs/tts.md | 22 +- docs/tui.md | 14 +- docs/vps.md | 2 +- docs/web/control-ui.md | 16 +- docs/web/dashboard.md | 12 +- docs/web/index.md | 10 +- ...atsapp-clawd.jpg => whatsapp-openclaw.jpg} | Bin extensions/bluebubbles/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/bluebubbles/package.json | 10 +- extensions/bluebubbles/src/accounts.ts | 18 +- extensions/bluebubbles/src/actions.test.ts | 44 +- extensions/bluebubbles/src/actions.ts | 12 +- extensions/bluebubbles/src/attachments.ts | 4 +- extensions/bluebubbles/src/channel.ts | 34 +- extensions/bluebubbles/src/chat.ts | 4 +- extensions/bluebubbles/src/config-schema.ts | 2 +- extensions/bluebubbles/src/media-send.ts | 4 +- extensions/bluebubbles/src/monitor.test.ts | 96 +-- extensions/bluebubbles/src/monitor.ts | 12 +- extensions/bluebubbles/src/onboarding.ts | 18 +- extensions/bluebubbles/src/reactions.ts | 4 +- extensions/bluebubbles/src/runtime.ts | 2 +- extensions/bluebubbles/src/send.ts | 4 +- extensions/copilot-proxy/README.md | 6 +- extensions/copilot-proxy/index.ts | 2 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/copilot-proxy/package.json | 8 +- extensions/diagnostics-otel/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/diagnostics-otel/package.json | 8 +- .../diagnostics-otel/src/service.test.ts | 30 +- extensions/diagnostics-otel/src/service.ts | 170 ++--- extensions/discord/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/discord/package.json | 8 +- extensions/discord/src/channel.ts | 2 +- extensions/discord/src/runtime.ts | 2 +- extensions/google-antigravity-auth/README.md | 6 +- extensions/google-antigravity-auth/index.ts | 4 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 .../google-antigravity-auth/package.json | 8 +- extensions/google-gemini-cli-auth/README.md | 10 +- extensions/google-gemini-cli-auth/index.ts | 6 +- extensions/google-gemini-cli-auth/oauth.ts | 8 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 .../google-gemini-cli-auth/package.json | 8 +- extensions/googlechat/index.ts | 8 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/googlechat/package.json | 14 +- extensions/googlechat/src/accounts.ts | 18 +- extensions/googlechat/src/actions.ts | 16 +- extensions/googlechat/src/api.ts | 2 +- extensions/googlechat/src/channel.ts | 46 +- extensions/googlechat/src/monitor.ts | 18 +- extensions/googlechat/src/onboarding.ts | 22 +- extensions/googlechat/src/runtime.ts | 2 +- extensions/googlechat/src/types.config.ts | 2 +- extensions/imessage/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/imessage/package.json | 8 +- extensions/imessage/src/channel.ts | 2 +- extensions/imessage/src/runtime.ts | 2 +- extensions/line/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/line/package.json | 12 +- extensions/line/src/card-command.ts | 6 +- extensions/line/src/channel.logout.test.ts | 8 +- .../line/src/channel.sendPayload.test.ts | 16 +- extensions/line/src/channel.ts | 10 +- extensions/line/src/runtime.ts | 2 +- extensions/llm-task/README.md | 8 +- extensions/llm-task/index.ts | 4 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/llm-task/package.json | 8 +- extensions/llm-task/src/llm-task-tool.ts | 12 +- extensions/lobster/README.md | 14 +- extensions/lobster/index.ts | 4 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/lobster/package.json | 6 +- extensions/lobster/src/lobster-tool.test.ts | 14 +- extensions/lobster/src/lobster-tool.ts | 4 +- extensions/matrix/CHANGELOG.md | 20 +- extensions/matrix/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/matrix/package.json | 12 +- extensions/matrix/src/actions.ts | 2 +- .../matrix/src/channel.directory.test.ts | 2 +- extensions/matrix/src/channel.ts | 2 +- extensions/matrix/src/config-schema.ts | 2 +- extensions/matrix/src/directory-live.ts | 2 +- extensions/matrix/src/group-mentions.ts | 2 +- extensions/matrix/src/matrix/accounts.ts | 2 +- .../matrix/src/matrix/actions/client.ts | 2 +- extensions/matrix/src/matrix/client/config.ts | 2 +- extensions/matrix/src/matrix/deps.ts | 2 +- .../matrix/src/matrix/monitor/allowlist.ts | 2 +- .../matrix/src/matrix/monitor/auto-join.ts | 2 +- .../matrix/src/matrix/monitor/events.ts | 2 +- .../matrix/src/matrix/monitor/handler.ts | 10 +- extensions/matrix/src/matrix/monitor/index.ts | 2 +- .../matrix/src/matrix/monitor/location.ts | 2 +- .../matrix/src/matrix/monitor/media.test.ts | 2 +- .../matrix/src/matrix/monitor/replies.ts | 2 +- extensions/matrix/src/matrix/monitor/rooms.ts | 2 +- extensions/matrix/src/matrix/poll-types.ts | 2 +- extensions/matrix/src/matrix/send.test.ts | 2 +- extensions/matrix/src/matrix/send.ts | 2 +- extensions/matrix/src/matrix/send/client.ts | 2 +- extensions/matrix/src/onboarding.ts | 4 +- extensions/matrix/src/outbound.ts | 2 +- extensions/matrix/src/resolve-targets.ts | 2 +- extensions/matrix/src/runtime.ts | 2 +- extensions/matrix/src/tool-actions.ts | 2 +- extensions/mattermost/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/mattermost/package.json | 10 +- extensions/mattermost/src/channel.ts | 2 +- extensions/mattermost/src/config-schema.ts | 2 +- extensions/mattermost/src/group-mentions.ts | 2 +- .../mattermost/src/mattermost/accounts.ts | 18 +- .../src/mattermost/monitor-helpers.ts | 10 +- .../mattermost/src/mattermost/monitor.ts | 8 +- .../mattermost/src/onboarding-helpers.ts | 8 +- extensions/mattermost/src/onboarding.ts | 8 +- extensions/mattermost/src/runtime.ts | 2 +- extensions/mattermost/src/types.ts | 2 +- extensions/memory-core/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/memory-core/package.json | 12 +- extensions/memory-lancedb/config.ts | 28 +- extensions/memory-lancedb/index.test.ts | 6 +- extensions/memory-lancedb/index.ts | 8 +- ...wdbot.plugin.json => openclaw.plugin.json} | 2 +- extensions/memory-lancedb/package.json | 8 +- extensions/msteams/CHANGELOG.md | 16 +- extensions/msteams/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/msteams/package.json | 12 +- extensions/msteams/src/attachments.test.ts | 2 +- .../msteams/src/channel.directory.test.ts | 4 +- extensions/msteams/src/channel.ts | 6 +- .../msteams/src/conversation-store-fs.test.ts | 11 +- extensions/msteams/src/directory-live.ts | 2 +- extensions/msteams/src/graph-upload.ts | 8 +- extensions/msteams/src/media-helpers.ts | 2 +- extensions/msteams/src/messenger.test.ts | 2 +- extensions/msteams/src/messenger.ts | 2 +- extensions/msteams/src/monitor-handler.ts | 4 +- .../src/monitor-handler/message-handler.ts | 2 +- extensions/msteams/src/monitor.ts | 6 +- extensions/msteams/src/onboarding.ts | 22 +- extensions/msteams/src/outbound.ts | 2 +- extensions/msteams/src/policy.test.ts | 2 +- extensions/msteams/src/policy.ts | 4 +- extensions/msteams/src/polls-store.test.ts | 2 +- extensions/msteams/src/polls.test.ts | 11 +- extensions/msteams/src/polls.ts | 17 +- extensions/msteams/src/probe.test.ts | 2 +- extensions/msteams/src/probe.ts | 2 +- extensions/msteams/src/reply-dispatcher.ts | 6 +- extensions/msteams/src/runtime.ts | 2 +- extensions/msteams/src/send-context.ts | 4 +- extensions/msteams/src/send.ts | 10 +- extensions/msteams/src/token.ts | 2 +- extensions/nextcloud-talk/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/nextcloud-talk/package.json | 10 +- extensions/nextcloud-talk/src/accounts.ts | 4 +- extensions/nextcloud-talk/src/channel.ts | 16 +- .../nextcloud-talk/src/config-schema.ts | 2 +- extensions/nextcloud-talk/src/inbound.ts | 16 +- extensions/nextcloud-talk/src/monitor.ts | 2 +- extensions/nextcloud-talk/src/onboarding.ts | 4 +- extensions/nextcloud-talk/src/policy.ts | 4 +- extensions/nextcloud-talk/src/room-info.ts | 2 +- extensions/nextcloud-talk/src/runtime.ts | 2 +- extensions/nextcloud-talk/src/types.ts | 2 +- extensions/nostr/CHANGELOG.md | 10 +- extensions/nostr/README.md | 10 +- extensions/nostr/index.ts | 12 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/nostr/package.json | 12 +- extensions/nostr/src/channel.ts | 4 +- extensions/nostr/src/config-schema.ts | 2 +- .../nostr/src/nostr-state-store.test.ts | 17 +- extensions/nostr/src/runtime.ts | 2 +- extensions/nostr/src/types.ts | 8 +- extensions/open-prose/index.ts | 4 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/open-prose/package.json | 6 +- extensions/open-prose/skills/prose/SKILL.md | 10 +- extensions/open-prose/skills/prose/prose.md | 8 +- extensions/qwen-portal-auth/README.md | 6 +- extensions/qwen-portal-auth/index.ts | 2 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/signal/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/signal/package.json | 8 +- extensions/signal/src/channel.ts | 2 +- extensions/signal/src/runtime.ts | 2 +- extensions/slack/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/slack/package.json | 8 +- extensions/slack/src/channel.ts | 2 +- extensions/slack/src/runtime.ts | 2 +- extensions/telegram/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/telegram/package.json | 8 +- extensions/telegram/src/channel.ts | 6 +- extensions/telegram/src/runtime.ts | 2 +- extensions/tlon/README.md | 6 +- extensions/tlon/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/tlon/package.json | 10 +- extensions/tlon/src/channel.ts | 30 +- extensions/tlon/src/config-schema.ts | 2 +- extensions/tlon/src/monitor/discovery.ts | 2 +- extensions/tlon/src/monitor/history.ts | 2 +- extensions/tlon/src/monitor/index.ts | 6 +- extensions/tlon/src/onboarding.ts | 8 +- extensions/tlon/src/runtime.ts | 2 +- extensions/tlon/src/types.ts | 6 +- extensions/twitch/CHANGELOG.md | 4 +- extensions/twitch/README.md | 16 +- extensions/twitch/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/twitch/package.json | 10 +- extensions/twitch/src/actions.ts | 2 +- extensions/twitch/src/config-schema.ts | 2 +- extensions/twitch/src/config.ts | 6 +- extensions/twitch/src/monitor.ts | 6 +- extensions/twitch/src/onboarding.test.ts | 2 +- extensions/twitch/src/onboarding.ts | 26 +- extensions/twitch/src/outbound.test.ts | 4 +- extensions/twitch/src/outbound.ts | 4 +- extensions/twitch/src/plugin.test.ts | 4 +- extensions/twitch/src/plugin.ts | 18 +- extensions/twitch/src/runtime.ts | 2 +- extensions/twitch/src/send.test.ts | 4 +- extensions/twitch/src/send.ts | 10 +- extensions/twitch/src/token.test.ts | 24 +- extensions/twitch/src/token.ts | 14 +- extensions/twitch/src/twitch-client.ts | 8 +- extensions/twitch/src/types.ts | 6 +- extensions/twitch/src/utils/markdown.ts | 2 +- extensions/voice-call/CHANGELOG.md | 24 +- extensions/voice-call/README.md | 32 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/voice-call/package.json | 8 +- extensions/voice-call/src/cli.ts | 20 +- extensions/voice-call/src/core-bridge.ts | 10 +- extensions/voice-call/src/manager.test.ts | 4 +- extensions/voice-call/src/manager.ts | 22 +- .../voice-call/src/response-generator.ts | 2 +- extensions/whatsapp/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/whatsapp/package.json | 8 +- extensions/whatsapp/src/channel.ts | 2 +- extensions/whatsapp/src/runtime.ts | 2 +- extensions/zalo/CHANGELOG.md | 20 +- extensions/zalo/README.md | 8 +- extensions/zalo/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/zalo/package.json | 12 +- extensions/zalo/src/accounts.ts | 18 +- extensions/zalo/src/actions.ts | 12 +- extensions/zalo/src/channel.directory.test.ts | 4 +- extensions/zalo/src/channel.ts | 40 +- extensions/zalo/src/config-schema.ts | 2 +- extensions/zalo/src/monitor.ts | 18 +- extensions/zalo/src/monitor.webhook.test.ts | 4 +- extensions/zalo/src/onboarding.ts | 54 +- extensions/zalo/src/runtime.ts | 2 +- extensions/zalo/src/send.ts | 4 +- extensions/zalo/src/status-issues.ts | 2 +- extensions/zalo/src/token.ts | 2 +- extensions/zalouser/CHANGELOG.md | 10 +- extensions/zalouser/README.md | 36 +- extensions/zalouser/index.ts | 6 +- ...wdbot.plugin.json => openclaw.plugin.json} | 0 extensions/zalouser/package.json | 12 +- extensions/zalouser/src/accounts.ts | 20 +- extensions/zalouser/src/channel.ts | 54 +- extensions/zalouser/src/config-schema.ts | 2 +- extensions/zalouser/src/monitor.ts | 10 +- extensions/zalouser/src/onboarding.ts | 64 +- extensions/zalouser/src/runtime.ts | 2 +- extensions/zalouser/src/status-issues.ts | 4 +- fly.private.toml | 10 +- fly.toml | 10 +- moltbot.mjs => openclaw.mjs | 0 package.json | 42 +- packages/clawdbot/index.js | 1 + packages/clawdbot/package.json | 15 +- packages/clawdbot/scripts/postinstall.js | 1 + packages/moltbot/index.js | 1 + packages/moltbot/package.json | 19 + packages/moltbot/scripts/postinstall.js | 1 + pnpm-lock.yaml | 113 +-- render.yaml | 12 +- scripts/auth-monitor.sh | 20 +- scripts/build-and-run-mac.sh | 6 +- scripts/build_icon.sh | 6 +- scripts/bundle-a2ui.sh | 2 +- scripts/canvas-a2ui-copy.ts | 8 +- scripts/changelog-to-html.sh | 10 +- scripts/claude-auth-status.sh | 52 +- scripts/clawlog.sh | 8 +- scripts/codesign-mac-app.sh | 12 +- scripts/create-dmg.sh | 14 +- scripts/debug-claude-usage.ts | 6 +- scripts/docker/cleanup-smoke/Dockerfile | 6 +- scripts/docker/cleanup-smoke/run.sh | 30 +- scripts/docker/install-sh-e2e/Dockerfile | 6 +- scripts/docker/install-sh-e2e/run.sh | 64 +- scripts/docker/install-sh-nonroot/Dockerfile | 6 +- scripts/docker/install-sh-nonroot/run.sh | 29 +- scripts/docker/install-sh-smoke/Dockerfile | 6 +- scripts/docker/install-sh-smoke/run.sh | 34 +- scripts/e2e/doctor-install-switch-docker.sh | 24 +- scripts/e2e/gateway-network-docker.sh | 16 +- scripts/e2e/onboard-docker.sh | 38 +- scripts/e2e/plugins-docker.sh | 26 +- scripts/e2e/qr-import-docker.sh | 2 +- scripts/make_appcast.sh | 8 +- scripts/mobile-reauth.sh | 10 +- scripts/notarize-mac-artifact.sh | 2 +- scripts/package-mac-app.sh | 46 +- scripts/package-mac-dist.sh | 14 +- scripts/postinstall.js | 1 + scripts/protocol-gen-swift.ts | 6 +- scripts/protocol-gen.ts | 4 +- scripts/release-check.ts | 2 +- scripts/restart-mac.sh | 66 +- scripts/run-node.mjs | 10 +- scripts/sandbox-browser-entrypoint.sh | 12 +- scripts/sandbox-browser-setup.sh | 2 +- scripts/sandbox-common-setup.sh | 6 +- scripts/sandbox-setup.sh | 2 +- scripts/setup-auth-system.sh | 18 +- scripts/sync-plugin-versions.ts | 2 +- ....service => openclaw-auth-monitor.service} | 6 +- ...itor.timer => openclaw-auth-monitor.timer} | 2 +- scripts/termux-auth-widget.sh | 20 +- scripts/termux-quick-auth.sh | 6 +- scripts/termux-sync-widget.sh | 15 +- scripts/test-cleanup-docker.sh | 2 +- scripts/test-force.ts | 11 +- scripts/test-install-sh-docker.sh | 38 +- scripts/test-install-sh-e2e-docker.sh | 16 +- scripts/test-live-gateway-models-docker.sh | 20 +- scripts/test-live-models-docker.sh | 22 +- scripts/test-parallel.mjs | 4 +- scripts/update-clawtributors.ts | 2 +- scripts/watch-node.mjs | 4 +- scripts/zai-fallback-repro.ts | 14 +- skills/1password/SKILL.md | 6 +- skills/apple-notes/SKILL.md | 4 +- skills/apple-reminders/SKILL.md | 2 +- skills/bear-notes/SKILL.md | 2 +- skills/bird/SKILL.md | 2 +- skills/blogwatcher/SKILL.md | 2 +- skills/blucli/SKILL.md | 2 +- skills/bluebubbles/SKILL.md | 2 +- skills/camsnap/SKILL.md | 2 +- skills/canvas/SKILL.md | 12 +- skills/clawdhub/SKILL.md | 4 +- skills/coding-agent/SKILL.md | 12 +- skills/discord/SKILL.md | 10 +- skills/eightctl/SKILL.md | 2 +- skills/food-order/SKILL.md | 2 +- skills/gemini/SKILL.md | 2 +- skills/gifgrep/SKILL.md | 2 +- skills/github/SKILL.md | 2 +- skills/gog/SKILL.md | 2 +- skills/goplaces/SKILL.md | 2 +- skills/himalaya/SKILL.md | 2 +- skills/imsg/SKILL.md | 2 +- skills/local-places/SKILL.md | 2 +- skills/mcporter/SKILL.md | 2 +- skills/model-usage/SKILL.md | 2 +- skills/nano-banana-pro/SKILL.md | 6 +- .../nano-banana-pro/scripts/generate_image.py | 2 +- skills/nano-pdf/SKILL.md | 2 +- skills/notion/SKILL.md | 2 +- skills/obsidian/SKILL.md | 2 +- skills/openai-image-gen/SKILL.md | 2 +- skills/openai-whisper-api/SKILL.md | 4 +- skills/openai-whisper/SKILL.md | 2 +- skills/openhue/SKILL.md | 2 +- skills/oracle/SKILL.md | 2 +- skills/ordercli/SKILL.md | 2 +- skills/peekaboo/SKILL.md | 2 +- skills/sag/SKILL.md | 2 +- skills/session-logs/SKILL.md | 2 +- skills/sherpa-onnx-tts/SKILL.md | 4 +- skills/slack/SKILL.md | 8 +- skills/songsee/SKILL.md | 2 +- skills/sonoscli/SKILL.md | 2 +- skills/spotify-player/SKILL.md | 2 +- skills/summarize/SKILL.md | 2 +- skills/things-mac/SKILL.md | 6 +- skills/tmux/SKILL.md | 14 +- skills/trello/SKILL.md | 4 +- skills/video-frames/SKILL.md | 2 +- skills/voice-call/SKILL.md | 8 +- skills/wacli/SKILL.md | 4 +- skills/weather/SKILL.md | 2 +- src/acp/client.ts | 10 +- src/acp/server.ts | 6 +- src/acp/types.ts | 4 +- src/agents/agent-paths.test.ts | 32 +- src/agents/agent-paths.ts | 10 +- src/agents/agent-scope.test.ts | 42 +- src/agents/agent-scope.ts | 28 +- src/agents/anthropic-payload-log.ts | 4 +- src/agents/anthropic.setup-token.live.test.ts | 24 +- src/agents/apply-patch.test.ts | 2 +- src/agents/auth-health.ts | 6 +- src/agents/auth-profiles.chutes.test.ts | 20 +- ...th-profiles.ensureauthprofilestore.test.ts | 12 +- ...th-profiles.markauthprofilefailure.test.ts | 6 +- src/agents/auth-profiles/display.ts | 4 +- src/agents/auth-profiles/doctor.ts | 6 +- .../oauth.fallback-to-main-agent.test.ts | 18 +- src/agents/auth-profiles/oauth.ts | 6 +- src/agents/auth-profiles/order.ts | 4 +- src/agents/auth-profiles/paths.ts | 6 +- src/agents/auth-profiles/repair.ts | 8 +- .../auth-profiles/session-override.test.ts | 14 +- src/agents/auth-profiles/session-override.ts | 4 +- src/agents/auth-profiles/types.ts | 6 +- src/agents/auth-profiles/usage.ts | 6 +- .../bash-tools.exec.approval-id.test.ts | 4 +- src/agents/bash-tools.exec.ts | 2 +- src/agents/bash-tools.shared.ts | 4 +- src/agents/bash-tools.test.ts | 14 +- src/agents/bootstrap-files.test.ts | 4 +- src/agents/bootstrap-files.ts | 6 +- src/agents/bootstrap-hooks.ts | 4 +- src/agents/cache-trace.test.ts | 10 +- src/agents/cache-trace.ts | 14 +- src/agents/channel-tools.test.ts | 4 +- src/agents/channel-tools.ts | 18 +- src/agents/claude-cli-runner.test.ts | 4 +- src/agents/cli-backends.ts | 6 +- src/agents/cli-credentials.test.ts | 6 +- src/agents/cli-runner.ts | 12 +- src/agents/cli-runner/helpers.ts | 12 +- src/agents/context-window-guard.test.ts | 6 +- src/agents/context-window-guard.ts | 4 +- src/agents/context.ts | 8 +- src/agents/docs-path.ts | 6 +- src/agents/identity-avatar.test.ts | 16 +- src/agents/identity-avatar.ts | 6 +- src/agents/identity-file.test.ts | 4 +- src/agents/identity.test.ts | 6 +- src/agents/identity.ts | 23 +- src/agents/live-auth-keys.ts | 4 +- src/agents/memory-search.ts | 4 +- src/agents/minimax-vlm.ts | 2 +- src/agents/model-auth.test.ts | 44 +- src/agents/model-auth.ts | 16 +- src/agents/model-catalog.test.ts | 10 +- src/agents/model-catalog.ts | 12 +- src/agents/model-fallback.test.ts | 14 +- src/agents/model-fallback.ts | 12 +- src/agents/model-selection.test.ts | 14 +- src/agents/model-selection.ts | 22 +- ...s-github-copilot-provider-token-is.test.ts | 14 +- ...fault-baseurl-token-exchange-fails.test.ts | 18 +- ...ssing-provider-apikey-from-env-var.test.ts | 24 +- ...ini-3-ids-preview-google-providers.test.ts | 16 +- .../models-config.providers.ollama.test.ts | 2 +- src/agents/models-config.providers.ts | 14 +- ...s-writing-models-json-no-env-token.test.ts | 34 +- src/agents/models-config.ts | 12 +- ...-github-copilot-profile-env-tokens.test.ts | 18 +- src/agents/models.profiles.live.test.ts | 22 +- ....test.ts => openclaw-gateway-tool.test.ts} | 32 +- ....test.ts => openclaw-tools.agents.test.ts} | 10 +- ....test.ts => openclaw-tools.camera.test.ts} | 8 +- ... => openclaw-tools.session-status.test.ts} | 18 +- ...est.ts => openclaw-tools.sessions.test.ts} | 18 +- ...s-cross-agent-spawning-configured.test.ts} | 8 +- ...unces-agent-wait-lifecycle-events.test.ts} | 6 +- ...spawn-applies-model-child-session.test.ts} | 12 +- ...-normalizes-allowlisted-agent-ids.test.ts} | 12 +- ...-prefers-per-agent-subagent-model.test.ts} | 10 +- ...esolves-main-announce-target-from.test.ts} | 8 +- .../{moltbot-tools.ts => openclaw-tools.ts} | 6 +- ...d-helpers.resolvebootstrapmaxchars.test.ts | 6 +- src/agents/pi-embedded-helpers/bootstrap.ts | 4 +- src/agents/pi-embedded-helpers/errors.ts | 4 +- src/agents/pi-embedded-helpers/openai.ts | 2 +- ...i-embedded-runner-extraparams.live.test.ts | 4 +- ...-runner.applygoogleturnorderingfix.test.ts | 10 +- ...ed-runner.buildembeddedsandboxinfo.test.ts | 36 +- ...-runner.createsystempromptoverride.test.ts | 10 +- ...s-back-provider-default-per-dm-not.test.ts | 20 +- ...-undefined-sessionkey-is-undefined.test.ts | 32 +- ...-embedded-runner.limithistoryturns.test.ts | 10 +- ...dded-runner.resolvesessionagentids.test.ts | 12 +- ...ded-pi-agent.auth-profile-rotation.test.ts | 38 +- .../pi-embedded-runner.splitsdktools.test.ts | 10 +- src/agents/pi-embedded-runner.test.ts | 12 +- src/agents/pi-embedded-runner/cache-ttl.ts | 2 +- src/agents/pi-embedded-runner/compact.ts | 20 +- src/agents/pi-embedded-runner/extensions.ts | 10 +- src/agents/pi-embedded-runner/extra-params.ts | 6 +- src/agents/pi-embedded-runner/history.ts | 6 +- src/agents/pi-embedded-runner/model.test.ts | 4 +- src/agents/pi-embedded-runner/model.ts | 10 +- .../run.overflow-compaction.test.ts | 4 +- src/agents/pi-embedded-runner/run.ts | 8 +- src/agents/pi-embedded-runner/run/attempt.ts | 12 +- .../pi-embedded-runner/run/images.test.ts | 6 +- src/agents/pi-embedded-runner/run/params.ts | 4 +- src/agents/pi-embedded-runner/run/payloads.ts | 4 +- src/agents/pi-embedded-runner/run/types.ts | 4 +- .../session-manager-cache.ts | 2 +- src/agents/pi-embedded-runner/utils.ts | 6 +- .../pi-embedded-subscribe.raw-stream.ts | 4 +- src/agents/pi-settings.ts | 4 +- src/agents/pi-tools-agent-config.test.ts | 84 +-- ...liases-schemas-without-dropping-b.test.ts} | 24 +- ...liases-schemas-without-dropping-d.test.ts} | 40 +- ...liases-schemas-without-dropping-f.test.ts} | 20 +- ...-aliases-schemas-without-dropping.test.ts} | 28 +- src/agents/pi-tools.policy.ts | 8 +- src/agents/pi-tools.read.ts | 4 +- src/agents/pi-tools.safe-bins.test.ts | 12 +- src/agents/pi-tools.ts | 16 +- src/agents/pi-tools.workspace-paths.test.ts | 46 +- ...n-status-default-sandbox-allowlist.test.ts | 8 +- ...nt-specific-docker-settings-beyond.test.ts | 18 +- ...d-use-agent-specific-workspaceroot.test.ts | 18 +- ...use-global-sandbox-config-no-agent.test.ts | 14 +- src/agents/sandbox-create-args.test.ts | 34 +- src/agents/sandbox-explain.test.ts | 14 +- src/agents/sandbox-skills.test.ts | 12 +- .../sandbox.resolveSandboxContext.test.ts | 20 +- src/agents/sandbox/browser.ts | 28 +- src/agents/sandbox/config.ts | 7 +- src/agents/sandbox/constants.ts | 14 +- src/agents/sandbox/context.ts | 6 +- src/agents/sandbox/docker.ts | 33 +- src/agents/sandbox/runtime-status.ts | 18 +- src/agents/sandbox/tool-policy.ts | 4 +- ...ult-guard.tool-result-persist-hook.test.ts | 10 +- src/agents/session-transcript-repair.ts | 2 +- src/agents/session-write-lock.test.ts | 12 +- src/agents/shell-utils.test.ts | 2 +- src/agents/skills-install.ts | 4 +- src/agents/skills-status.ts | 6 +- .../skills.applyskillenvoverrides.test.ts | 8 +- ...without-affecting-workspace-skills.test.ts | 2 +- ...rs-workspace-skills-managed-skills.test.ts | 18 +- ...pty-prompt-skills-dirs-are-missing.test.ts | 8 +- ...erged-skills-into-target-workspace.test.ts | 10 +- ...skills.buildworkspaceskillcommands.test.ts | 6 +- ...skills.buildworkspaceskillsnapshot.test.ts | 4 +- .../skills.buildworkspaceskillstatus.test.ts | 22 +- .../skills.loadworkspaceskillentries.test.ts | 14 +- .../skills.resolveskillspromptforrun.test.ts | 6 +- src/agents/skills.ts | 6 +- src/agents/skills/bundled-dir.ts | 2 +- src/agents/skills/config.ts | 16 +- src/agents/skills/env-overrides.ts | 6 +- src/agents/skills/frontmatter.ts | 22 +- src/agents/skills/plugin-skills.ts | 4 +- src/agents/skills/refresh.ts | 6 +- src/agents/skills/types.ts | 4 +- src/agents/skills/workspace.ts | 32 +- .../subagent-registry.persistence.test.ts | 22 +- src/agents/system-prompt-params.test.ts | 10 +- src/agents/system-prompt-params.ts | 6 +- src/agents/system-prompt.test.ts | 72 +- src/agents/system-prompt.ts | 42 +- src/agents/timeout.ts | 6 +- src/agents/tool-images.ts | 2 +- src/agents/tool-policy.test.ts | 4 +- src/agents/tool-policy.ts | 4 +- src/agents/tools/browser-tool.ts | 10 +- src/agents/tools/discord-actions.ts | 4 +- src/agents/tools/gateway-tool.ts | 4 +- src/agents/tools/image-tool.helpers.ts | 6 +- src/agents/tools/image-tool.test.ts | 40 +- src/agents/tools/image-tool.ts | 18 +- src/agents/tools/memory-tool.ts | 6 +- src/agents/tools/message-tool.ts | 8 +- src/agents/tools/nodes-tool.ts | 4 +- src/agents/tools/session-status-tool.ts | 10 +- src/agents/tools/sessions-helpers.ts | 6 +- src/agents/tools/sessions-send-helpers.ts | 4 +- src/agents/tools/sessions-send-tool.ts | 4 +- src/agents/tools/slack-actions.test.ts | 46 +- src/agents/tools/slack-actions.ts | 4 +- src/agents/tools/telegram-actions.test.ts | 50 +- src/agents/tools/telegram-actions.ts | 4 +- src/agents/tools/tts-tool.ts | 4 +- src/agents/tools/web-fetch.ts | 8 +- src/agents/tools/web-search.ts | 22 +- src/agents/tools/whatsapp-actions.test.ts | 6 +- src/agents/tools/whatsapp-actions.ts | 4 +- src/agents/workspace.test.ts | 6 +- src/agents/workspace.ts | 6 +- src/auto-reply/chunk.ts | 6 +- src/auto-reply/command-auth.ts | 12 +- src/auto-reply/command-control.test.ts | 18 +- src/auto-reply/command-detection.ts | 8 +- src/auto-reply/commands-registry.data.ts | 2 +- src/auto-reply/commands-registry.test.ts | 12 +- src/auto-reply/commands-registry.ts | 22 +- src/auto-reply/commands-registry.types.ts | 6 +- src/auto-reply/dispatch.ts | 8 +- src/auto-reply/envelope.ts | 4 +- src/auto-reply/inbound-debounce.ts | 4 +- src/auto-reply/inbound.test.ts | 24 +- src/auto-reply/reply.block-streaming.test.ts | 12 +- ...ts-thinking-xhigh-codex-models.e2e.test.ts | 22 +- ...ixed-messages-acks-immediately.e2e.test.ts | 20 +- ...ow-reasoning-capable-models-no.e2e.test.ts | 18 +- ...nline-model-uses-default-model.e2e.test.ts | 12 +- ...-allowlisted-models-model-list.e2e.test.ts | 20 +- ...s-fuzzy-selection-is-ambiguous.e2e.test.ts | 18 +- ...gent-allowlist-addition-global.e2e.test.ts | 16 +- ...-alongside-directive-only-acks.e2e.test.ts | 18 +- ...nt-elevated-level-as-off-after.e2e.test.ts | 14 +- ...t-verbose-level-verbose-has-no.e2e.test.ts | 18 +- ...-model-matches-model-directive.e2e.test.ts | 16 +- ...rbose-during-flight-run-toggle.e2e.test.ts | 16 +- src/auto-reply/reply.heartbeat-typing.test.ts | 4 +- src/auto-reply/reply.media-note.test.ts | 6 +- src/auto-reply/reply.queue.test.ts | 4 +- src/auto-reply/reply.raw-body.test.ts | 16 +- ...y.triggers.group-intro-prompts.e2e.test.ts | 6 +- ...tivation-from-allowfrom-groups.e2e.test.ts | 10 +- ...ed-sender-toggle-elevated-mode.e2e.test.ts | 10 +- ...ted-off-groups-without-mention.e2e.test.ts | 10 +- ...summary-current-model-provider.e2e.test.ts | 4 +- ...ommands-strips-it-before-agent.e2e.test.ts | 8 +- ...ed-directive-unapproved-sender.e2e.test.ts | 10 +- ...or-cause-embedded-agent-throws.e2e.test.ts | 6 +- ...ne-status-unauthorized-senders.e2e.test.ts | 10 +- ...uth-profile-key-snippet-status.e2e.test.ts | 6 +- ....runs-compact-as-gated-command.e2e.test.ts | 8 +- ...uns-greeting-prompt-bare-reset.e2e.test.ts | 16 +- ...lt-model-status-not-configured.e2e.test.ts | 6 +- ...-model-picker-grouped-by-model.e2e.test.ts | 4 +- ...bound-media-into-sandbox-workspace.test.ts | 8 +- ...ets-active-session-native-stop.e2e.test.ts | 6 +- src/auto-reply/reply/abort.test.ts | 18 +- src/auto-reply/reply/abort.ts | 8 +- .../reply/agent-runner-execution.ts | 2 +- src/auto-reply/reply/agent-runner-memory.ts | 4 +- .../reply/agent-runner-utils.test.ts | 6 +- src/auto-reply/reply/agent-runner-utils.ts | 4 +- ...gent-runner.authprofileid-fallback.test.ts | 4 +- ...emini-sessions-deletes-transcripts.test.ts | 20 +- ...ction-failure-by-resetting-session.test.ts | 30 +- ...tbeat.signals-typing-block-replies.test.ts | 2 +- ...eplies-even-if-session-reset-fails.test.ts | 10 +- ...n-count-flush-compaction-completes.test.ts | 2 +- ...lush-turn-updates-session-metadata.test.ts | 4 +- ...h.skips-memory-flush-cli-providers.test.ts | 2 +- ...ry-flush-sandbox-workspace-is-read.test.ts | 4 +- ...nfigured-prompts-memory-flush-runs.test.ts | 4 +- .../agent-runner.messaging-tools.test.ts | 2 +- src/auto-reply/reply/bash-command.ts | 12 +- src/auto-reply/reply/block-streaming.ts | 8 +- src/auto-reply/reply/commands-allowlist.ts | 8 +- src/auto-reply/reply/commands-approve.test.ts | 8 +- src/auto-reply/reply/commands-compact.ts | 4 +- .../reply/commands-context-report.ts | 4 +- src/auto-reply/reply/commands-context.ts | 4 +- src/auto-reply/reply/commands-models.ts | 4 +- src/auto-reply/reply/commands-parsing.test.ts | 6 +- src/auto-reply/reply/commands-policy.test.ts | 12 +- src/auto-reply/reply/commands-session.ts | 8 +- src/auto-reply/reply/commands-status.ts | 6 +- src/auto-reply/reply/commands-types.ts | 4 +- src/auto-reply/reply/commands.test.ts | 48 +- .../reply/directive-handling.auth.ts | 6 +- .../reply/directive-handling.fast-lane.ts | 6 +- .../reply/directive-handling.impl.ts | 6 +- .../reply/directive-handling.model-picker.ts | 4 +- .../reply/directive-handling.model.test.ts | 10 +- .../reply/directive-handling.model.ts | 8 +- .../reply/directive-handling.parse.ts | 4 +- .../reply/directive-handling.persist.ts | 8 +- .../directive-handling.queue-validation.ts | 4 +- .../reply/directive-handling.shared.ts | 2 +- .../reply/dispatch-from-config.test.ts | 38 +- src/auto-reply/reply/dispatch-from-config.ts | 6 +- src/auto-reply/reply/followup-runner.test.ts | 4 +- .../reply/get-reply-directives-apply.ts | 6 +- src/auto-reply/reply/get-reply-directives.ts | 6 +- .../reply/get-reply-inline-actions.ts | 8 +- src/auto-reply/reply/get-reply-run.ts | 8 +- src/auto-reply/reply/get-reply.ts | 6 +- src/auto-reply/reply/groups.ts | 8 +- src/auto-reply/reply/memory-flush.ts | 4 +- src/auto-reply/reply/mentions.test.ts | 6 +- src/auto-reply/reply/mentions.ts | 8 +- .../model-selection.inherit-parent.test.ts | 12 +- src/auto-reply/reply/model-selection.ts | 8 +- src/auto-reply/reply/provider-dispatcher.ts | 6 +- .../reply/queue.collect-routing.test.ts | 4 +- src/auto-reply/reply/queue/types.ts | 6 +- src/auto-reply/reply/reply-elevated.ts | 6 +- src/auto-reply/reply/reply-routing.test.ts | 12 +- src/auto-reply/reply/reply-threading.ts | 4 +- .../reply/response-prefix-template.test.ts | 12 +- src/auto-reply/reply/route-reply.test.ts | 12 +- src/auto-reply/reply/route-reply.ts | 4 +- src/auto-reply/reply/session-reset-model.ts | 4 +- src/auto-reply/reply/session-resets.test.ts | 24 +- src/auto-reply/reply/session-updates.ts | 10 +- src/auto-reply/reply/session.test.ts | 58 +- src/auto-reply/reply/session.ts | 4 +- src/auto-reply/reply/stage-sandbox-media.ts | 6 +- src/auto-reply/skill-commands.test.ts | 2 +- src/auto-reply/skill-commands.ts | 6 +- src/auto-reply/status.test.ts | 24 +- src/auto-reply/status.ts | 20 +- src/auto-reply/templating.ts | 2 +- src/browser/chrome.profile-decoration.ts | 13 +- src/browser/chrome.test.ts | 51 +- src/browser/chrome.ts | 29 +- src/browser/client-fetch.ts | 6 +- src/browser/client.ts | 2 +- src/browser/config.test.ts | 46 +- src/browser/config.ts | 32 +- src/browser/constants.ts | 6 +- src/browser/control-service.ts | 2 +- src/browser/extension-relay.ts | 6 +- src/browser/profiles-service.test.ts | 16 +- src/browser/profiles-service.ts | 12 +- src/browser/profiles.test.ts | 10 +- src/browser/profiles.ts | 2 +- .../pw-session.browserless.live.test.ts | 4 +- src/browser/pw-tools-core.downloads.ts | 2 +- src/browser/pw-tools-core.interactions.ts | 10 +- src/browser/pw-tools-core.responses.ts | 2 +- src/browser/routes/agent.act.ts | 4 +- src/browser/routes/agent.debug.ts | 2 +- src/browser/routes/basic.ts | 2 +- ...-tab-available.prefers-last-target.test.ts | 12 +- .../server-context.remote-tab-ops.test.ts | 18 +- src/browser/server-context.ts | 22 +- ...-contract-form-layout-act-commands.test.ts | 20 +- ....agent-contract-snapshot-endpoints.test.ts | 20 +- ...overs-additional-endpoint-branches.test.ts | 52 +- ...s-open-profile-unknown-returns-404.test.ts | 40 +- ...es-status-starts-browser-requested.test.ts | 20 +- ...fault-maxchars-explicitly-set-zero.test.ts | 24 +- src/browser/server.ts | 4 +- src/canvas-host/a2ui.ts | 36 +- src/canvas-host/a2ui/index.html | 56 +- src/canvas-host/server.test.ts | 30 +- src/canvas-host/server.ts | 66 +- src/channels/dock.ts | 6 +- src/channels/plugins/actions/discord.test.ts | 14 +- src/channels/plugins/actions/signal.test.ts | 18 +- src/channels/plugins/actions/telegram.test.ts | 12 +- src/channels/plugins/catalog.test.ts | 10 +- src/channels/plugins/catalog.ts | 28 +- src/channels/plugins/config-helpers.ts | 22 +- src/channels/plugins/config-writes.ts | 4 +- src/channels/plugins/directory-config.ts | 4 +- src/channels/plugins/group-mentions.ts | 6 +- src/channels/plugins/helpers.ts | 8 +- src/channels/plugins/media-limits.ts | 6 +- src/channels/plugins/message-actions.ts | 8 +- src/channels/plugins/onboarding-types.ts | 22 +- src/channels/plugins/onboarding/discord.ts | 18 +- src/channels/plugins/onboarding/imessage.ts | 14 +- src/channels/plugins/onboarding/signal.ts | 16 +- src/channels/plugins/onboarding/slack.ts | 28 +- src/channels/plugins/onboarding/telegram.ts | 18 +- src/channels/plugins/onboarding/whatsapp.ts | 22 +- .../plugins/outbound/telegram.test.ts | 6 +- src/channels/plugins/pairing-message.ts | 2 +- src/channels/plugins/pairing.ts | 4 +- src/channels/plugins/setup-helpers.ts | 20 +- src/channels/plugins/slack.actions.test.ts | 4 +- .../plugins/status-issues/bluebubbles.ts | 2 +- .../plugins/status-issues/whatsapp.ts | 4 +- src/channels/plugins/status.ts | 4 +- src/channels/plugins/types.adapters.ts | 84 +-- src/channels/plugins/types.core.ts | 28 +- src/channels/plugins/whatsapp-heartbeat.ts | 6 +- src/channels/registry.test.ts | 2 +- src/channels/registry.ts | 2 +- src/channels/reply-prefix.ts | 4 +- src/cli/acp-cli.ts | 4 +- src/cli/argv.test.ts | 120 ++-- src/cli/argv.ts | 4 +- src/cli/banner.ts | 16 +- .../register.files-downloads.ts | 2 +- src/cli/browser-cli-examples.ts | 58 +- src/cli/browser-cli-extension.test.ts | 12 +- src/cli/browser-cli-extension.ts | 10 +- src/cli/browser-cli-manage.ts | 8 +- src/cli/browser-cli.ts | 6 +- src/cli/channel-options.ts | 2 +- src/cli/channels-cli.ts | 2 +- src/cli/cli-name.ts | 14 +- src/cli/command-format.ts | 6 +- src/cli/config-cli.ts | 4 +- src/cli/cron-cli/register.ts | 3 +- src/cli/daemon-cli.coverage.test.ts | 48 +- src/cli/daemon-cli/install.ts | 4 +- src/cli/daemon-cli/register.ts | 2 +- src/cli/daemon-cli/shared.ts | 24 +- src/cli/daemon-cli/status.gather.ts | 10 +- src/cli/daemon-cli/status.print.ts | 27 +- src/cli/directory-cli.ts | 2 +- src/cli/dns-cli.test.ts | 4 +- src/cli/dns-cli.ts | 39 +- src/cli/docs-cli.ts | 5 +- src/cli/exec-approvals-cli.ts | 12 +- src/cli/gateway-cli.coverage.test.ts | 14 +- src/cli/gateway-cli/dev.ts | 4 +- src/cli/gateway-cli/register.ts | 20 +- src/cli/gateway-cli/run.ts | 24 +- src/cli/gateway-cli/shared.ts | 10 +- src/cli/gateway.sigterm.test.ts | 18 +- src/cli/hooks-cli.test.ts | 6 +- src/cli/hooks-cli.ts | 16 +- src/cli/logs-cli.test.ts | 4 +- src/cli/logs-cli.ts | 7 +- src/cli/memory-cli.test.ts | 12 +- src/cli/memory-cli.ts | 2 +- src/cli/models-cli.ts | 2 +- src/cli/node-cli/daemon.ts | 6 +- src/cli/node-cli/register.ts | 3 +- src/cli/nodes-camera.test.ts | 4 +- src/cli/nodes-cli/register.canvas.ts | 2 +- src/cli/nodes-cli/register.ts | 2 +- src/cli/nodes-screen.test.ts | 2 +- src/cli/nodes-screen.ts | 2 +- src/cli/pairing-cli.ts | 6 +- src/cli/plugin-registry.ts | 4 +- src/cli/plugins-cli.ts | 20 +- src/cli/profile.test.ts | 78 +- src/cli/profile.ts | 16 +- src/cli/program.nodes-media.test.ts | 4 +- src/cli/program/config-guard.ts | 4 +- src/cli/program/help.ts | 25 +- src/cli/program/preaction.ts | 2 +- src/cli/program/register.agent.ts | 27 +- src/cli/program/register.configure.ts | 2 +- src/cli/program/register.maintenance.ts | 8 +- src/cli/program/register.message.ts | 10 +- src/cli/program/register.onboard.ts | 4 +- src/cli/program/register.setup.ts | 6 +- .../register.status-health-sessions.ts | 26 +- src/cli/program/register.subclis.test.ts | 16 +- src/cli/program/register.subclis.ts | 8 +- src/cli/route.ts | 2 +- src/cli/run-main.ts | 6 +- src/cli/sandbox-cli.ts | 38 +- src/cli/security-cli.ts | 8 +- src/cli/skills-cli.ts | 6 +- src/cli/system-cli.ts | 2 +- src/cli/tagline.ts | 4 +- src/cli/tui-cli.ts | 2 +- src/cli/update-cli.test.ts | 58 +- src/cli/update-cli.ts | 92 +-- src/cli/webhooks-cli.ts | 12 +- src/commands/agent-via-gateway.test.ts | 10 +- src/commands/agent-via-gateway.ts | 2 +- src/commands/agent.delivery.test.ts | 16 +- src/commands/agent.test.ts | 10 +- src/commands/agent.ts | 2 +- src/commands/agent/delivery.ts | 4 +- src/commands/agent/session-store.ts | 4 +- src/commands/agent/session.ts | 6 +- src/commands/agents.add.test.ts | 2 +- src/commands/agents.bindings.ts | 12 +- src/commands/agents.command-shared.ts | 6 +- src/commands/agents.commands.add.ts | 4 +- src/commands/agents.commands.list.ts | 2 +- src/commands/agents.config.ts | 20 +- src/commands/agents.identity.test.ts | 26 +- src/commands/agents.providers.ts | 12 +- src/commands/agents.test.ts | 12 +- src/commands/auth-choice.apply.openai.ts | 2 +- .../auth-choice.apply.plugin-provider.ts | 8 +- src/commands/auth-choice.apply.ts | 6 +- src/commands/auth-choice.default-model.ts | 10 +- src/commands/auth-choice.model-check.ts | 4 +- src/commands/auth-choice.test.ts | 80 +-- ....adds-non-default-telegram-account.test.ts | 8 +- ...time-errors-channels-status-output.test.ts | 2 +- src/commands/channels/add-mutators.ts | 10 +- src/commands/channels/add.ts | 4 +- src/commands/channels/capabilities.test.ts | 2 +- src/commands/channels/capabilities.ts | 4 +- src/commands/channels/remove.ts | 4 +- src/commands/channels/shared.ts | 6 +- src/commands/channels/status.ts | 6 +- src/commands/chutes-oauth.ts | 2 +- src/commands/cleanup-utils.ts | 4 +- src/commands/configure.channels.ts | 12 +- src/commands/configure.gateway-auth.ts | 6 +- src/commands/configure.gateway.ts | 10 +- src/commands/configure.wizard.test.ts | 8 +- src/commands/configure.wizard.ts | 50 +- src/commands/daemon-install-helpers.test.ts | 24 +- src/commands/daemon-install-helpers.ts | 8 +- src/commands/dashboard.test.ts | 4 +- src/commands/dashboard.ts | 4 +- src/commands/docs.ts | 10 +- ...octor-auth.deprecated-cli-profiles.test.ts | 10 +- src/commands/doctor-auth.ts | 30 +- src/commands/doctor-config-flow.test.ts | 8 +- src/commands/doctor-config-flow.ts | 58 +- src/commands/doctor-format.ts | 10 +- src/commands/doctor-gateway-daemon-flow.ts | 15 +- src/commands/doctor-gateway-health.ts | 4 +- src/commands/doctor-gateway-services.ts | 99 +-- src/commands/doctor-legacy-config.test.ts | 12 +- src/commands/doctor-legacy-config.ts | 8 +- ...form-notes.launchctl-env-overrides.test.ts | 18 +- src/commands/doctor-platform-notes.ts | 77 +- src/commands/doctor-sandbox.ts | 26 +- src/commands/doctor-security.test.ts | 28 +- src/commands/doctor-security.ts | 16 +- src/commands/doctor-state-integrity.ts | 16 +- src/commands/doctor-state-migrations.test.ts | 85 +-- src/commands/doctor-ui.ts | 4 +- src/commands/doctor-update.ts | 10 +- src/commands/doctor-workspace-status.ts | 8 +- src/commands/doctor-workspace.test.ts | 30 +- src/commands/doctor-workspace.ts | 39 +- ...-back-legacy-sandbox-image-missing.test.ts | 40 +- ...owfrom-channels-whatsapp-allowfrom.test.ts | 54 +- ...-state-migrations-yes-mode-without.test.ts | 40 +- src/commands/doctor.ts | 24 +- ...agent-sandbox-docker-browser-prune.test.ts | 59 +- ...r.warns-state-directory-is-missing.test.ts | 54 +- src/commands/gateway-status.ts | 10 +- src/commands/gateway-status/helpers.ts | 12 +- .../google-gemini-model-default.test.ts | 8 +- src/commands/google-gemini-model-default.ts | 6 +- src/commands/health-format.test.ts | 4 +- src/commands/health.snapshot.test.ts | 2 +- src/commands/health.ts | 8 +- src/commands/model-picker.test.ts | 16 +- src/commands/model-picker.ts | 20 +- src/commands/models.list.test.ts | 14 +- src/commands/models.set.test.ts | 8 +- src/commands/models/auth.ts | 6 +- src/commands/models/list.auth-overview.ts | 4 +- src/commands/models/list.configured.ts | 4 +- src/commands/models/list.probe.ts | 14 +- src/commands/models/list.registry.ts | 16 +- src/commands/models/list.status-command.ts | 8 +- src/commands/models/list.status.test.ts | 8 +- src/commands/models/shared.ts | 10 +- src/commands/node-daemon-install-helpers.ts | 2 +- src/commands/onboard-auth.config-core.ts | 32 +- src/commands/onboard-auth.config-minimax.ts | 22 +- src/commands/onboard-auth.config-opencode.ts | 6 +- src/commands/onboard-auth.credentials.ts | 4 +- src/commands/onboard-auth.test.ts | 50 +- src/commands/onboard-channels.test.ts | 8 +- src/commands/onboard-channels.ts | 22 +- src/commands/onboard-helpers.ts | 18 +- src/commands/onboard-hooks.test.ts | 22 +- src/commands/onboard-hooks.ts | 16 +- ...onboard-non-interactive.ai-gateway.test.ts | 50 +- .../onboard-non-interactive.gateway.test.ts | 64 +- .../onboard-non-interactive.token.test.ts | 50 +- src/commands/onboard-non-interactive.ts | 6 +- .../onboard-non-interactive/api-keys.ts | 6 +- src/commands/onboard-non-interactive/local.ts | 8 +- .../local/auth-choice.ts | 8 +- .../local/daemon-install.ts | 4 +- .../local/gateway-config.ts | 6 +- .../local/skills-config.ts | 4 +- .../local/workspace.ts | 4 +- .../onboard-non-interactive/remote.ts | 8 +- src/commands/onboard-remote.ts | 16 +- src/commands/onboard-skills.ts | 16 +- src/commands/onboard.ts | 6 +- .../onboarding/plugin-install.test.ts | 20 +- src/commands/onboarding/plugin-install.ts | 16 +- .../openai-codex-model-default.test.ts | 10 +- src/commands/openai-codex-model-default.ts | 6 +- .../opencode-zen-model-default.test.ts | 12 +- src/commands/opencode-zen-model-default.ts | 6 +- src/commands/reset.ts | 6 +- src/commands/sandbox-display.ts | 2 +- src/commands/sandbox-explain.test.ts | 4 +- src/commands/sandbox-explain.ts | 12 +- src/commands/sandbox.test.ts | 8 +- src/commands/setup.ts | 8 +- src/commands/signal-install.ts | 4 +- src/commands/status-all.ts | 10 +- src/commands/status-all/agents.ts | 4 +- src/commands/status-all/channels.ts | 16 +- src/commands/status-all/diagnosis.ts | 2 +- src/commands/status-all/report-lines.ts | 2 +- src/commands/status.command.ts | 18 +- src/commands/status.gateway-probe.ts | 4 +- src/commands/status.link-channel.ts | 4 +- src/commands/status.scan.ts | 4 +- src/commands/status.test.ts | 40 +- src/commands/status.update.ts | 6 +- src/commands/uninstall.ts | 8 +- src/compat/legacy-names.ts | 16 +- src/config/agent-dirs.ts | 8 +- src/config/agent-limits.ts | 6 +- src/config/channel-capabilities.test.ts | 10 +- src/config/channel-capabilities.ts | 4 +- .../config.agent-concurrency-defaults.test.ts | 4 +- src/config/config.backup-rotation.test.ts | 6 +- src/config/config.compaction-settings.test.ts | 8 +- src/config/config.discord.test.ts | 12 +- src/config/config.env-vars.test.ts | 12 +- src/config/config.identity-avatar.test.ts | 8 +- src/config/config.identity-defaults.test.ts | 44 +- ...etection.accepts-imessage-dmpolicy.test.ts | 16 +- ...etection.rejects-routing-allowfrom.test.ts | 6 +- ...ig.multi-agent-agentdir-validation.test.ts | 10 +- .../config.nix-integration-u3-u5-u9.test.ts | 144 ++-- src/config/config.plugin-validation.test.ts | 16 +- ...preservation-on-validation-failure.test.ts | 4 +- src/config/config.pruning-defaults.test.ts | 16 +- .../config.skills-entries-config.test.ts | 6 +- .../config.telegram-custom-commands.test.ts | 6 +- src/config/config.ts | 2 +- src/config/defaults.ts | 24 +- src/config/env-substitution.test.ts | 4 +- src/config/env-vars.ts | 4 +- src/config/group-policy.ts | 10 +- src/config/includes.test.ts | 12 +- src/config/io.compat.test.ts | 65 +- src/config/io.ts | 44 +- src/config/legacy-migrate.ts | 4 +- src/config/markdown-tables.ts | 4 +- src/config/merge-config.ts | 6 +- src/config/model-alias-defaults.test.ts | 10 +- src/config/normalize-paths.test.ts | 16 +- src/config/normalize-paths.ts | 4 +- src/config/paths.test.ts | 75 +- src/config/paths.ts | 104 +-- src/config/plugin-auto-enable.ts | 40 +- src/config/runtime-overrides.test.ts | 8 +- src/config/runtime-overrides.ts | 6 +- src/config/schema.ts | 24 +- src/config/sessions.cache.test.ts | 8 +- src/config/sessions.test.ts | 44 +- src/config/sessions/store.ts | 2 +- src/config/sessions/transcript.ts | 2 +- src/config/test-helpers.ts | 2 +- src/config/types.browser.ts | 6 +- src/config/types.gateway.ts | 6 +- src/config/types.imessage.ts | 2 +- .../{types.clawdbot.ts => types.openclaw.ts} | 8 +- src/config/types.slack.ts | 2 +- src/config/types.ts | 2 +- src/config/types.whatsapp.ts | 2 +- src/config/validation.ts | 18 +- src/config/version.ts | 10 +- src/config/zod-schema.ts | 5 +- src/cron/cron-protocol-conformance.test.ts | 7 +- ...onse-has-heartbeat-ok-but-includes.test.ts | 16 +- ...p-recipient-besteffortdeliver-true.test.ts | 16 +- ....uses-last-non-empty-agent-text-as.test.ts | 18 +- src/cron/isolated-agent/delivery-target.ts | 4 +- src/cron/isolated-agent/run.ts | 6 +- src/cron/isolated-agent/session.ts | 4 +- src/cron/run-log.test.ts | 4 +- .../service.prevents-duplicate-timers.test.ts | 2 +- ...runs-one-shot-main-job-disables-it.test.ts | 2 +- ...s-main-jobs-empty-systemevent-text.test.ts | 2 +- src/daemon/constants.test.ts | 32 +- src/daemon/constants.ts | 44 +- src/daemon/inspect.ts | 48 +- src/daemon/launchd.test.ts | 92 +-- src/daemon/launchd.ts | 14 +- src/daemon/legacy.ts | 70 -- src/daemon/node-service.ts | 28 +- src/daemon/paths.test.ts | 26 +- src/daemon/paths.ts | 6 +- src/daemon/program-args.test.ts | 16 +- src/daemon/program-args.ts | 2 +- src/daemon/schtasks.test.ts | 100 +-- src/daemon/schtasks.ts | 12 +- src/daemon/service-env.test.ts | 20 +- src/daemon/service-env.ts | 46 +- src/daemon/systemd-hints.ts | 2 +- src/daemon/systemd-unit.test.ts | 14 +- src/daemon/systemd-unit.ts | 2 +- src/daemon/systemd.test.ts | 44 +- src/daemon/systemd.ts | 12 +- src/discord/accounts.ts | 16 +- src/discord/audit.test.ts | 2 +- src/discord/audit.ts | 4 +- src/discord/monitor.slash.test.ts | 4 +- src/discord/monitor.test.ts | 28 +- ...ild-messages-mentionpatterns-match.test.ts | 36 +- ...ends-status-replies-responseprefix.test.ts | 26 +- src/discord/monitor/exec-approvals.ts | 4 +- .../message-handler.inbound-contract.test.ts | 2 +- .../message-handler.preflight.types.ts | 4 +- .../monitor/message-handler.process.test.ts | 2 +- src/discord/monitor/message-handler.ts | 2 +- src/discord/monitor/native-command.ts | 4 +- src/discord/monitor/provider.ts | 4 +- src/discord/send.creates-thread.test.ts | 8 +- src/discord/targets.test.ts | 4 +- src/discord/token.test.ts | 8 +- src/discord/token.ts | 4 +- src/docker-setup.test.ts | 44 +- src/entry.ts | 17 +- src/gateway/assistant-identity.test.ts | 12 +- src/gateway/assistant-identity.ts | 4 +- src/gateway/auth.ts | 11 +- src/gateway/boot.test.ts | 6 +- src/gateway/boot.ts | 4 +- src/gateway/call.test.ts | 22 +- src/gateway/call.ts | 10 +- src/gateway/config-reload.ts | 10 +- src/gateway/control-ui.ts | 14 +- src/gateway/gateway-cli-backend.live.test.ts | 88 +-- .../gateway-models.profiles.live.test.ts | 142 ++-- src/gateway/gateway.e2e.test.ts | 102 +-- src/gateway/hooks-mapping.test.ts | 4 +- src/gateway/hooks.test.ts | 10 +- src/gateway/hooks.ts | 8 +- src/gateway/http-utils.ts | 8 +- src/gateway/node-command-policy.ts | 4 +- src/gateway/openai-http.e2e.test.ts | 42 +- src/gateway/openai-http.ts | 6 +- src/gateway/openresponses-http.e2e.test.ts | 48 +- src/gateway/openresponses-http.ts | 8 +- src/gateway/protocol/client-info.ts | 10 +- src/gateway/server-browser.ts | 4 +- src/gateway/server-channels.ts | 4 +- src/gateway/server-constants.ts | 4 +- src/gateway/server-cron.ts | 2 +- src/gateway/server-discovery-runtime.ts | 19 +- src/gateway/server-discovery.test.ts | 10 +- src/gateway/server-discovery.ts | 14 +- src/gateway/server-http.ts | 2 +- src/gateway/server-methods/channels.ts | 4 +- src/gateway/server-methods/config.ts | 4 +- src/gateway/server-methods/logs.test.ts | 8 +- src/gateway/server-methods/logs.ts | 2 +- src/gateway/server-methods/skills.ts | 6 +- src/gateway/server-methods/update.ts | 4 +- src/gateway/server-plugins.test.ts | 6 +- src/gateway/server-plugins.ts | 4 +- src/gateway/server-reload-handlers.ts | 10 +- src/gateway/server-runtime-config.ts | 6 +- src/gateway/server-runtime-state.ts | 2 +- src/gateway/server-startup.ts | 16 +- ...r.agent.gateway-server-agent-a.e2e.test.ts | 28 +- ...r.agent.gateway-server-agent-b.e2e.test.ts | 10 +- src/gateway/server.auth.e2e.test.ts | 50 +- ...ver.chat.gateway-server-chat-b.e2e.test.ts | 2 +- ...erver.chat.gateway-server-chat.e2e.test.ts | 10 +- src/gateway/server.config-apply.e2e.test.ts | 12 +- src/gateway/server.config-patch.e2e.test.ts | 6 +- src/gateway/server.cron.e2e.test.ts | 20 +- src/gateway/server.health.e2e.test.ts | 10 +- src/gateway/server.hooks.e2e.test.ts | 2 +- src/gateway/server.impl.ts | 15 +- src/gateway/server.ios-client-id.e2e.test.ts | 8 +- .../server.models-voicewake-misc.e2e.test.ts | 42 +- src/gateway/server.reload.e2e.test.ts | 16 +- .../server.roles-allowlist-update.e2e.test.ts | 2 +- src/gateway/server.sessions-send.e2e.test.ts | 26 +- ...ions.gateway-server-sessions-a.e2e.test.ts | 14 +- .../server/ws-connection/message-handler.ts | 2 +- src/gateway/session-utils.fs.test.ts | 6 +- src/gateway/session-utils.fs.ts | 3 +- src/gateway/session-utils.test.ts | 14 +- src/gateway/session-utils.ts | 27 +- src/gateway/sessions-patch.test.ts | 12 +- src/gateway/sessions-patch.ts | 4 +- src/gateway/sessions-resolve.ts | 4 +- src/gateway/test-helpers.mocks.ts | 14 +- src/gateway/test-helpers.server.ts | 56 +- src/gateway/tools-invoke-http.test.ts | 4 +- src/gateway/tools-invoke-http.ts | 10 +- src/git-hooks.test.ts | 2 +- src/hooks/bundled-dir.ts | 4 +- src/hooks/bundled/README.md | 40 +- src/hooks/bundled/boot-md/HOOK.md | 6 +- src/hooks/bundled/boot-md/handler.ts | 4 +- src/hooks/bundled/command-logger/HOOK.md | 24 +- src/hooks/bundled/command-logger/handler.ts | 3 +- src/hooks/bundled/session-memory/HOOK.md | 10 +- .../bundled/session-memory/handler.test.ts | 34 +- src/hooks/bundled/session-memory/handler.ts | 10 +- src/hooks/bundled/soul-evil/HOOK.md | 10 +- src/hooks/bundled/soul-evil/README.md | 6 +- src/hooks/bundled/soul-evil/handler.test.ts | 6 +- src/hooks/bundled/soul-evil/handler.ts | 4 +- src/hooks/config.ts | 12 +- src/hooks/frontmatter.test.ts | 80 +-- src/hooks/frontmatter.ts | 22 +- src/hooks/gmail-ops.ts | 6 +- src/hooks/gmail-setup-utils.test.ts | 2 +- src/hooks/gmail-watcher.ts | 6 +- src/hooks/gmail.test.ts | 18 +- src/hooks/gmail.ts | 4 +- src/hooks/hooks-install.e2e.test.ts | 22 +- src/hooks/hooks-status.ts | 10 +- src/hooks/install.test.ts | 16 +- src/hooks/install.ts | 20 +- src/hooks/installs.ts | 4 +- src/hooks/internal-hooks.ts | 6 +- src/hooks/llm-slug-generator.ts | 6 +- src/hooks/loader.test.ts | 30 +- src/hooks/loader.ts | 9 +- src/hooks/plugin-hooks.ts | 14 +- src/hooks/soul-evil.test.ts | 10 +- src/hooks/types.ts | 6 +- src/hooks/workspace.ts | 32 +- src/imessage/accounts.ts | 16 +- ...essages-without-mention-by-default.test.ts | 16 +- ...last-route-chat-id-direct-messages.test.ts | 4 +- src/imessage/monitor/monitor-provider.ts | 4 +- src/imessage/monitor/types.ts | 4 +- src/index.ts | 8 +- src/infra/archive.test.ts | 2 +- src/infra/bonjour-discovery.test.ts | 44 +- src/infra/bonjour-discovery.ts | 46 +- src/infra/bonjour.test.ts | 20 +- src/infra/bonjour.ts | 21 +- src/infra/brew.test.ts | 4 +- src/infra/channel-summary.ts | 14 +- src/infra/control-ui-assets.test.ts | 4 +- src/infra/device-identity.ts | 2 +- src/infra/device-pairing.test.ts | 2 +- src/infra/diagnostic-events.ts | 4 +- src/infra/diagnostic-flags.test.ts | 10 +- src/infra/diagnostic-flags.ts | 8 +- src/infra/dotenv.test.ts | 10 +- src/infra/dotenv.ts | 2 +- src/infra/exec-approval-forwarder.test.ts | 6 +- src/infra/exec-approval-forwarder.ts | 10 +- src/infra/exec-approvals.test.ts | 4 +- src/infra/exec-approvals.ts | 4 +- src/infra/gateway-lock.test.ts | 8 +- src/infra/gateway-lock.ts | 6 +- ...espects-ackmaxchars-heartbeat-acks.test.ts | 34 +- ...tbeat-runner.returns-default-unset.test.ts | 70 +- src/infra/heartbeat-runner.scheduler.test.ts | 6 +- ...ner.sender-prefers-delivery-target.test.ts | 6 +- src/infra/heartbeat-runner.ts | 35 +- src/infra/heartbeat-visibility.test.ts | 28 +- src/infra/heartbeat-visibility.ts | 4 +- src/infra/is-main.test.ts | 2 +- src/infra/machine-name.ts | 2 +- .../{moltbot-root.ts => openclaw-root.ts} | 4 +- src/infra/outbound/agent-delivery.test.ts | 6 +- src/infra/outbound/agent-delivery.ts | 4 +- src/infra/outbound/channel-selection.ts | 8 +- src/infra/outbound/deliver.test.ts | 24 +- src/infra/outbound/deliver.ts | 8 +- src/infra/outbound/directory-cache.ts | 12 +- .../outbound/message-action-runner.test.ts | 14 +- .../message-action-runner.threading.test.ts | 4 +- src/infra/outbound/message-action-runner.ts | 18 +- src/infra/outbound/message.ts | 6 +- src/infra/outbound/outbound-policy.test.ts | 10 +- src/infra/outbound/outbound-policy.ts | 6 +- src/infra/outbound/outbound-send-service.ts | 4 +- src/infra/outbound/outbound-session.test.ts | 12 +- src/infra/outbound/outbound-session.ts | 10 +- src/infra/outbound/target-resolver.test.ts | 4 +- src/infra/outbound/target-resolver.ts | 12 +- src/infra/outbound/targets.test.ts | 4 +- src/infra/outbound/targets.ts | 10 +- src/infra/path-env.test.ts | 58 +- src/infra/path-env.ts | 24 +- src/infra/ports-format.ts | 6 +- src/infra/ports.test.ts | 2 +- src/infra/ports.ts | 4 +- src/infra/provider-usage.fetch.claude.ts | 2 +- src/infra/provider-usage.fetch.minimax.ts | 2 +- src/infra/provider-usage.test.ts | 6 +- src/infra/restart-sentinel.test.ts | 10 +- src/infra/restart-sentinel.ts | 2 +- src/infra/restart.ts | 10 +- src/infra/runtime-guard.ts | 4 +- src/infra/session-cost-usage.test.ts | 16 +- src/infra/session-cost-usage.ts | 8 +- src/infra/shell-env.test.ts | 8 +- src/infra/shell-env.ts | 8 +- src/infra/skills-remote.ts | 8 +- src/infra/state-migrations.fs.test.ts | 2 +- src/infra/state-migrations.ts | 42 +- src/infra/system-events.test.ts | 4 +- src/infra/system-presence.test.ts | 4 +- src/infra/system-presence.ts | 2 +- src/infra/tailscale.ts | 2 +- src/infra/tls/gateway.ts | 2 +- ...handled-rejections.fatal-detection.test.ts | 8 +- src/infra/unhandled-rejections.ts | 12 +- src/infra/update-check.ts | 2 +- src/infra/update-global.ts | 25 +- src/infra/update-runner.test.ts | 46 +- src/infra/update-runner.ts | 16 +- src/infra/update-startup.test.ts | 20 +- src/infra/update-startup.ts | 6 +- src/infra/voicewake.test.ts | 6 +- src/infra/voicewake.ts | 2 +- src/infra/warnings.ts | 2 +- src/infra/widearea-dns.test.ts | 22 +- src/infra/widearea-dns.ts | 50 +- src/line/accounts.test.ts | 20 +- src/line/accounts.ts | 8 +- src/line/bot-handlers.ts | 4 +- src/line/bot-message-context.test.ts | 6 +- src/line/bot-message-context.ts | 6 +- src/line/bot.ts | 4 +- src/line/monitor.ts | 4 +- src/line/probe.test.ts | 4 +- src/link-understanding/apply.ts | 4 +- src/link-understanding/runner.ts | 4 +- src/logger.test.ts | 6 +- src/logging/config.ts | 4 +- src/logging/console-capture.test.ts | 2 +- src/logging/console.ts | 6 +- src/logging/logger.ts | 14 +- src/logging/redact.ts | 6 +- src/macos/gateway-daemon.ts | 16 +- src/macos/relay-smoke.test.ts | 4 +- src/macos/relay-smoke.ts | 2 +- src/macos/relay.ts | 17 +- src/markdown/frontmatter.test.ts | 16 +- src/media-understanding/apply.test.ts | 64 +- src/media-understanding/apply.ts | 6 +- src/media-understanding/attachments.ts | 2 +- .../providers/deepgram/audio.live.test.ts | 2 +- src/media-understanding/providers/image.ts | 4 +- src/media-understanding/resolve.test.ts | 14 +- src/media-understanding/resolve.ts | 14 +- .../runner.auto-audio.test.ts | 10 +- .../runner.deepgram.test.ts | 6 +- src/media-understanding/runner.ts | 20 +- .../runner.vision-skip.test.ts | 4 +- src/media-understanding/types.ts | 2 +- src/media/host.ts | 2 +- src/media/image-ops.ts | 6 +- src/media/input-files.ts | 2 +- src/media/store.header-ext.test.ts | 2 +- src/media/store.redirect.test.ts | 2 +- src/media/store.test.ts | 10 +- src/memory/batch-gemini.ts | 4 +- src/memory/batch-openai.ts | 2 +- src/memory/embeddings-gemini.ts | 2 +- src/memory/embeddings.ts | 6 +- src/memory/index.test.ts | 2 +- src/memory/manager.async-search.test.ts | 2 +- src/memory/manager.atomic-reindex.test.ts | 2 +- src/memory/manager.batch.test.ts | 2 +- src/memory/manager.embedding-batches.test.ts | 2 +- .../manager.sync-errors-do-not-crash.test.ts | 2 +- src/memory/manager.ts | 8 +- src/memory/manager.vector-dedupe.test.ts | 2 +- src/memory/search-manager.ts | 4 +- src/node-host/runner.ts | 12 +- src/pairing/pairing-messages.test.ts | 12 +- src/pairing/pairing-messages.ts | 4 +- src/pairing/pairing-store.test.ts | 10 +- src/plugin-sdk/index.ts | 8 +- src/plugins/bundled-dir.ts | 2 +- src/plugins/cli.test.ts | 2 +- src/plugins/cli.ts | 8 +- src/plugins/commands.ts | 10 +- src/plugins/config-schema.ts | 4 +- src/plugins/config-state.ts | 4 +- src/plugins/discovery.test.ts | 48 +- src/plugins/discovery.ts | 30 +- src/plugins/enable.ts | 10 +- src/plugins/install.test.ts | 30 +- src/plugins/install.ts | 20 +- src/plugins/installs.ts | 6 +- src/plugins/loader.test.ts | 76 +- src/plugins/loader.ts | 34 +- src/plugins/manifest-registry.ts | 12 +- src/plugins/manifest.ts | 23 +- src/plugins/providers.ts | 4 +- src/plugins/registry.ts | 66 +- src/plugins/runtime.ts | 2 +- src/plugins/services.ts | 4 +- src/plugins/slots.test.ts | 10 +- src/plugins/slots.ts | 6 +- src/plugins/status.ts | 4 +- src/plugins/tools.optional.test.ts | 4 +- src/plugins/tools.ts | 8 +- src/plugins/types.ts | 86 +-- src/plugins/update.ts | 16 +- src/postinstall-patcher.test.ts | 2 +- src/process/exec.test.ts | 16 +- src/providers/github-copilot-token.test.ts | 4 +- src/providers/qwen-portal-oauth.ts | 2 +- src/routing/bindings.ts | 10 +- src/routing/resolve-route.test.ts | 30 +- src/routing/resolve-route.ts | 8 +- src/scripts/canvas-a2ui-copy.test.ts | 4 +- src/security/audit-extra.ts | 38 +- src/security/audit.test.ts | 192 ++--- src/security/audit.ts | 28 +- src/security/fix.test.ts | 40 +- src/security/fix.ts | 14 +- src/sessions/send-policy.test.ts | 10 +- src/sessions/send-policy.ts | 4 +- src/signal/accounts.ts | 16 +- ...onitor.event-handler.sender-prefix.test.ts | 2 +- ...-only-senders-uuid-allowlist-entry.test.ts | 2 +- ...ends-tool-summaries-responseprefix.test.ts | 8 +- src/signal/monitor.ts | 4 +- src/signal/monitor/event-handler.types.ts | 4 +- src/signal/reaction-level.ts | 4 +- src/slack/accounts.ts | 16 +- src/slack/channel-migration.ts | 6 +- src/slack/monitor.test-helpers.ts | 2 +- src/slack/monitor.test.ts | 12 +- ...onitor.threading.missing-thread-ts.test.ts | 2 +- ...ends-tool-summaries-responseprefix.test.ts | 8 +- src/slack/monitor/commands.ts | 7 +- src/slack/monitor/context.test.ts | 6 +- src/slack/monitor/context.ts | 6 +- .../prepare.inbound-contract.test.ts | 10 +- .../prepare.sender-prefix.test.ts | 4 +- .../monitor/slash.command-arg-menus.test.ts | 15 +- src/slack/monitor/slash.policy.test.ts | 7 +- src/slack/monitor/slash.ts | 129 ++-- src/slack/monitor/types.ts | 4 +- src/slack/threading-tool-context.test.ts | 16 +- src/slack/threading-tool-context.ts | 4 +- src/telegram/accounts.test.ts | 10 +- src/telegram/accounts.ts | 18 +- .../bot-message-context.dm-threads.test.ts | 4 +- .../bot-message-context.sender-prefix.test.ts | 6 +- src/telegram/bot-message-context.ts | 10 +- .../bot-native-commands.plugin-auth.test.ts | 4 +- src/telegram/bot-native-commands.ts | 6 +- ...patterns-match-without-botusername.test.ts | 14 +- ...topic-skill-filters-system-prompts.test.ts | 8 +- ...-all-group-messages-grouppolicy-is.test.ts | 20 +- ...e-callback-query-updates-by-update.test.ts | 8 +- ...gram-bot.installs-grammy-throttler.test.ts | 14 +- ...lowfrom-entries-case-insensitively.test.ts | 14 +- ...-case-insensitively-grouppolicy-is.test.ts | 16 +- ...-dms-by-telegram-accountid-binding.test.ts | 12 +- ...ies-without-native-reply-threading.test.ts | 20 +- ...s-media-file-path-no-file-download.test.ts | 26 +- ...udes-location-text-ctx-fields-pins.test.ts | 4 +- src/telegram/bot.test.ts | 126 ++-- src/telegram/bot.ts | 4 +- src/telegram/bot/helpers.test.ts | 10 +- src/telegram/draft-chunking.test.ts | 6 +- src/telegram/draft-chunking.ts | 4 +- src/telegram/fetch.test.ts | 4 +- src/telegram/group-migration.ts | 6 +- src/telegram/inline-buttons.ts | 6 +- src/telegram/monitor.ts | 6 +- src/telegram/network-config.test.ts | 10 +- src/telegram/network-config.ts | 4 +- src/telegram/pairing-store.test.ts | 10 +- src/telegram/pairing-store.ts | 4 +- src/telegram/reaction-level.test.ts | 16 +- src/telegram/reaction-level.ts | 4 +- src/telegram/sticker-cache.test.ts | 4 +- src/telegram/sticker-cache.ts | 4 +- src/telegram/token.test.ts | 14 +- src/telegram/token.ts | 4 +- src/telegram/update-offset-store.test.ts | 10 +- src/telegram/webhook.ts | 4 +- src/terminal/links.ts | 2 +- src/test-helpers/workspace.ts | 2 +- src/tts/tts.test.ts | 24 +- src/tts/tts.ts | 18 +- src/tui/commands.ts | 4 +- src/tui/gateway-chat.ts | 6 +- src/tui/tui.ts | 2 +- src/utils.test.ts | 18 +- src/utils.ts | 12 +- src/utils/usage-format.test.ts | 4 +- src/utils/usage-format.ts | 4 +- src/version.ts | 8 +- src/web/accounts.ts | 20 +- src/web/accounts.whatsapp-auth.test.ts | 12 +- src/web/active-listener.ts | 2 +- src/web/auth-store.ts | 2 +- ...asts-sequentially-configured-order.test.ts | 12 +- ...wn-broadcast-agent-ids-agents-list.test.ts | 8 +- .../auto-reply.partial-reply-gating.test.ts | 14 +- .../auto-reply.typing-controller-idle.test.ts | 8 +- ...compresses-common-formats-jpeg-cap.test.ts | 4 +- ...y.falls-back-text-media-send-fails.test.ts | 4 +- ...efixes-body-same-phone-marker-from.test.ts | 4 +- ....reconnects-after-connection-close.test.ts | 8 +- ...oup-chats-injects-history-replying.test.ts | 8 +- ...mmaries-immediately-responseprefix.test.ts | 6 +- ...-activation-silent-token-preserves.test.ts | 16 +- ...gent-mention-patterns-group-gating.test.ts | 12 +- src/web/auto-reply/mentions.test.ts | 6 +- src/web/auto-reply/monitor.ts | 2 +- .../auto-reply/monitor/group-gating.test.ts | 2 +- .../auto-reply/monitor/message-line.test.ts | 2 +- src/web/auto-reply/monitor/process-message.ts | 2 +- src/web/auto-reply/session-snapshot.test.ts | 2 +- src/web/inbound.media.test.ts | 2 +- src/web/login.ts | 2 +- src/web/media.test.ts | 2 +- ...ssages-from-senders-allowfrom-list.test.ts | 2 +- ...unauthorized-senders-not-allowfrom.test.ts | 2 +- ...captures-media-path-image-messages.test.ts | 4 +- ...tor-inbox.streams-inbound-messages.test.ts | 2 +- src/web/qr-image.test.ts | 2 +- src/web/reconnect.test.ts | 4 +- src/web/reconnect.ts | 6 +- src/web/session.test.ts | 6 +- src/web/session.ts | 4 +- src/web/test-helpers.ts | 8 +- src/wizard/onboarding.finalize.ts | 53 +- src/wizard/onboarding.gateway-config.ts | 12 +- src/wizard/onboarding.test.ts | 6 +- src/wizard/onboarding.ts | 28 +- test/gateway.multi.e2e.test.ts | 36 +- test/helpers/temp-home.ts | 10 +- test/media-understanding.auto.e2e.test.ts | 20 +- test/provider-timeout.e2e.test.ts | 54 +- test/setup.ts | 8 +- test/test-env.ts | 46 +- ui/index.html | 4 +- ui/package.json | 2 +- ui/src/styles/base.css | 2 +- ui/src/ui/app-channels.ts | 26 +- ui/src/ui/app-chat.ts | 10 +- ui/src/ui/app-gateway.ts | 20 +- ui/src/ui/app-polling.ts | 8 +- ui/src/ui/app-render.ts | 6 +- ui/src/ui/app-scroll.ts | 2 +- ui/src/ui/app-settings.ts | 48 +- ui/src/ui/app.ts | 6 +- ui/src/ui/assistant-identity.ts | 8 +- ui/src/ui/chat-markdown.browser.test.ts | 14 +- ui/src/ui/controllers/chat.ts | 2 +- ui/src/ui/controllers/config.test.ts | 4 +- ui/src/ui/device-auth.ts | 2 +- ui/src/ui/device-identity.ts | 2 +- ui/src/ui/focus-mode.browser.test.ts | 14 +- ui/src/ui/navigation.browser.test.ts | 30 +- ui/src/ui/navigation.test.ts | 10 +- ui/src/ui/navigation.ts | 2 +- ui/src/ui/storage.ts | 2 +- ui/src/ui/views/chat.test.ts | 2 +- ui/src/ui/views/debug.ts | 2 +- ui/src/ui/views/overview.ts | 16 +- ui/vite.config.ts | 2 +- vitest.config.ts | 4 +- vitest.e2e.config.ts | 2 +- vitest.live.config.ts | 2 +- 2357 files changed, 16688 insertions(+), 16788 deletions(-) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/CameraHudState.kt (85%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/DeviceNames.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/LocationMode.kt (92%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/MainActivity.kt (96%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/MainViewModel.kt (94%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/NodeApp.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/NodeForegroundService.kt (94%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/NodeRuntime.kt (89%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/PermissionRequester.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ScreenCaptureRequester.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/SecurePrefs.kt (79%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/SessionKey.kt (92%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/VoiceWakeMode.kt (91%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/WakeWords.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/chat/ChatController.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/chat/ChatModels.kt (96%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/BonjourEscapes.kt (96%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/DeviceAuthStore.kt (90%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/DeviceIdentityStore.kt (93%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/GatewayDiscovery.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/GatewayEndpoint.kt (94%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/GatewayProtocol.kt (52%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/GatewaySession.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/gateway/GatewayTls.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/CameraCaptureManager.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/CanvasController.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/JpegSizeLimiter.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/LocationCaptureManager.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/ScreenRecordManager.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/node/SmsManager.kt (98%) rename apps/android/app/src/main/java/{bot/molt/android/protocol/ClawdbotCanvasA2UIAction.kt => ai/openclaw/android/protocol/OpenClawCanvasA2UIAction.kt} (89%) rename apps/android/app/src/main/java/{bot/molt/android/protocol/ClawdbotProtocolConstants.kt => ai/openclaw/android/protocol/OpenClawProtocolConstants.kt} (69%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/tools/ToolDisplay.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/CameraHudOverlay.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/ChatSheet.kt (53%) rename apps/android/app/src/main/java/{bot/molt/android/ui/ClawdbotTheme.kt => ai/openclaw/android/ui/OpenClawTheme.kt} (92%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/RootScreen.kt (93%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/SettingsSheet.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/StatusPill.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/TalkOrbOverlay.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatComposer.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatMarkdown.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatMessageListCard.kt (95%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatMessageViews.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatSessionsDialog.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/ChatSheetContent.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/ui/chat/SessionFilters.kt (94%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/voice/StreamingMediaDataSource.kt (98%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/voice/TalkDirectiveParser.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/voice/TalkModeManager.kt (99%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/voice/VoiceWakeCommandExtractor.kt (97%) rename apps/android/app/src/main/java/{bot/molt => ai/openclaw}/android/voice/VoiceWakeManager.kt (99%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/NodeForegroundServiceTest.kt (98%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/WakeWordsTest.kt (67%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/gateway/BonjourEscapesTest.kt (78%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/node/CanvasControllerSnapshotParamsTest.kt (97%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/node/JpegSizeLimiterTest.kt (97%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/node/SmsManagerTest.kt (98%) rename apps/android/app/src/test/java/{bot/molt/android/protocol/ClawdbotCanvasA2UIActionTest.kt => ai/openclaw/android/protocol/OpenClawCanvasA2UIActionTest.kt} (64%) create mode 100644 apps/android/app/src/test/java/ai/openclaw/android/protocol/OpenClawProtocolConstantsTest.kt rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/ui/chat/SessionFiltersTest.kt (93%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/voice/TalkDirectiveParserTest.kt (97%) rename apps/android/app/src/test/java/{bot/molt => ai/openclaw}/android/voice/VoiceWakeCommandExtractorTest.kt (76%) delete mode 100644 apps/android/app/src/test/java/bot/molt/android/protocol/ClawdbotProtocolConstantsTest.kt rename apps/ios/Sources/{ClawdbotApp.swift => OpenClawApp.swift} (97%) rename apps/macos/Icon.icon/Assets/{clawdbot-mac.png => openclaw-mac.png} (100%) delete mode 100644 apps/macos/Sources/Moltbot/ClawdbotPaths.swift delete mode 100644 apps/macos/Sources/Moltbot/Constants.swift delete mode 100644 apps/macos/Sources/MoltbotMacCLI/TypeAliases.swift rename apps/macos/Sources/{Moltbot => OpenClaw}/AboutSettings.swift (91%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AgeFormatting.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AgentEventStore.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AgentEventsWindow.swift (93%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AgentWorkspace.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AnthropicAuthControls.swift (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AnthropicOAuth.swift (94%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AnthropicOAuthCodeState.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AnyCodable+Helpers.swift (64%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AppState.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/AudioInputDeviceObserver.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CLIInstallPrompter.swift (91%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CLIInstaller.swift (91%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CameraCaptureService.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasA2UIActionMessageHandler.swift (87%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasChromeContainerView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasFileWatcher.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasManager.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasScheme.swift (94%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasSchemeHandler.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindow.swift (88%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindowController+Helpers.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindowController+Navigation.swift (90%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindowController+Testing.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindowController+Window.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CanvasWindowController.swift (90%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelConfigForm.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsSettings+ChannelSections.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsSettings+ChannelState.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsSettings+Helpers.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsSettings+View.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsSettings.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsStore+Config.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsStore+Lifecycle.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ChannelsStore.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CommandResolver.swift (84%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConfigFileWatcher.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConfigSchemaSupport.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConfigSettings.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConfigStore.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConnectionModeCoordinator.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ConnectionModeResolver.swift (96%) create mode 100644 apps/macos/Sources/OpenClaw/Constants.swift rename apps/macos/Sources/{Moltbot => OpenClaw}/ContextMenuCardView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ContextUsageBar.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ControlChannel.swift (93%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CostUsageMenuView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CritterIconRenderer.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CritterStatusLabel+Behavior.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CritterStatusLabel.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronJobEditor+Helpers.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronJobEditor+Testing.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronJobEditor.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronJobsStore.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronModels.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings+Actions.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings+Helpers.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings+Layout.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings+Rows.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings+Testing.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/CronSettings.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DebugActions.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DebugSettings.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DeepLinks.swift (94%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DeviceModelCatalog.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DevicePairingApprovalPrompter.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DiagnosticsFileLog.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/DockIconManager.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ExecApprovals.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ExecApprovalsGatewayPrompter.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ExecApprovalsSocket.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/FileHandle+SafeRead.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayAutostartPolicy.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayConnection.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayConnectivityCoordinator.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayDiscoveryHelpers.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayDiscoveryMenu.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayDiscoveryPreferences.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayEndpointStore.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayEnvironment.swift (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayLaunchAgentManager.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayProcessManager.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GatewayRemoteConfig.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/GeneralSettings.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/HealthStore.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/HeartbeatStore.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/HoverHUD.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/IconState.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/InstancesSettings.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/InstancesStore.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/LaunchAgentManager.swift (77%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Launchctl.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/LaunchdManager.swift (87%) rename apps/macos/Sources/{Moltbot => OpenClaw}/LogLocator.swift (68%) rename apps/macos/Sources/{Moltbot/Logging/ClawdbotLogging.swift => OpenClaw/Logging/OpenClawLogging.swift} (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuBar.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuContentView.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuContextCardInjector.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuHighlightedHostView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuHostedItem.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuSessionsHeaderView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuSessionsInjector.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MenuUsageHeaderView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/MicLevelMonitor.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ModelCatalogLoader.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NSAttributedString+VoiceWake.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeMode/MacNodeLocationService.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeMode/MacNodeModeCoordinator.swift (77%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeMode/MacNodeRuntime.swift (88%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeMode/MacNodeRuntimeMainActorServices.swift (93%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeMode/MacNodeScreenCommands.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodePairingApprovalPrompter.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodeServiceManager.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodesMenu.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NodesStore.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NotificationManager.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/NotifyOverlay.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Onboarding.swift (93%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Actions.swift (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Chat.swift (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Layout.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Monitoring.swift (94%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Pages.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Testing.swift (92%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Wizard.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingView+Workspace.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingWidgets.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/OnboardingWizard.swift (97%) rename apps/macos/Sources/{Moltbot/ClawdbotConfigFile.swift => OpenClaw/OpenClawConfigFile.swift} (97%) create mode 100644 apps/macos/Sources/OpenClaw/OpenClawPaths.swift rename apps/macos/Sources/{Moltbot => OpenClaw}/PeekabooBridgeHostCoordinator.swift (79%) rename apps/macos/Sources/{Moltbot => OpenClaw}/PermissionManager.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/PermissionsSettings.swift (90%) rename apps/macos/Sources/{Moltbot => OpenClaw}/PointingHandCursor.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/PortGuardian.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/PresenceReporter.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Process+PipeRead.swift (100%) rename apps/macos/Sources/{Moltbot/ProcessInfo+Clawdbot.swift => OpenClaw/ProcessInfo+OpenClaw.swift} (87%) rename apps/macos/Sources/{Moltbot => OpenClaw}/RemotePortTunnel.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/RemoteTunnelManager.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Resources/DeviceModels/LICENSE.apple-device-identifiers.txt (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Resources/DeviceModels/NOTICE.md (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Resources/DeviceModels/ios-device-identifiers.json (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Resources/DeviceModels/mac-device-identifiers.json (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/Resources/Info.plist (62%) rename apps/macos/Sources/{Moltbot/Resources/Moltbot.icns => OpenClaw/Resources/OpenClaw.icns} (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/RuntimeLocator.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ScreenRecordService.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ScreenshotSize.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SessionActions.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SessionData.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SessionMenuLabelView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SessionMenuPreviewView.swift (94%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SessionsSettings.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SettingsComponents.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SettingsRootView.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SettingsWindowOpener.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/ShellExecutor.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SkillsModels.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SkillsSettings.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SoundEffects.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/StatusPill.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/String+NonEmpty.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/SystemRunSettingsView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TailscaleIntegrationSection.swift (97%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TailscaleService.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkAudioPlayer.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkModeController.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkModeRuntime.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkModeTypes.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkOverlay.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TalkOverlayView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/TerminationSignalWatcher.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/UsageCostData.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/UsageData.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/UsageMenuLabelView.swift (100%) create mode 100644 apps/macos/Sources/OpenClaw/UserDefaultsMigration.swift rename apps/macos/Sources/{Moltbot => OpenClaw}/ViewMetrics.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VisualEffectView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoicePushToTalk.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceSessionCoordinator.swift (98%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeChime.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeForwarder.swift (96%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeGlobalSettingsSync.swift (95%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeHelpers.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlay.swift (90%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlayController+Session.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlayController+Testing.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlayController+Window.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlayTextViews.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeOverlayView.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeRuntime.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeSettings.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeTestCard.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeTester.swift (99%) rename apps/macos/Sources/{Moltbot => OpenClaw}/VoiceWakeTextUtils.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/WebChatManager.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/WebChatSwiftUI.swift (91%) rename apps/macos/Sources/{Moltbot => OpenClaw}/WindowPlacement.swift (100%) rename apps/macos/Sources/{Moltbot => OpenClaw}/WorkActivityStore.swift (95%) rename apps/macos/Sources/{MoltbotDiscovery => OpenClawDiscovery}/GatewayDiscoveryModel.swift (96%) rename apps/macos/Sources/{MoltbotDiscovery => OpenClawDiscovery}/WideAreaGatewayDiscovery.swift (97%) rename apps/macos/Sources/{MoltbotIPC => OpenClawIPC}/IPC.swift (98%) rename apps/macos/Sources/{MoltbotMacCLI => OpenClawMacCLI}/ConnectCommand.swift (95%) rename apps/macos/Sources/{MoltbotMacCLI => OpenClawMacCLI}/DiscoverCommand.swift (97%) rename apps/macos/Sources/{MoltbotMacCLI => OpenClawMacCLI}/EntryPoint.swift (71%) rename apps/macos/Sources/{MoltbotMacCLI => OpenClawMacCLI}/GatewayConfig.swift (86%) create mode 100644 apps/macos/Sources/OpenClawMacCLI/TypeAliases.swift rename apps/macos/Sources/{MoltbotMacCLI => OpenClawMacCLI}/WizardCommand.swift (97%) rename apps/macos/Sources/{MoltbotProtocol => OpenClawProtocol}/GatewayModels.swift (100%) delete mode 100644 apps/macos/Tests/MoltbotIPCTests/ClawdbotConfigFileTests.swift rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AgentEventStoreTests.swift (83%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AgentWorkspaceTests.swift (90%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AnthropicAuthControlsSmokeTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AnthropicAuthResolverTests.swift (89%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AnthropicOAuthCodeStateTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/AnyCodableEncodingTests.swift (83%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CLIInstallerTests.swift (88%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CameraCaptureServiceTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CameraIPCTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CanvasFileWatcherTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CanvasIPCTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CanvasWindowSmokeTests.swift (89%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ChannelsSettingsSmokeTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CommandResolverTests.swift (79%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ConfigStoreTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CoverageDumpTests.swift (100%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CritterIconRendererTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CronJobEditorSmokeTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/CronModelsTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/DeviceModelCatalogTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ExecAllowlistTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ExecApprovalHelpersTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ExecApprovalsGatewayPrompterTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/FileHandleLegacyAPIGuardTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/FileHandleSafeReadTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayAgentChannelTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayAutostartPolicyTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayChannelConfigureTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayChannelConnectTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayChannelRequestTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayChannelShutdownTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayConnectionControlTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayDiscoveryModelTests.swift (93%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayEndpointStoreTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayEnvironmentTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayFrameDecodeTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayLaunchAgentManagerTests.swift (72%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/GatewayProcessManagerTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/HealthDecodeTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/HealthStoreStateTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/HoverHUDControllerTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/InstancesSettingsSmokeTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/InstancesStoreTests.swift (75%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/LogLocatorTests.swift (72%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/LowCoverageHelperTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/LowCoverageViewSmokeTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/MacGatewayChatTransportMappingTests.swift (83%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/MacNodeRuntimeTests.swift (81%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/MasterDiscoveryMenuSmokeTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/MenuContentSmokeTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/MenuSessionsInjectorTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ModelCatalogLoaderTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/NodeManagerPathsTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/NodePairingApprovalPrompterTests.swift (89%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/NodePairingReconcilePolicyTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/OnboardingCoverageTests.swift (87%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/OnboardingViewSmokeTests.swift (94%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/OnboardingWizardStepViewTests.swift (92%) create mode 100644 apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift rename apps/macos/Tests/{MoltbotIPCTests/ClawdbotOAuthStoreTests.swift => OpenClawIPCTests/OpenClawOAuthStoreTests.swift} (69%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/PermissionManagerLocationTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/PermissionManagerTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/Placeholder.swift (100%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/RemotePortTunnelTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/RuntimeLocatorTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/ScreenshotSizeTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/SemverTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/SessionDataTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/SessionMenuPreviewTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/SettingsViewSmokeTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/SkillsSettingsSmokeTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/TailscaleIntegrationSectionTests.swift (95%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/TalkAudioPlayerTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/TestIsolation.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/UtilitiesTests.swift (91%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoicePushToTalkHotkeyTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoicePushToTalkTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeForwarderTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeGlobalSettingsSyncTests.swift (85%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeHelpersTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeOverlayControllerTests.swift (98%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeOverlayTests.swift (96%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeOverlayViewSmokeTests.swift (97%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeRuntimeTests.swift (83%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/VoiceWakeTesterTests.swift (100%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WebChatMainSessionKeyTests.swift (92%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WebChatManagerTests.swift (91%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WebChatSwiftUISmokeTests.swift (75%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WideAreaGatewayDiscoveryTests.swift (71%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WindowPlacementTests.swift (99%) rename apps/macos/Tests/{MoltbotIPCTests => OpenClawIPCTests}/WorkActivityStoreTests.swift (96%) delete mode 100644 apps/shared/MoltbotKit/Sources/MoltbotKit/BonjourTypes.swift delete mode 100644 apps/shared/MoltbotKit/Sources/MoltbotKit/LocationSettings.swift rename apps/shared/{MoltbotKit => OpenClawKit}/Package.swift (66%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/AssistantTextParser.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatComposer.swift (93%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatMarkdownPreprocessor.swift (92%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatMarkdownRenderer.swift (97%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatMessageViews.swift (93%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatModels.swift (82%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatPayloadDecoding.swift (93%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatSessions.swift (71%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatSheets.swift (97%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatTheme.swift (94%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatTransport.swift (53%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatView.swift (95%) rename apps/shared/{MoltbotKit/Sources/MoltbotChatUI => OpenClawKit/Sources/OpenClawChatUI}/ChatViewModel.swift (89%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/AnyCodable.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/AsyncTimeout.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/AudioStreamingProtocols.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/BonjourEscapes.swift (100%) create mode 100644 apps/shared/OpenClawKit/Sources/OpenClawKit/BonjourTypes.swift rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/BridgeFrames.swift (98%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CameraCommands.swift (57%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CanvasA2UIAction.swift (94%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CanvasA2UICommands.swift (69%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CanvasA2UIJSONL.swift (98%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CanvasCommandParams.swift (70%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/CanvasCommands.swift (75%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/Capabilities.swift (63%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/DeepLinks.swift (94%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/DeviceAuthStore.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/DeviceIdentity.swift (88%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/ElevenLabsKitShim.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayChannel.swift (99%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayEndpointID.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayErrors.swift (98%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayNodeSession.swift (98%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayPayloadDecoding.swift (88%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayPush.swift (94%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/GatewayTLSPinning.swift (89%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/InstanceIdentity.swift (85%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/JPEGTranscoder.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/LocationCommands.swift (76%) create mode 100644 apps/shared/OpenClawKit/Sources/OpenClawKit/LocationSettings.swift rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/NodeError.swift (73%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit/ClawdbotKitResources.swift => OpenClawKit/Sources/OpenClawKit/OpenClawKitResources.swift} (95%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/Resources/CanvasScaffold/scaffold.html (88%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/Resources/tool-display.json (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/ScreenCommands.swift (80%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/StoragePaths.swift (80%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/SystemCommands.swift (74%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/TalkDirective.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/TalkHistoryTimestamp.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/TalkPromptBuilder.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/TalkSystemSpeechSynthesizer.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotKit => OpenClawKit/Sources/OpenClawKit}/ToolDisplay.swift (98%) rename apps/shared/{MoltbotKit/Sources/MoltbotProtocol => OpenClawKit/Sources/OpenClawProtocol}/AnyCodable.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotProtocol => OpenClawKit/Sources/OpenClawProtocol}/GatewayModels.swift (100%) rename apps/shared/{MoltbotKit/Sources/MoltbotProtocol => OpenClawKit/Sources/OpenClawProtocol}/WizardHelpers.swift (100%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/AssistantTextParserTests.swift (97%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/BonjourEscapesTests.swift (87%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/CanvasA2UIActionTests.swift (53%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/CanvasA2UITests.swift (61%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/CanvasSnapshotFormatTests.swift (83%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/ChatMarkdownPreprocessorTests.swift (94%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/ChatThemeTests.swift (76%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/ChatViewModelTests.swift (84%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/ElevenLabsTTSValidationTests.swift (96%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/GatewayNodeSessionTests.swift (97%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/JPEGTranscoderTests.swift (99%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/TalkDirectiveTests.swift (98%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/TalkHistoryTimestampTests.swift (95%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/TalkPromptBuilderTests.swift (95%) rename apps/shared/{MoltbotKit/Tests/MoltbotKitTests => OpenClawKit/Tests/OpenClawKitTests}/ToolDisplayRegistryTests.swift (75%) rename apps/shared/{MoltbotKit => OpenClawKit}/Tools/CanvasA2UI/bootstrap.js (91%) rename apps/shared/{MoltbotKit => OpenClawKit}/Tools/CanvasA2UI/rolldown.config.mjs (96%) create mode 100644 docs/assets/openclaw-logo-text.png rename docs/start/{clawd.md => openclaw.md} (64%) rename docs/{whatsapp-clawd.jpg => whatsapp-openclaw.jpg} (100%) rename extensions/bluebubbles/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/copilot-proxy/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/diagnostics-otel/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/discord/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/google-antigravity-auth/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/google-gemini-cli-auth/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/googlechat/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/imessage/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/line/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/llm-task/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/lobster/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/matrix/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/mattermost/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/memory-core/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/memory-lancedb/{clawdbot.plugin.json => openclaw.plugin.json} (96%) rename extensions/msteams/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/nextcloud-talk/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/nostr/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/open-prose/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/qwen-portal-auth/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/signal/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/slack/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/telegram/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/tlon/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/twitch/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/voice-call/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/whatsapp/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/zalo/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename extensions/zalouser/{clawdbot.plugin.json => openclaw.plugin.json} (100%) rename moltbot.mjs => openclaw.mjs (100%) create mode 100644 packages/clawdbot/index.js create mode 100644 packages/clawdbot/scripts/postinstall.js create mode 100644 packages/moltbot/index.js create mode 100644 packages/moltbot/package.json create mode 100644 packages/moltbot/scripts/postinstall.js rename scripts/systemd/{clawdbot-auth-monitor.service => openclaw-auth-monitor.service} (59%) rename scripts/systemd/{clawdbot-auth-monitor.timer => openclaw-auth-monitor.timer} (64%) rename src/agents/{clawdbot-gateway-tool.test.ts => openclaw-gateway-tool.test.ts} (82%) rename src/agents/{clawdbot-tools.agents.test.ts => openclaw-tools.agents.test.ts} (94%) rename src/agents/{clawdbot-tools.camera.test.ts => openclaw-tools.camera.test.ts} (91%) rename src/agents/{clawdbot-tools.session-status.test.ts => openclaw-tools.session-status.test.ts} (92%) rename src/agents/{clawdbot-tools.sessions.test.ts => openclaw-tools.sessions.test.ts} (96%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-allows-cross-agent-spawning-configured.test.ts => openclaw-tools.subagents.sessions-spawn-allows-cross-agent-spawning-configured.test.ts} (95%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-announces-agent-wait-lifecycle-events.test.ts => openclaw-tools.subagents.sessions-spawn-announces-agent-wait-lifecycle-events.test.ts} (96%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-applies-model-child-session.test.ts => openclaw-tools.subagents.sessions-spawn-applies-model-child-session.test.ts} (95%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-normalizes-allowlisted-agent-ids.test.ts => openclaw-tools.subagents.sessions-spawn-normalizes-allowlisted-agent-ids.test.ts} (97%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-prefers-per-agent-subagent-model.test.ts => openclaw-tools.subagents.sessions-spawn-prefers-per-agent-subagent-model.test.ts} (95%) rename src/agents/{clawdbot-tools.subagents.sessions-spawn-resolves-main-announce-target-from.test.ts => openclaw-tools.subagents.sessions-spawn-resolves-main-announce-target-from.test.ts} (96%) rename src/agents/{moltbot-tools.ts => openclaw-tools.ts} (97%) rename src/agents/{pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-b.test.ts => pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-b.test.ts} (86%) rename src/agents/{pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-d.test.ts => pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-d.test.ts} (78%) rename src/agents/{pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping-f.test.ts => pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping-f.test.ts} (85%) rename src/agents/{pi-tools.create-clawdbot-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.ts => pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.ts} (95%) rename src/config/{types.clawdbot.ts => types.openclaw.ts} (95%) delete mode 100644 src/daemon/legacy.ts rename src/infra/{moltbot-root.ts => openclaw-root.ts} (94%) diff --git a/AGENTS.md b/AGENTS.md index 44b0149fda..db5d68eb55 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,5 @@ # Repository Guidelines -- Repo: https://github.com/moltbot/moltbot +- Repo: https://github.com/openclaw/openclaw - GitHub issues/comments/PR comments: use literal multiline strings or `-F - <<'EOF'` (or $'...') for real newlines; never embed "\\n". ## Project Structure & Module Organization @@ -7,8 +7,8 @@ - Tests: colocated `*.test.ts`. - Docs: `docs/` (images, queue, Pi config). Built output lives in `dist/`. - Plugins/extensions: live under `extensions/*` (workspace packages). Keep plugin-only deps in the extension `package.json`; do not add them to the root `package.json` unless core uses them. -- Plugins: install runs `npm install --omit=dev` in plugin dir; runtime deps must live in `dependencies`. Avoid `workspace:*` in `dependencies` (npm install breaks); put `moltbot` in `devDependencies` or `peerDependencies` instead (runtime resolves `clawdbot/plugin-sdk` via jiti alias). -- Installers served from `https://molt.bot/*`: live in the sibling repo `../molt.bot` (`public/install.sh`, `public/install-cli.sh`, `public/install.ps1`). +- Plugins: install runs `npm install --omit=dev` in plugin dir; runtime deps must live in `dependencies`. Avoid `workspace:*` in `dependencies` (npm install breaks); put `openclaw` in `devDependencies` or `peerDependencies` instead (runtime resolves `clawdbot/plugin-sdk` via jiti alias). +- Installers served from `https://openclaw.ai/*`: live in the sibling repo `../openclaw.ai` (`public/install.sh`, `public/install-cli.sh`, `public/install.ps1`). - Messaging channels: always consider **all** built-in + extension channels when refactoring shared logic (routing, allowlists, pairing, command gating, onboarding, docs). - Core channel docs: `docs/channels/` - Core channel code: `src/telegram`, `src/discord`, `src/slack`, `src/signal`, `src/imessage`, `src/web` (WhatsApp web), `src/channels`, `src/routing` @@ -16,24 +16,24 @@ - When adding channels/extensions/apps/docs, review `.github/labeler.yml` for label coverage. ## Docs Linking (Mintlify) -- Docs are hosted on Mintlify (docs.molt.bot). +- Docs are hosted on Mintlify (docs.openclaw.ai). - Internal doc links in `docs/**/*.md`: root-relative, no `.md`/`.mdx` (example: `[Config](/configuration)`). - Section cross-references: use anchors on root-relative paths (example: `[Hooks](/configuration#hooks)`). - Doc headings and anchors: avoid em dashes and apostrophes in headings because they break Mintlify anchor links. -- When Peter asks for links, reply with full `https://docs.molt.bot/...` URLs (not root-relative). -- When you touch docs, end the reply with the `https://docs.molt.bot/...` URLs you referenced. -- README (GitHub): keep absolute docs URLs (`https://docs.molt.bot/...`) so links work on GitHub. +- When Peter asks for links, reply with full `https://docs.openclaw.ai/...` URLs (not root-relative). +- When you touch docs, end the reply with the `https://docs.openclaw.ai/...` URLs you referenced. +- README (GitHub): keep absolute docs URLs (`https://docs.openclaw.ai/...`) so links work on GitHub. - Docs content must be generic: no personal device names/hostnames/paths; use placeholders like `user@gateway-host` and “gateway host”. ## exe.dev VM ops (general) - Access: stable path is `ssh exe.dev` then `ssh vm-name` (assume SSH key already set). - SSH flaky: use exe.dev web terminal or Shelley (web agent); keep a tmux session for long ops. -- Update: `sudo npm i -g moltbot@latest` (global install needs root on `/usr/lib/node_modules`). -- Config: use `moltbot config set ...`; ensure `gateway.mode=local` is set. +- Update: `sudo npm i -g openclaw@latest` (global install needs root on `/usr/lib/node_modules`). +- Config: use `openclaw config set ...`; ensure `gateway.mode=local` is set. - Discord: store raw token only (no `DISCORD_BOT_TOKEN=` prefix). - Restart: stop old gateway and run: - `pkill -9 -f moltbot-gateway || true; nohup moltbot gateway run --bind loopback --port 18789 --force > /tmp/moltbot-gateway.log 2>&1 &` -- Verify: `moltbot channels status --probe`, `ss -ltnp | rg 18789`, `tail -n 120 /tmp/moltbot-gateway.log`. + `pkill -9 -f openclaw-gateway || true; nohup openclaw gateway run --bind loopback --port 18789 --force > /tmp/openclaw-gateway.log 2>&1 &` +- Verify: `openclaw channels status --probe`, `ss -ltnp | rg 18789`, `tail -n 120 /tmp/openclaw-gateway.log`. ## Build, Test, and Development Commands - Runtime baseline: Node **22+** (keep Node + Bun paths working). @@ -41,7 +41,7 @@ - Pre-commit hooks: `prek install` (runs same checks as CI) - Also supported: `bun install` (keep `pnpm-lock.yaml` + Bun patching in sync when touching deps/patches). - Prefer Bun for TypeScript execution (scripts, dev, tests): `bun ` / `bunx `. -- Run CLI in dev: `pnpm moltbot ...` (bun) or `pnpm dev`. +- Run CLI in dev: `pnpm openclaw ...` (bun) or `pnpm dev`. - Node remains supported for running built output (`dist/*`) and production installs. - Mac packaging (dev): `scripts/package-mac-app.sh` defaults to current arch. Release checklist: `docs/platforms/mac/release.md`. - Type-check/build: `pnpm build` (tsc) @@ -54,7 +54,7 @@ - Add brief code comments for tricky or non-obvious logic. - Keep files concise; extract helpers instead of “V2” copies. Use existing patterns for CLI options and dependency injection via `createDefaultDeps`. - Aim to keep files under ~700 LOC; guideline only (not a hard guardrail). Split/refactor when it improves clarity or testability. -- Naming: use **Moltbot** for product/app/docs headings; use `moltbot` for CLI command, package/binary, paths, and config keys. +- Naming: use **OpenClaw** for product/app/docs headings; use `openclaw` for CLI command, package/binary, paths, and config keys. ## Release Channels (Naming) - stable: tagged releases only (e.g. `vYYYY.M.D`), npm dist-tag `latest`. @@ -66,7 +66,7 @@ - Naming: match source names with `*.test.ts`; e2e in `*.e2e.test.ts`. - Run `pnpm test` (or `pnpm test:coverage`) before pushing when you touch logic. - Do not set test workers above 16; tried already. -- Live tests (real keys): `CLAWDBOT_LIVE_TEST=1 pnpm test:live` (Moltbot-only) or `LIVE=1 pnpm test:live` (includes provider live tests). Docker: `pnpm test:docker:live-models`, `pnpm test:docker:live-gateway`. Onboarding Docker E2E: `pnpm test:docker:onboard`. +- Live tests (real keys): `CLAWDBOT_LIVE_TEST=1 pnpm test:live` (OpenClaw-only) or `LIVE=1 pnpm test:live` (includes provider live tests). Docker: `pnpm test:docker:live-models`, `pnpm test:docker:live-gateway`. Onboarding Docker E2E: `pnpm test:docker:onboard`. - Full kit + what’s covered: `docs/testing.md`. - Pure test additions/fixes generally do **not** need a changelog entry unless they alter user-facing behavior or the user asks for one. - Mobile: before using a simulator, check for connected real devices (iOS + Android) and prefer them when available. @@ -97,19 +97,19 @@ - **Landing mode:** create an integration branch from `main`, bring in PR commits (**prefer rebase** for linear history; **merge allowed** when complexity/conflicts make it safer), apply fixes, add changelog (+ thanks + PR #), run full gate **locally before committing** (`pnpm lint && pnpm build && pnpm test`), commit, merge back to `main`, then `git switch main` (never stay on a topic branch after landing). Important: contributor needs to be in git graph after this! ## Security & Configuration Tips -- Web provider stores creds at `~/.clawdbot/credentials/`; rerun `moltbot login` if logged out. +- Web provider stores creds at `~/.clawdbot/credentials/`; rerun `openclaw login` if logged out. - Pi sessions live under `~/.clawdbot/sessions/` by default; the base directory is not configurable. - Environment variables: see `~/.profile`. - Never commit or publish real phone numbers, videos, or live configuration values. Use obviously fake placeholders in docs, tests, and examples. - Release flow: always read `docs/reference/RELEASING.md` and `docs/platforms/mac/release.md` before any release work; do not ask routine questions once those docs answer them. ## Troubleshooting -- Rebrand/migration issues or legacy config/service warnings: run `moltbot doctor` (see `docs/gateway/doctor.md`). +- Rebrand/migration issues or legacy config/service warnings: run `openclaw doctor` (see `docs/gateway/doctor.md`). ## Agent-Specific Notes - Vocabulary: "makeup" = "mac app". - Never edit `node_modules` (global/Homebrew/npm/git installs too). Updates overwrite. Skill notes go in `tools.md` or `AGENTS.md`. -- Signal: "update fly" => `fly ssh console -a flawd-bot -C "bash -lc 'cd /data/clawd/moltbot && git pull --rebase origin main'"` then `fly machines restart e825232f34d058 -a flawd-bot`. +- Signal: "update fly" => `fly ssh console -a flawd-bot -C "bash -lc 'cd /data/clawd/openclaw && git pull --rebase origin main'"` then `fly machines restart e825232f34d058 -a flawd-bot`. - When working on a GitHub Issue or PR, print the full URL at the end of the task. - When answering questions, respond with high-confidence answers only: verify in code; do not guess. - Never update the Carbon dependency. @@ -117,12 +117,12 @@ - Patching dependencies (pnpm patches, overrides, or vendored changes) requires explicit approval; do not do this by default. - CLI progress: use `src/cli/progress.ts` (`osc-progress` + `@clack/prompts` spinner); don’t hand-roll spinners/bars. - Status output: keep tables + ANSI-safe wrapping (`src/terminal/table.ts`); `status --all` = read-only/pasteable, `status --deep` = probes. -- Gateway currently runs only as the menubar app; there is no separate LaunchAgent/helper label installed. Restart via the Moltbot Mac app or `scripts/restart-mac.sh`; to verify/kill use `launchctl print gui/$UID | grep moltbot` rather than assuming a fixed label. **When debugging on macOS, start/stop the gateway via the app, not ad-hoc tmux sessions; kill any temporary tunnels before handoff.** -- macOS logs: use `./scripts/clawlog.sh` to query unified logs for the Moltbot subsystem; it supports follow/tail/category filters and expects passwordless sudo for `/usr/bin/log`. +- Gateway currently runs only as the menubar app; there is no separate LaunchAgent/helper label installed. Restart via the OpenClaw Mac app or `scripts/restart-mac.sh`; to verify/kill use `launchctl print gui/$UID | grep openclaw` rather than assuming a fixed label. **When debugging on macOS, start/stop the gateway via the app, not ad-hoc tmux sessions; kill any temporary tunnels before handoff.** +- macOS logs: use `./scripts/clawlog.sh` to query unified logs for the OpenClaw subsystem; it supports follow/tail/category filters and expects passwordless sudo for `/usr/bin/log`. - If shared guardrails are available locally, review them; otherwise follow this repo's guidance. - SwiftUI state management (iOS/macOS): prefer the `Observation` framework (`@Observable`, `@Bindable`) over `ObservableObject`/`@StateObject`; don’t introduce new `ObservableObject` unless required for compatibility, and migrate existing usages when touching related code. - Connection providers: when adding a new connection, update every UI surface and docs (macOS app, web UI, mobile if applicable, onboarding/overview docs) and add matching status + configuration forms so provider lists and settings stay in sync. -- Version locations: `package.json` (CLI), `apps/android/app/build.gradle.kts` (versionName/versionCode), `apps/ios/Sources/Info.plist` + `apps/ios/Tests/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `apps/macos/Sources/Moltbot/Resources/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `docs/install/updating.md` (pinned npm version), `docs/platforms/mac/release.md` (APP_VERSION/APP_BUILD examples), Peekaboo Xcode projects/Info.plists (MARKETING_VERSION/CURRENT_PROJECT_VERSION). +- Version locations: `package.json` (CLI), `apps/android/app/build.gradle.kts` (versionName/versionCode), `apps/ios/Sources/Info.plist` + `apps/ios/Tests/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `apps/macos/Sources/OpenClaw/Resources/Info.plist` (CFBundleShortVersionString/CFBundleVersion), `docs/install/updating.md` (pinned npm version), `docs/platforms/mac/release.md` (APP_VERSION/APP_BUILD examples), Peekaboo Xcode projects/Info.plists (MARKETING_VERSION/CURRENT_PROJECT_VERSION). - **Restart apps:** “restart iOS/Android apps” means rebuild (recompile/install) and relaunch, not just kill/launch. - **Device checks:** before testing, verify connected real devices (iOS/Android) before reaching for simulators/emulators. - iOS Team ID lookup: `security find-identity -p codesigning -v` → use Apple Development (…) TEAMID. Fallback: `defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers`. @@ -149,9 +149,9 @@ - Do not rebuild the macOS app over SSH; rebuilds must be run directly on the Mac. - Never send streaming/partial replies to external messaging surfaces (WhatsApp, Telegram); only final replies should be delivered there. Streaming/tool events may still go to internal UIs/control channel. - Voice wake forwarding tips: - - Command template should stay `moltbot-mac agent --message "${text}" --thinking low`; `VoiceWakeForwarder` already shell-escapes `${text}`. Don’t add extra quotes. - - launchd PATH is minimal; ensure the app’s launch agent PATH includes standard system paths plus your pnpm bin (typically `$HOME/Library/pnpm`) so `pnpm`/`moltbot` binaries resolve when invoked via `moltbot-mac`. -- For manual `moltbot message send` messages that include `!`, use the heredoc pattern noted below to avoid the Bash tool’s escaping. + - Command template should stay `openclaw-mac agent --message "${text}" --thinking low`; `VoiceWakeForwarder` already shell-escapes `${text}`. Don’t add extra quotes. + - launchd PATH is minimal; ensure the app’s launch agent PATH includes standard system paths plus your pnpm bin (typically `$HOME/Library/pnpm`) so `pnpm`/`openclaw` binaries resolve when invoked via `openclaw-mac`. +- For manual `openclaw message send` messages that include `!`, use the heredoc pattern noted below to avoid the Bash tool’s escaping. - Release guardrails: do not change version numbers without operator’s explicit consent; always ask permission before running any npm publish/release step. ## NPM + 1Password (publish/verify) diff --git a/CHANGELOG.md b/CHANGELOG.md index a134359f54..6444466d02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,89 +1,169 @@ # Changelog -Docs: https://docs.molt.bot +Docs: https://docs.openclaw.ai -## 2026.1.29 +## 2026.1.27-beta.1 Status: beta. -### Highlights -- Rebrand: rename the npm package/CLI to `moltbot`, keep a `moltbot` compatibility shim, move extensions to the `@moltbot/*` scope, and update bot.molt bundle IDs/labels/logging subsystems. Thanks @thewilloftheshadow. -- New channels/plugins: Twitch plugin; Google Chat (beta) with Workspace Add-on events + typing indicator. (#1612, #1635) Thanks @tyler6204, @iHildy. -- Security hardening: gateway auth defaults required, hook token query-param deprecation, Windows ACL audits, mDNS minimal discovery, and SSH target option injection fix. (#4001, #2016, #1957, #1882, #2200) -- WebChat: image paste + image-only sends; keep sub-agent announce replies visible. (#1925, #1977) -- Tooling: per-sender group tool policies + tools.alsoAllow additive allowlist. (#1757, #1762) -- Memory Search: allow extra paths for memory indexing. (#3600) Thanks @kira-ariaki. - ### Changes -- Providers: add Venice AI integration; update Moonshot Kimi references to kimi-k2.5; update MiniMax API endpoint/format. (#2762, #3064) -- Providers: add Xiaomi MiMo (mimo-v2-flash) support and onboarding flow. (#3454) Thanks @WqyJh. -- Telegram: quote replies, edit-message action, silent sends, sticker support + vision caching, linkPreview toggle, plugin sendPayload support. (#2900, #2394, #2382, #2548, #1700, #1917) -- Discord: configurable privileged gateway intents for presences/members. (#2266) Thanks @kentaro. -- Browser: route browser control via gateway/node; fallback URL matching for relay targets. (#1999) -- macOS: add direct gateway transport; preserve custom SSH usernames for remote control; bump Textual to 0.3.1. (#2033, #2046) -- Routing: add per-account DM session scope + guidance for multi-account setups. (#3095) Thanks @jarvis-sam. -- Hooks: make session-memory message count configurable. (#2681) -- Tools: honor tools.exec.safeBins in exec allowlist checks. (#2281) -- Security: add Control UI device auth bypass flag + audit warnings; warn on hook tokens via query params; add security audit CLI surface. (#2248, #2200) -- Doctor: warn on gateway exposure without auth. (#2016) Thanks @Alex-Alaniz. -- Config: apply config.env before ${VAR} substitution. (#1813) -- Web search: add Brave freshness filter parameter. (#1688) Thanks @JonUleis. -- Control UI: improve chat session dropdown refresh, URL confirmation flow, config-save guardrails, and chat composer sizing. (#3682, #3578, #1707, #2950) +- Rebrand: rename the npm package/CLI to `openclaw`, add a `openclaw` compatibility shim, and move extensions to the `@openclaw/*` scope. - Commands: group /help and /commands output with Telegram paging. (#2504) Thanks @hougangdev. -- CLI: use Node's compile cache for faster startup; recognize versioned node binaries (e.g., node-22). (#2808, #2490) Thanks @pi0, @David-Marsh-Photo. +- macOS: limit project-local `node_modules/.bin` PATH preference to debug builds (reduce PATH hijacking risk). +- macOS: finish OpenClaw app rename for macOS sources, bundle identifiers, and shared kit paths. (#2844) Thanks @fal3. +- Branding: update launchd labels, mobile bundle IDs, and logging subsystems to bot.molt (legacy com.clawdbot migrations). Thanks @thewilloftheshadow. +- Tools: add per-sender group tool policies and fix precedence. (#1757) Thanks @adam91holt. - Agents: summarize dropped messages during compaction safeguard pruning. (#2509) Thanks @jogi47. +- Memory Search: allow extra paths for memory indexing (ignores symlinks). (#3600) Thanks @kira-ariaki. - Skills: add multi-image input support to Nano Banana Pro skill. (#1958) Thanks @tyler6204. +- Agents: honor tools.exec.safeBins in exec allowlist checks. (#2281) - Matrix: switch plugin SDK to @vector-im/matrix-bot-sdk. -- Docs: new deployment guides (Northflank, Render, Oracle, Raspberry Pi, GCP, DigitalOcean), Claude Max API Proxy, Vercel AI Gateway, migration guide, formal verification updates, and Fly private hardening. (#2167, #1975, #2333, #1871, #1848, #1870, #1875, #1901, #2381, #2289) -- Onboarding: add Venice API key to non-interactive flow; strengthen security warning copy. +- Docs: tighten Fly private deployment steps. (#2289) Thanks @dguido. +- Docs: add migration guide for moving to a new machine. (#2381) +- Docs: add Northflank one-click deployment guide. (#2167) Thanks @AdeboyeDN. +- Gateway: warn on hook tokens via query params; document header auth preference. (#2200) Thanks @YuriNachos. +- Gateway: add dangerous Control UI device auth bypass flag + audit warnings. (#2248) +- Doctor: warn on gateway exposure without auth. (#2016) Thanks @Alex-Alaniz. +- Config: auto-migrate legacy state/config paths and keep config resolution consistent across legacy filenames. +- Discord: add configurable privileged gateway intents for presences/members. (#2266) Thanks @kentaro. +- Docs: add Vercel AI Gateway to providers sidebar. (#1901) Thanks @jerilynzheng. +- Agents: expand cron tool description with full schema docs. (#1988) Thanks @tomascupr. +- Skills: add missing dependency metadata for GitHub, Notion, Slack, Discord. (#1995) Thanks @jackheuberger. +- Docs: add Render deployment guide. (#1975) Thanks @anurag. +- Docs: add Claude Max API Proxy guide. (#1875) Thanks @atalovesyou. +- Docs: add DigitalOcean deployment guide. (#1870) Thanks @0xJonHoldsCrypto. +- Docs: add Oracle Cloud (OCI) platform guide + cross-links. (#2333) Thanks @hirefrank. +- Docs: add Raspberry Pi install guide. (#1871) Thanks @0xJonHoldsCrypto. +- Docs: add GCP Compute Engine deployment guide. (#1848) Thanks @hougangdev. +- Docs: add LINE channel guide. Thanks @thewilloftheshadow. +- Docs: credit both contributors for Control UI refresh. (#1852) Thanks @EnzeD. +- Onboarding: add Venice API key to non-interactive flow. (#1893) Thanks @jonisjongithub. +- Onboarding: strengthen security warning copy for beta + access control expectations. +- Tlon: format thread reply IDs as @ud. (#1837) Thanks @wca4a. +- Gateway: prefer newest session metadata when combining stores. (#1823) Thanks @emanuelst. +- Web UI: keep sub-agent announce replies visible in WebChat. (#1977) Thanks @andrescardonas7. +- CI: increase Node heap size for macOS checks. (#1890) Thanks @realZachi. +- macOS: avoid crash when rendering code blocks by bumping Textual to 0.3.1. (#2033) Thanks @garricn. +- Browser: fall back to URL matching for extension relay target resolution. (#1999) Thanks @jonit-dev. +- Browser: route browser control via gateway/node; remove standalone browser control command and control URL config. +- Browser: route `browser.request` via node proxies when available; honor proxy timeouts; derive browser ports from `gateway.port`. +- Update: ignore dist/control-ui for dirty checks and restore after ui builds. (#1976) Thanks @Glucksberg. +- Build: bundle A2UI assets during build and stop tracking generated bundles. (#2455) Thanks @0oAstro. +- Telegram: allow caption param for media sends. (#1888) Thanks @mguellsegarra. +- Telegram: support plugin sendPayload channelData (media/buttons) and validate plugin commands. (#1917) Thanks @JoshuaLelon. +- Telegram: avoid block replies when streaming is disabled. (#1885) Thanks @ivancasco. +- Docs: keep docs header sticky so navbar stays visible while scrolling. (#2445) Thanks @chenyuan99. +- Docs: update exe.dev install instructions. (#https://github.com/openclaw/openclaw/pull/3047) Thanks @zackerthescar. +- Security: use Windows ACLs for permission audits and fixes on Windows. (#1957) +- Auth: show copyable Google auth URL after ASCII prompt. (#1787) Thanks @robbyczgw-cla. +- Routing: precompile session key regexes. (#1697) Thanks @Ray0907. +- TUI: avoid width overflow when rendering selection lists. (#1686) Thanks @mossein. +- Telegram: keep topic IDs in restart sentinel notifications. (#1807) Thanks @hsrvc. +- Telegram: add optional silent send flag (disable notifications). (#2382) Thanks @Suksham-sharma. +- Telegram: support editing sent messages via message(action="edit"). (#2394) Thanks @marcelomar21. +- Telegram: support quote replies for message tool and inbound context. (#2900) Thanks @aduk059. +- Telegram: add sticker receive/send with vision caching. (#2629) Thanks @longjos. +- Telegram: send sticker pixels to vision models. (#2650) +- Config: apply config.env before ${VAR} substitution. (#1813) Thanks @spanishflu-est1918. +- Slack: clear ack reaction after streamed replies. (#2044) Thanks @fancyboi999. +- macOS: keep custom SSH usernames in remote target. (#2046) Thanks @algal. +- CLI: use Node's module compile cache for faster startup. (#2808) Thanks @pi0. +- Routing: add per-account DM session scope and document multi-account isolation. (#3095) Thanks @jarvis-sam. ### Breaking - **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed). ### Fixes -- Security: harden SSH tunnel target parsing to prevent option injection/DoS. (#4001) Thanks @YLChen-007. -- Security: prevent PATH injection in exec sandbox; harden file serving; pin DNS in URL fetches; verify Twilio webhooks; fix LINE webhook timing-attack edge case; validate Tailscale Serve identity; flag loopback Control UI with auth disabled as critical. (#1616, #1795) -- Gateway: prevent crashes on transient network errors, suppress AbortError/unhandled rejections, sanitize error responses, clean session locks on exit, and harden reverse proxy handling for unauthenticated proxied connects. (#2980, #2451, #2483, #1795) -- Config: auto-migrate legacy state/config paths; honor state dir overrides. -- Packaging: include missing dist/shared and dist/link-understanding outputs in npm tarball installs. -- Telegram: avoid silent empty replies, improve polling/network recovery, handle video notes, keep DM thread sessions, ignore non-forum message_thread_id, centralize API error logging, include AccountId in native command context. (#3796, #3013, #2905, #2731, #2492, #2942) -- Telegram: preserve reasoning tags inside code blocks. (#3952) Thanks @vinaygit18. -- Discord: restore username resolution, resolve outbound usernames to IDs, honor threadId replies, guard forum thread access. (#3131, #2649) -- BlueBubbles: coalesce URL link previews, improve reaction handling, preserve reply-tag GUIDs. (#1981, #1641) -- Voice Call: prevent TTS overlap, validate env-var config, return TwiML for conversation calls. (#1713, #1634) -- Media: fix text attachment MIME classification + XML escaping on Windows. (#3628, #3750) -- Models: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94. -- Web UI: auto-scroll on send; fix textarea sizing; improve chat session refresh. (#2471, #2950, #3682) -- CLI/TUI: resume sessions cleanly; guard width overflow; avoid spinner prompt race. (#1921, #1686, #2874) -- Slack: fix file downloads failing on redirects with missing auth header. (#1936) -- iMessage: normalize messaging targets. (#1708) -- Signal: fix reactions and add configurable startup timeout. (#1651, #1677) -- Matrix: decrypt E2EE media with size guard. (#1744) +- Telegram: avoid silent empty replies by tracking normalization skips before fallback. (#3796) +- Mentions: honor mentionPatterns even when explicit mentions are present. (#3303) Thanks @HirokiKobayashi-R. +- Discord: restore username directory lookup in target resolution. (#3131) Thanks @bonald. +- Agents: align MiniMax base URL test expectation with default provider config. (#3131) Thanks @bonald. +- Agents: prevent retries on oversized image errors and surface size limits. (#2871) Thanks @Suksham-sharma. +- Agents: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94. +- Memory Search: keep auto provider model defaults and only include remote when configured. (#2576) Thanks @papago2355. +- Telegram: include AccountId in native command context for multi-agent routing. (#2942) Thanks @Chloe-VP. +- Telegram: handle video note attachments in media extraction. (#2905) Thanks @mylukin. +- TTS: read OPENAI_TTS_BASE_URL at runtime instead of module load to honor config.env. (#3341) Thanks @hclsys. +- macOS: auto-scroll to bottom when sending a new message while scrolled up. (#2471) Thanks @kennyklee. +- Web UI: auto-expand the chat compose textarea while typing (with sensible max height). (#2950) Thanks @shivamraut101. +- Gateway: prevent crashes on transient network errors (fetch failures, timeouts, DNS). Added fatal error detection to only exit on truly critical errors. Fixes #2895, #2879, #2873. (#2980) Thanks @elliotsecops. +- Agents: guard channel tool listActions to avoid plugin crashes. (#2859) Thanks @mbelinky. +- Discord: stop resolveDiscordTarget from passing directory params into messaging target parsers. Fixes #3167. Thanks @thewilloftheshadow. +- Discord: avoid resolving bare channel names to user DMs when a username matches. Thanks @thewilloftheshadow. +- Discord: fix directory config type import for target resolution. Thanks @thewilloftheshadow. +- Providers: update MiniMax API endpoint and compatibility mode. (#3064) Thanks @hlbbbbbbb. +- Telegram: treat more network errors as recoverable in polling. (#3013) Thanks @ryancontent. +- Discord: resolve usernames to user IDs for outbound messages. (#2649) Thanks @nonggialiang. +- Providers: update Moonshot Kimi model references to kimi-k2.5. (#2762) Thanks @MarvinCui. +- Gateway: suppress AbortError and transient network errors in unhandled rejections. (#2451) Thanks @Glucksberg. +- TTS: keep /tts status replies on text-only commands and avoid duplicate block-stream audio. (#2451) Thanks @Glucksberg. +- Security: pin npm overrides to keep tar@7.5.4 for install toolchains. +- Security: properly test Windows ACL audit for config includes. (#2403) Thanks @dominicnunez. +- CLI: recognize versioned Node executables when parsing argv. (#2490) Thanks @David-Marsh-Photo. +- CLI: avoid prompting for gateway runtime under the spinner. (#2874) +- BlueBubbles: coalesce inbound URL link preview messages. (#1981) Thanks @tyler6204. +- Cron: allow payloads containing "heartbeat" in event filter. (#2219) Thanks @dwfinkelstein. +- CLI: avoid loading config for global help/version while registering plugin commands. (#2212) Thanks @dial481. +- Agents: include memory.md when bootstrapping memory context. (#2318) Thanks @czekaj. +- Agents: release session locks on process termination and cover more signals. (#2483) Thanks @janeexai. +- Agents: skip cooldowned providers during model failover. (#2143) Thanks @YiWang24. +- Telegram: harden polling + retry behavior for transient network errors and Node 22 transport issues. (#2420) Thanks @techboss. +- Telegram: ignore non-forum group message_thread_id while preserving DM thread sessions. (#2731) Thanks @dylanneve1. +- Telegram: wrap reasoning italics per line to avoid raw underscores. (#2181) Thanks @YuriNachos. +- Telegram: centralize API error logging for delivery and bot calls. (#2492) Thanks @altryne. +- Voice Call: enforce Twilio webhook signature verification for ngrok URLs; disable ngrok free tier bypass by default. +- Security: harden Tailscale Serve auth by validating identity via local tailscaled before trusting headers. +- Media: fix text attachment MIME misclassification with CSV/TSV inference and UTF-16 detection; add XML attribute escaping for file output. (#3628) Thanks @frankekn. +- Build: align memory-core peer dependency with lockfile. +- Security: add mDNS discovery mode with minimal default to reduce information disclosure. (#1882) Thanks @orlyjamie. +- Security: harden URL fetches with DNS pinning to reduce rebinding risk. Thanks Chris Zheng. +- Web UI: improve WebChat image paste previews and allow image-only sends. (#1925) Thanks @smartprogrammer93. +- Security: wrap external hook content by default with a per-hook opt-out. (#1827) Thanks @mertcicekci0. +- Gateway: default auth now fail-closed (token/password required; Tailscale Serve identity remains allowed). +- Gateway: treat loopback + non-local Host connections as remote unless trusted proxy headers are present. +- Onboarding: remove unsupported gateway auth "off" choice from onboarding/configure flows and CLI flags. +## 2026.1.24-3 + +### Fixes +- Slack: fix image downloads failing due to missing Authorization header on cross-origin redirects. (#1936) Thanks @sanderhelgesen. +- Gateway: harden reverse proxy handling for local-client detection and unauthenticated proxied connects. (#1795) Thanks @orlyjamie. +- Security audit: flag loopback Control UI with auth disabled as critical. (#1795) Thanks @orlyjamie. +- CLI: resume claude-cli sessions and stream CLI replies to TUI clients. (#1921) Thanks @rmorse. + +## 2026.1.24-2 + +### Fixes +- Packaging: include dist/link-understanding output in npm tarball (fixes missing apply.js import on install). + +## 2026.1.24-1 + +### Fixes +- Packaging: include dist/shared output in npm tarball (fixes missing reasoning-tags import on install). ## 2026.1.24 ### Highlights -- Providers: Ollama discovery + docs; Venice guide upgrades + cross-links. (#1606) Thanks @abhaymundhara. https://docs.molt.bot/providers/ollama https://docs.molt.bot/providers/venice +- Providers: Ollama discovery + docs; Venice guide upgrades + cross-links. (#1606) Thanks @abhaymundhara. https://docs.openclaw.ai/providers/ollama https://docs.openclaw.ai/providers/venice - Channels: LINE plugin (Messaging API) with rich replies + quick replies. (#1630) Thanks @plum-dawg. -- TTS: Edge fallback (keyless) + `/tts` auto modes. (#1668, #1667) Thanks @steipete, @sebslight. https://docs.molt.bot/tts -- Exec approvals: approve in-chat via `/approve` across all channels (including plugins). (#1621) Thanks @czekaj. https://docs.molt.bot/tools/exec-approvals https://docs.molt.bot/tools/slash-commands -- Telegram: DM topics as separate sessions + outbound link preview toggle. (#1597, #1700) Thanks @rohannagpal, @zerone0x. https://docs.molt.bot/channels/telegram +- TTS: Edge fallback (keyless) + `/tts` auto modes. (#1668, #1667) Thanks @steipete, @sebslight. https://docs.openclaw.ai/tts +- Exec approvals: approve in-chat via `/approve` across all channels (including plugins). (#1621) Thanks @czekaj. https://docs.openclaw.ai/tools/exec-approvals https://docs.openclaw.ai/tools/slash-commands +- Telegram: DM topics as separate sessions + outbound link preview toggle. (#1597, #1700) Thanks @rohannagpal, @zerone0x. https://docs.openclaw.ai/channels/telegram ### Changes - Channels: add LINE plugin (Messaging API) with rich replies, quick replies, and plugin HTTP registry. (#1630) Thanks @plum-dawg. -- TTS: add Edge TTS provider fallback, defaulting to keyless Edge with MP3 retry on format failures. (#1668) Thanks @steipete. https://docs.molt.bot/tts -- TTS: add auto mode enum (off/always/inbound/tagged) with per-session `/tts` override. (#1667) Thanks @sebslight. https://docs.molt.bot/tts +- TTS: add Edge TTS provider fallback, defaulting to keyless Edge with MP3 retry on format failures. (#1668) Thanks @steipete. https://docs.openclaw.ai/tts +- TTS: add auto mode enum (off/always/inbound/tagged) with per-session `/tts` override. (#1667) Thanks @sebslight. https://docs.openclaw.ai/tts - Telegram: treat DM topics as separate sessions and keep DM history limits stable with thread suffixes. (#1597) Thanks @rohannagpal. -- Telegram: add `channels.telegram.linkPreview` to toggle outbound link previews. (#1700) Thanks @zerone0x. https://docs.molt.bot/channels/telegram -- Web search: add Brave freshness filter parameter for time-scoped results. (#1688) Thanks @JonUleis. https://docs.molt.bot/tools/web +- Telegram: add `channels.telegram.linkPreview` to toggle outbound link previews. (#1700) Thanks @zerone0x. https://docs.openclaw.ai/channels/telegram +- Web search: add Brave freshness filter parameter for time-scoped results. (#1688) Thanks @JonUleis. https://docs.openclaw.ai/tools/web - UI: refresh Control UI dashboard design system (colors, icons, typography). (#1745, #1786) Thanks @EnzeD, @mousberg. -- Exec approvals: forward approval prompts to chat with `/approve` for all channels (including plugins). (#1621) Thanks @czekaj. https://docs.molt.bot/tools/exec-approvals https://docs.molt.bot/tools/slash-commands +- Exec approvals: forward approval prompts to chat with `/approve` for all channels (including plugins). (#1621) Thanks @czekaj. https://docs.openclaw.ai/tools/exec-approvals https://docs.openclaw.ai/tools/slash-commands - Gateway: expose config.patch in the gateway tool with safe partial updates + restart sentinel. (#1653) Thanks @Glucksberg. -- Diagnostics: add diagnostic flags for targeted debug logs (config + env override). https://docs.molt.bot/diagnostics/flags +- Diagnostics: add diagnostic flags for targeted debug logs (config + env override). https://docs.openclaw.ai/diagnostics/flags - Docs: expand FAQ (migration, scheduling, concurrency, model recommendations, OpenAI subscription auth, Pi sizing, hackable install, docs SSL workaround). - Docs: add verbose installer troubleshooting guidance. - Docs: add macOS VM guide with local/hosted options + VPS/nodes guidance. (#1693) Thanks @f-trycua. -- Docs: add Bedrock EC2 instance role setup + IAM steps. (#1625) Thanks @sergical. https://docs.molt.bot/bedrock +- Docs: add Bedrock EC2 instance role setup + IAM steps. (#1625) Thanks @sergical. https://docs.openclaw.ai/bedrock - Docs: update Fly.io guide notes. - Dev: add prek pre-commit hooks + dependabot config for weekly updates. (#1720) Thanks @dguido. @@ -94,11 +174,11 @@ Status: beta. - Web UI: hide internal `message_id` hints in chat bubbles. - Gateway: allow Control UI token-only auth to skip device pairing even when device identity is present (`gateway.controlUi.allowInsecureAuth`). (#1679) Thanks @steipete. - Matrix: decrypt E2EE media attachments with preflight size guard. (#1744) Thanks @araa47. -- BlueBubbles: route phone-number targets to DMs, avoid leaking routing IDs, and auto-create missing DMs (Private API required). (#1751) Thanks @tyler6204. https://docs.molt.bot/channels/bluebubbles +- BlueBubbles: route phone-number targets to DMs, avoid leaking routing IDs, and auto-create missing DMs (Private API required). (#1751) Thanks @tyler6204. https://docs.openclaw.ai/channels/bluebubbles - BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing. - iMessage: normalize chat_id/chat_guid/chat_identifier prefixes case-insensitively and keep service-prefixed handles stable. (#1708) Thanks @aaronn. - Signal: repair reaction sends (group/UUID targets + CLI author flags). (#1651) Thanks @vilkasdev. -- Signal: add configurable signal-cli startup timeout + external daemon mode docs. (#1677) https://docs.molt.bot/channels/signal +- Signal: add configurable signal-cli startup timeout + external daemon mode docs. (#1677) https://docs.openclaw.ai/channels/signal - Telegram: set fetch duplex="half" for uploads on Node 22 to avoid sendPhoto failures. (#1684) Thanks @commdata2338. - Telegram: use wrapped fetch for long-polling on Node to normalize AbortSignal handling. (#1639) - Telegram: honor per-account proxy for outbound API calls. (#1774) Thanks @radek-paclt. @@ -136,25 +216,25 @@ Status: beta. ## 2026.1.23 ### Highlights -- TTS: move Telegram TTS into core + enable model-driven TTS tags by default for expressive audio replies. (#1559) Thanks @Glucksberg. https://docs.molt.bot/tts -- Gateway: add `/tools/invoke` HTTP endpoint for direct tool calls (auth + tool policy enforced). (#1575) Thanks @vignesh07. https://docs.molt.bot/gateway/tools-invoke-http-api -- Heartbeat: per-channel visibility controls (OK/alerts/indicator). (#1452) Thanks @dlauer. https://docs.molt.bot/gateway/heartbeat -- Deploy: add Fly.io deployment support + guide. (#1570) https://docs.molt.bot/platforms/fly -- Channels: add Tlon/Urbit channel plugin (DMs, group mentions, thread replies). (#1544) Thanks @wca4a. https://docs.molt.bot/channels/tlon +- TTS: move Telegram TTS into core + enable model-driven TTS tags by default for expressive audio replies. (#1559) Thanks @Glucksberg. https://docs.openclaw.ai/tts +- Gateway: add `/tools/invoke` HTTP endpoint for direct tool calls (auth + tool policy enforced). (#1575) Thanks @vignesh07. https://docs.openclaw.ai/gateway/tools-invoke-http-api +- Heartbeat: per-channel visibility controls (OK/alerts/indicator). (#1452) Thanks @dlauer. https://docs.openclaw.ai/gateway/heartbeat +- Deploy: add Fly.io deployment support + guide. (#1570) https://docs.openclaw.ai/platforms/fly +- Channels: add Tlon/Urbit channel plugin (DMs, group mentions, thread replies). (#1544) Thanks @wca4a. https://docs.openclaw.ai/channels/tlon ### Changes -- Channels: allow per-group tool allow/deny policies across built-in + plugin channels. (#1546) Thanks @adam91holt. https://docs.molt.bot/multi-agent-sandbox-tools -- Agents: add Bedrock auto-discovery defaults + config overrides. (#1553) Thanks @fal3. https://docs.molt.bot/bedrock -- CLI: add `moltbot system` for system events + heartbeat controls; remove standalone `wake`. (commit 71203829d) https://docs.molt.bot/cli/system -- CLI: add live auth probes to `moltbot models status` for per-profile verification. (commit 40181afde) https://docs.molt.bot/cli/models -- CLI: restart the gateway by default after `moltbot update`; add `--no-restart` to skip it. (commit 2c85b1b40) +- Channels: allow per-group tool allow/deny policies across built-in + plugin channels. (#1546) Thanks @adam91holt. https://docs.openclaw.ai/multi-agent-sandbox-tools +- Agents: add Bedrock auto-discovery defaults + config overrides. (#1553) Thanks @fal3. https://docs.openclaw.ai/bedrock +- CLI: add `openclaw system` for system events + heartbeat controls; remove standalone `wake`. (commit 71203829d) https://docs.openclaw.ai/cli/system +- CLI: add live auth probes to `openclaw models status` for per-profile verification. (commit 40181afde) https://docs.openclaw.ai/cli/models +- CLI: restart the gateway by default after `openclaw update`; add `--no-restart` to skip it. (commit 2c85b1b40) - Browser: add node-host proxy auto-routing for remote gateways (configurable per gateway/node). (commit c3cb26f7c) -- Plugins: add optional `llm-task` JSON-only tool for workflows. (#1498) Thanks @vignesh07. https://docs.molt.bot/tools/llm-task +- Plugins: add optional `llm-task` JSON-only tool for workflows. (#1498) Thanks @vignesh07. https://docs.openclaw.ai/tools/llm-task - Markdown: add per-channel table conversion (bullets for Signal/WhatsApp, code blocks elsewhere). (#1495) Thanks @odysseus0. - Agents: keep system prompt time zone-only and move current time to `session_status` for better cache hits. (commit 66eec295b) - Agents: remove redundant bash tool alias from tool registration/display. (#1571) Thanks @Takhoffman. -- Docs: add cron vs heartbeat decision guide (with Lobster workflow notes). (#1533) Thanks @JustYannicc. https://docs.molt.bot/automation/cron-vs-heartbeat -- Docs: clarify HEARTBEAT.md empty file skips heartbeats, missing file still runs. (#1535) Thanks @JustYannicc. https://docs.molt.bot/gateway/heartbeat +- Docs: add cron vs heartbeat decision guide (with Lobster workflow notes). (#1533) Thanks @JustYannicc. https://docs.openclaw.ai/automation/cron-vs-heartbeat +- Docs: clarify HEARTBEAT.md empty file skips heartbeats, missing file still runs. (#1535) Thanks @JustYannicc. https://docs.openclaw.ai/gateway/heartbeat ### Fixes - Sessions: accept non-UUID sessionIds for history/send/status while preserving agent scoping. (#1518) @@ -187,7 +267,7 @@ Status: beta. - UI: keep the Control UI sidebar visible while scrolling long pages. (#1515) Thanks @pookNast. - UI: cache Control UI markdown rendering + memoize chat text extraction to reduce Safari typing jank. (commit d57cb2e1a) - TUI: forward unknown slash commands, include Gateway commands in autocomplete, and render slash replies as system output. (commit 1af227b61, commit 8195497ce, commit 6fba598ea) -- CLI: auth probe output polish (table output, inline errors, reduced noise, and wrap fixes in `moltbot models status`). (commit da3f2b489, commit 00ae21bed, commit 31e59cd58, commit f7dc27f2d, commit 438e782f8, commit 886752217, commit aabe0bed3, commit 81535d512, commit c63144ab1) +- CLI: auth probe output polish (table output, inline errors, reduced noise, and wrap fixes in `openclaw models status`). (commit da3f2b489, commit 00ae21bed, commit 31e59cd58, commit f7dc27f2d, commit 438e782f8, commit 886752217, commit aabe0bed3, commit 81535d512, commit c63144ab1) - Media: only parse `MEDIA:` tags when they start the line to avoid stripping prose mentions. (#1206) - Media: preserve PNG alpha when possible; fall back to JPEG when still over size cap. (#1491) Thanks @robbyczgw-cla. - Skills: gate bird Homebrew install to macOS. (#1569) Thanks @bradleypriest. @@ -232,35 +312,35 @@ Status: beta. ## 2026.1.21-2 ### Fixes -- Control UI: ignore bootstrap identity placeholder text for avatar values and fall back to the default avatar. https://docs.molt.bot/cli/agents https://docs.molt.bot/web/control-ui +- Control UI: ignore bootstrap identity placeholder text for avatar values and fall back to the default avatar. https://docs.openclaw.ai/cli/agents https://docs.openclaw.ai/web/control-ui - Slack: remove deprecated `filetype` field from `files.uploadV2` to eliminate API warnings. (#1447) ## 2026.1.21 ### Changes -- Highlight: Lobster optional plugin tool for typed workflows + approval gates. https://docs.molt.bot/tools/lobster -- Lobster: allow workflow file args via `argsJson` in the plugin tool. https://docs.molt.bot/tools/lobster +- Highlight: Lobster optional plugin tool for typed workflows + approval gates. https://docs.openclaw.ai/tools/lobster +- Lobster: allow workflow file args via `argsJson` in the plugin tool. https://docs.openclaw.ai/tools/lobster - Heartbeat: allow running heartbeats in an explicit session key. (#1256) Thanks @zknicker. - CLI: default exec approvals to the local host, add gateway/node targeting flags, and show target details in allowlist output. - CLI: exec approvals mutations render tables instead of raw JSON. - Exec approvals: support wildcard agent allowlists (`*`) across all agents. - Exec approvals: allowlist matches resolved binary paths only, add safe stdin-only bins, and tighten allowlist shell parsing. - Nodes: expose node PATH in status/describe and bootstrap PATH for node-host execution. -- CLI: flatten node service commands under `moltbot node` and remove `service node` docs. -- CLI: move gateway service commands under `moltbot gateway` and add `gateway probe` for reachability. +- CLI: flatten node service commands under `openclaw node` and remove `service node` docs. +- CLI: move gateway service commands under `openclaw gateway` and add `gateway probe` for reachability. - Sessions: add per-channel reset overrides via `session.resetByChannel`. (#1353) Thanks @cash-echo-bot. - Agents: add identity avatar config support and Control UI avatar rendering. (#1329, #1424) Thanks @dlauer. - UI: show per-session assistant identity in the Control UI. (#1420) Thanks @robbyczgw-cla. -- CLI: add `moltbot update wizard` for interactive channel selection and restart prompts. https://docs.molt.bot/cli/update +- CLI: add `openclaw update wizard` for interactive channel selection and restart prompts. https://docs.openclaw.ai/cli/update - Signal: add typing indicators and DM read receipts via signal-cli. - MSTeams: add file uploads, adaptive cards, and attachment handling improvements. (#1410) Thanks @Evizero. - Onboarding: remove the run setup-token auth option (paste setup-token or reuse CLI creds instead). -- Docs: add troubleshooting entry for gateway.mode blocking gateway start. https://docs.molt.bot/gateway/troubleshooting +- Docs: add troubleshooting entry for gateway.mode blocking gateway start. https://docs.openclaw.ai/gateway/troubleshooting - Docs: add /model allowlist troubleshooting note. (#1405) - Docs: add per-message Gmail search example for gog. (#1220) Thanks @mbelinky. ### Breaking -- **BREAKING:** Control UI now rejects insecure HTTP without device identity by default. Use HTTPS (Tailscale Serve) or set `gateway.controlUi.allowInsecureAuth: true` to allow token-only auth. https://docs.molt.bot/web/control-ui#insecure-http +- **BREAKING:** Control UI now rejects insecure HTTP without device identity by default. Use HTTPS (Tailscale Serve) or set `gateway.controlUi.allowInsecureAuth: true` to allow token-only auth. https://docs.openclaw.ai/web/control-ui#insecure-http - **BREAKING:** Envelope and system event timestamps now default to host-local time (was UTC) so agents don’t have to constantly convert. ### Fixes @@ -286,68 +366,68 @@ Status: beta. ## 2026.1.20 ### Changes -- Control UI: add copy-as-markdown with error feedback. (#1345) https://docs.molt.bot/web/control-ui -- Control UI: drop the legacy list view. (#1345) https://docs.molt.bot/web/control-ui -- TUI: add syntax highlighting for code blocks. (#1200) https://docs.molt.bot/tui -- TUI: session picker shows derived titles, fuzzy search, relative times, and last message preview. (#1271) https://docs.molt.bot/tui -- TUI: add a searchable model picker for quicker model selection. (#1198) https://docs.molt.bot/tui -- TUI: add input history (up/down) for submitted messages. (#1348) https://docs.molt.bot/tui -- ACP: add `moltbot acp` for IDE integrations. https://docs.molt.bot/cli/acp -- ACP: add `moltbot acp client` interactive harness for debugging. https://docs.molt.bot/cli/acp -- Skills: add download installs with OS-filtered options. https://docs.molt.bot/tools/skills -- Skills: add the local sherpa-onnx-tts skill. https://docs.molt.bot/tools/skills -- Memory: add hybrid BM25 + vector search (FTS5) with weighted merging and fallback. https://docs.molt.bot/concepts/memory -- Memory: add SQLite embedding cache to speed up reindexing and frequent updates. https://docs.molt.bot/concepts/memory -- Memory: add OpenAI batch indexing for embeddings when configured. https://docs.molt.bot/concepts/memory -- Memory: enable OpenAI batch indexing by default for OpenAI embeddings. https://docs.molt.bot/concepts/memory -- Memory: allow parallel OpenAI batch indexing jobs (default concurrency: 2). https://docs.molt.bot/concepts/memory -- Memory: render progress immediately, color batch statuses in verbose logs, and poll OpenAI batch status every 2s by default. https://docs.molt.bot/concepts/memory -- Memory: add `--verbose` logging for memory status + batch indexing details. https://docs.molt.bot/concepts/memory -- Memory: add native Gemini embeddings provider for memory search. (#1151) https://docs.molt.bot/concepts/memory -- Browser: allow config defaults for efficient snapshots in the tool/CLI. (#1336) https://docs.molt.bot/tools/browser -- Nostr: add the Nostr channel plugin with profile management + onboarding defaults. (#1323) https://docs.molt.bot/channels/nostr -- Matrix: migrate to matrix-bot-sdk with E2EE support, location handling, and group allowlist upgrades. (#1298) https://docs.molt.bot/channels/matrix -- Slack: add HTTP webhook mode via Bolt HTTP receiver. (#1143) https://docs.molt.bot/channels/slack -- Telegram: enrich forwarded-message context with normalized origin details + legacy fallback. (#1090) https://docs.molt.bot/channels/telegram +- Control UI: add copy-as-markdown with error feedback. (#1345) https://docs.openclaw.ai/web/control-ui +- Control UI: drop the legacy list view. (#1345) https://docs.openclaw.ai/web/control-ui +- TUI: add syntax highlighting for code blocks. (#1200) https://docs.openclaw.ai/tui +- TUI: session picker shows derived titles, fuzzy search, relative times, and last message preview. (#1271) https://docs.openclaw.ai/tui +- TUI: add a searchable model picker for quicker model selection. (#1198) https://docs.openclaw.ai/tui +- TUI: add input history (up/down) for submitted messages. (#1348) https://docs.openclaw.ai/tui +- ACP: add `openclaw acp` for IDE integrations. https://docs.openclaw.ai/cli/acp +- ACP: add `openclaw acp client` interactive harness for debugging. https://docs.openclaw.ai/cli/acp +- Skills: add download installs with OS-filtered options. https://docs.openclaw.ai/tools/skills +- Skills: add the local sherpa-onnx-tts skill. https://docs.openclaw.ai/tools/skills +- Memory: add hybrid BM25 + vector search (FTS5) with weighted merging and fallback. https://docs.openclaw.ai/concepts/memory +- Memory: add SQLite embedding cache to speed up reindexing and frequent updates. https://docs.openclaw.ai/concepts/memory +- Memory: add OpenAI batch indexing for embeddings when configured. https://docs.openclaw.ai/concepts/memory +- Memory: enable OpenAI batch indexing by default for OpenAI embeddings. https://docs.openclaw.ai/concepts/memory +- Memory: allow parallel OpenAI batch indexing jobs (default concurrency: 2). https://docs.openclaw.ai/concepts/memory +- Memory: render progress immediately, color batch statuses in verbose logs, and poll OpenAI batch status every 2s by default. https://docs.openclaw.ai/concepts/memory +- Memory: add `--verbose` logging for memory status + batch indexing details. https://docs.openclaw.ai/concepts/memory +- Memory: add native Gemini embeddings provider for memory search. (#1151) https://docs.openclaw.ai/concepts/memory +- Browser: allow config defaults for efficient snapshots in the tool/CLI. (#1336) https://docs.openclaw.ai/tools/browser +- Nostr: add the Nostr channel plugin with profile management + onboarding defaults. (#1323) https://docs.openclaw.ai/channels/nostr +- Matrix: migrate to matrix-bot-sdk with E2EE support, location handling, and group allowlist upgrades. (#1298) https://docs.openclaw.ai/channels/matrix +- Slack: add HTTP webhook mode via Bolt HTTP receiver. (#1143) https://docs.openclaw.ai/channels/slack +- Telegram: enrich forwarded-message context with normalized origin details + legacy fallback. (#1090) https://docs.openclaw.ai/channels/telegram - Discord: fall back to `/skill` when native command limits are exceeded. (#1287) - Discord: expose `/skill` globally. (#1287) -- Zalouser: add channel dock metadata, config schema, setup wiring, probe, and status issues. (#1219) https://docs.molt.bot/plugins/zalouser -- Plugins: require manifest-embedded config schemas with preflight validation warnings. (#1272) https://docs.molt.bot/plugins/manifest -- Plugins: move channel catalog metadata into plugin manifests. (#1290) https://docs.molt.bot/plugins/manifest -- Plugins: align Nextcloud Talk policy helpers with core patterns. (#1290) https://docs.molt.bot/plugins/manifest -- Plugins/UI: let channel plugin metadata drive UI labels/icons and cron channel options. (#1306) https://docs.molt.bot/web/control-ui -- Agents/UI: add agent avatar support in identity config, IDENTITY.md, and the Control UI. (#1329) https://docs.molt.bot/gateway/configuration -- Plugins: add plugin slots with a dedicated memory slot selector. https://docs.molt.bot/plugins/agent-tools -- Plugins: ship the bundled BlueBubbles channel plugin (disabled by default). https://docs.molt.bot/channels/bluebubbles +- Zalouser: add channel dock metadata, config schema, setup wiring, probe, and status issues. (#1219) https://docs.openclaw.ai/plugins/zalouser +- Plugins: require manifest-embedded config schemas with preflight validation warnings. (#1272) https://docs.openclaw.ai/plugins/manifest +- Plugins: move channel catalog metadata into plugin manifests. (#1290) https://docs.openclaw.ai/plugins/manifest +- Plugins: align Nextcloud Talk policy helpers with core patterns. (#1290) https://docs.openclaw.ai/plugins/manifest +- Plugins/UI: let channel plugin metadata drive UI labels/icons and cron channel options. (#1306) https://docs.openclaw.ai/web/control-ui +- Agents/UI: add agent avatar support in identity config, IDENTITY.md, and the Control UI. (#1329) https://docs.openclaw.ai/gateway/configuration +- Plugins: add plugin slots with a dedicated memory slot selector. https://docs.openclaw.ai/plugins/agent-tools +- Plugins: ship the bundled BlueBubbles channel plugin (disabled by default). https://docs.openclaw.ai/channels/bluebubbles - Plugins: migrate bundled messaging extensions to the plugin SDK and resolve plugin-sdk imports in the loader. -- Plugins: migrate the Zalo plugin to the shared plugin SDK runtime. https://docs.molt.bot/channels/zalo -- Plugins: migrate the Zalo Personal plugin to the shared plugin SDK runtime. https://docs.molt.bot/plugins/zalouser -- Plugins: allow optional agent tools with explicit allowlists and add the plugin tool authoring guide. https://docs.molt.bot/plugins/agent-tools +- Plugins: migrate the Zalo plugin to the shared plugin SDK runtime. https://docs.openclaw.ai/channels/zalo +- Plugins: migrate the Zalo Personal plugin to the shared plugin SDK runtime. https://docs.openclaw.ai/plugins/zalouser +- Plugins: allow optional agent tools with explicit allowlists and add the plugin tool authoring guide. https://docs.openclaw.ai/plugins/agent-tools - Plugins: auto-enable bundled channel/provider plugins when configuration is present. -- Plugins: sync plugin sources on channel switches and update npm-installed plugins during `moltbot update`. -- Plugins: share npm plugin update logic between `moltbot update` and `moltbot plugins update`. +- Plugins: sync plugin sources on channel switches and update npm-installed plugins during `openclaw update`. +- Plugins: share npm plugin update logic between `openclaw update` and `openclaw plugins update`. - Gateway/API: add `/v1/responses` (OpenResponses) with item-based input + semantic streaming events. (#1229) - Gateway/API: expand `/v1/responses` to support file/image inputs, tool_choice, usage, and output limits. (#1229) -- Usage: add `/usage cost` summaries and macOS menu cost charts. https://docs.molt.bot/reference/api-usage-costs -- Security: warn when <=300B models run without sandboxing while web tools are enabled. https://docs.molt.bot/cli/security -- Exec: add host/security/ask routing for gateway + node exec. https://docs.molt.bot/tools/exec -- Exec: add `/exec` directive for per-session exec defaults (host/security/ask/node). https://docs.molt.bot/tools/exec -- Exec approvals: migrate approvals to `~/.clawdbot/exec-approvals.json` with per-agent allowlists + skill auto-allow toggle, and add approvals UI + node exec lifecycle events. https://docs.molt.bot/tools/exec-approvals -- Nodes: add headless node host (`moltbot node start`) for `system.run`/`system.which`. https://docs.molt.bot/cli/node -- Nodes: add node daemon service install/status/start/stop/restart. https://docs.molt.bot/cli/node +- Usage: add `/usage cost` summaries and macOS menu cost charts. https://docs.openclaw.ai/reference/api-usage-costs +- Security: warn when <=300B models run without sandboxing while web tools are enabled. https://docs.openclaw.ai/cli/security +- Exec: add host/security/ask routing for gateway + node exec. https://docs.openclaw.ai/tools/exec +- Exec: add `/exec` directive for per-session exec defaults (host/security/ask/node). https://docs.openclaw.ai/tools/exec +- Exec approvals: migrate approvals to `~/.clawdbot/exec-approvals.json` with per-agent allowlists + skill auto-allow toggle, and add approvals UI + node exec lifecycle events. https://docs.openclaw.ai/tools/exec-approvals +- Nodes: add headless node host (`openclaw node start`) for `system.run`/`system.which`. https://docs.openclaw.ai/cli/node +- Nodes: add node daemon service install/status/start/stop/restart. https://docs.openclaw.ai/cli/node - Bridge: add `skills.bins` RPC to support node host auto-allow skill bins. -- Sessions: add daily reset policy with per-type overrides and idle windows (default 4am local), preserving legacy idle-only configs. (#1146) https://docs.molt.bot/concepts/session -- Sessions: allow `sessions_spawn` to override thinking level for sub-agent runs. https://docs.molt.bot/tools/subagents -- Channels: unify thread/topic allowlist matching + command/mention gating helpers across core providers. https://docs.molt.bot/concepts/groups -- Models: add Qwen Portal OAuth provider support. (#1120) https://docs.molt.bot/providers/qwen -- Onboarding: add allowlist prompts and username-to-id resolution across core and extension channels. https://docs.molt.bot/start/onboarding -- Docs: clarify allowlist input types and onboarding behavior for messaging channels. https://docs.molt.bot/start/onboarding -- Docs: refresh Android node discovery docs for the Gateway WS service type. https://docs.molt.bot/platforms/android -- Docs: surface Amazon Bedrock in provider lists and clarify Bedrock auth env vars. (#1289) https://docs.molt.bot/bedrock -- Docs: clarify WhatsApp voice notes. https://docs.molt.bot/channels/whatsapp -- Docs: clarify Windows WSL portproxy LAN access notes. https://docs.molt.bot/platforms/windows -- Docs: refresh bird skill install metadata and usage notes. (#1302) https://docs.molt.bot/tools/browser-login +- Sessions: add daily reset policy with per-type overrides and idle windows (default 4am local), preserving legacy idle-only configs. (#1146) https://docs.openclaw.ai/concepts/session +- Sessions: allow `sessions_spawn` to override thinking level for sub-agent runs. https://docs.openclaw.ai/tools/subagents +- Channels: unify thread/topic allowlist matching + command/mention gating helpers across core providers. https://docs.openclaw.ai/concepts/groups +- Models: add Qwen Portal OAuth provider support. (#1120) https://docs.openclaw.ai/providers/qwen +- Onboarding: add allowlist prompts and username-to-id resolution across core and extension channels. https://docs.openclaw.ai/start/onboarding +- Docs: clarify allowlist input types and onboarding behavior for messaging channels. https://docs.openclaw.ai/start/onboarding +- Docs: refresh Android node discovery docs for the Gateway WS service type. https://docs.openclaw.ai/platforms/android +- Docs: surface Amazon Bedrock in provider lists and clarify Bedrock auth env vars. (#1289) https://docs.openclaw.ai/bedrock +- Docs: clarify WhatsApp voice notes. https://docs.openclaw.ai/channels/whatsapp +- Docs: clarify Windows WSL portproxy LAN access notes. https://docs.openclaw.ai/platforms/windows +- Docs: refresh bird skill install metadata and usage notes. (#1302) https://docs.openclaw.ai/tools/browser-login - Agents: add local docs path resolution and include docs/mirror/source/community pointers in the system prompt. - Agents: clarify node_modules read-only guidance in agent instructions. - Config: stamp last-touched metadata on write and warn if the config is newer than the running build. @@ -364,7 +444,7 @@ Status: beta. - Swabble: use the tagged Commander Swift package release. ### Breaking -- **BREAKING:** Reject invalid/unknown config entries and refuse to start the gateway for safety. Run `moltbot doctor --fix` to repair, then update plugins (`moltbot plugins update`) if you use any. +- **BREAKING:** Reject invalid/unknown config entries and refuse to start the gateway for safety. Run `openclaw doctor --fix` to repair, then update plugins (`openclaw plugins update`) if you use any. ### Fixes - Discovery: shorten Bonjour DNS-SD service type to `_moltbot-gw._tcp` and update discovery clients/docs. @@ -394,7 +474,7 @@ Status: beta. - Plugins: add Nextcloud Talk manifest for plugin config validation. (#1297) - Plugins: surface plugin load/register/config errors in gateway logs with plugin/source context. - CLI: preserve cron delivery settings when editing message payloads. (#1322) -- CLI: keep `moltbot logs` output resilient to broken pipes while preserving progress output. +- CLI: keep `openclaw logs` output resilient to broken pipes while preserving progress output. - CLI: avoid duplicating --profile/--dev flags when formatting commands. - CLI: centralize CLI command registration to keep fast-path routing and program wiring in sync. (#1207) - CLI: keep banners on routed commands, restore config guarding outside fast-path routing, and tighten fast-path flag parsing while skipping console capture for extra speed. (#1195) @@ -412,7 +492,7 @@ Status: beta. - TUI: show generic empty-state text for searchable pickers. (#1201) - TUI: highlight model search matches and stabilize search ordering. - Configure: hide OpenRouter auto routing model from the model picker. (#1182) -- Memory: show total file counts + scan issues in `moltbot memory status`. +- Memory: show total file counts + scan issues in `openclaw memory status`. - Memory: fall back to non-batch embeddings after repeated batch failures. - Memory: apply OpenAI batch defaults even without explicit remote config. - Memory: index atomically so failed reindex preserves the previous memory database. (#1151) @@ -422,7 +502,7 @@ Status: beta. - Memory: split overly long lines to keep embeddings under token limits. - Memory: skip empty chunks to avoid invalid embedding inputs. - Memory: split embedding batches to avoid OpenAI token limits during indexing. -- Memory: probe sqlite-vec availability in `moltbot memory status`. +- Memory: probe sqlite-vec availability in `openclaw memory status`. - Exec approvals: enforce allowlist when ask is off. - Exec approvals: prefer raw command for node approvals/events. - Tools: show exec elevated flag before the command and keep it outside markdown in tool summaries. @@ -472,20 +552,20 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ## 2026.1.16-1 ### Highlights -- Hooks: add hooks system with bundled hooks, CLI tooling, and docs. (#1028) — thanks @ThomsenDrake. https://docs.molt.bot/hooks -- Media: add inbound media understanding (image/audio/video) with provider + CLI fallbacks. https://docs.molt.bot/nodes/media-understanding -- Plugins: add Zalo Personal plugin (`@moltbot/zalouser`) and unify channel directory for plugins. (#1032) — thanks @suminhthanh. https://docs.molt.bot/plugins/zalouser -- Models: add Vercel AI Gateway auth choice + onboarding updates. (#1016) — thanks @timolins. https://docs.molt.bot/providers/vercel-ai-gateway -- Sessions: add `session.identityLinks` for cross-platform DM session li nking. (#1033) — thanks @thewilloftheshadow. https://docs.molt.bot/concepts/session -- Web search: add `country`/`language` parameters (schema + Brave API) and docs. (#1046) — thanks @YuriNachos. https://docs.molt.bot/tools/web +- Hooks: add hooks system with bundled hooks, CLI tooling, and docs. (#1028) — thanks @ThomsenDrake. https://docs.openclaw.ai/hooks +- Media: add inbound media understanding (image/audio/video) with provider + CLI fallbacks. https://docs.openclaw.ai/nodes/media-understanding +- Plugins: add Zalo Personal plugin (`@openclaw/zalouser`) and unify channel directory for plugins. (#1032) — thanks @suminhthanh. https://docs.openclaw.ai/plugins/zalouser +- Models: add Vercel AI Gateway auth choice + onboarding updates. (#1016) — thanks @timolins. https://docs.openclaw.ai/providers/vercel-ai-gateway +- Sessions: add `session.identityLinks` for cross-platform DM session li nking. (#1033) — thanks @thewilloftheshadow. https://docs.openclaw.ai/concepts/session +- Web search: add `country`/`language` parameters (schema + Brave API) and docs. (#1046) — thanks @YuriNachos. https://docs.openclaw.ai/tools/web ### Breaking -- **BREAKING:** `moltbot message` and message tool now require `target` (dropping `to`/`channelId` for destinations). (#1034) — thanks @tobalsan. +- **BREAKING:** `openclaw message` and message tool now require `target` (dropping `to`/`channelId` for destinations). (#1034) — thanks @tobalsan. - **BREAKING:** Channel auth now prefers config over env for Discord/Telegram/Matrix (env is fallback only). (#1040) — thanks @thewilloftheshadow. - **BREAKING:** Drop legacy `chatType: "room"` support; use `chatType: "channel"`. - **BREAKING:** remove legacy provider-specific target resolution fallbacks; target resolution is centralized with plugin hints + directory lookups. -- **BREAKING:** `moltbot hooks` is now `moltbot webhooks`; hooks live under `moltbot hooks`. https://docs.molt.bot/cli/webhooks -- **BREAKING:** `moltbot plugins install ` now copies into `~/.clawdbot/extensions` (use `--link` to keep path-based loading). +- **BREAKING:** `openclaw hooks` is now `openclaw webhooks`; hooks live under `openclaw hooks`. https://docs.openclaw.ai/cli/webhooks +- **BREAKING:** `openclaw plugins install ` now copies into `~/.clawdbot/extensions` (use `--link` to keep path-based loading). ### Changes - Plugins: ship bundled plugins disabled by default and allow overrides by installed versions. (#1066) — thanks @ItzR3NO. @@ -495,7 +575,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Tools: send Chrome-like headers by default for `web_fetch` to improve extraction on bot-sensitive sites. - Tools: Firecrawl fallback now uses bot-circumvention + cache by default; remove basic HTML fallback when extraction fails. - Tools: default `exec` exit notifications and auto-migrate legacy `tools.bash` to `tools.exec`. -- Tools: add `exec` PTY support for interactive sessions. https://docs.molt.bot/tools/exec +- Tools: add `exec` PTY support for interactive sessions. https://docs.openclaw.ai/tools/exec - Tools: add tmux-style `process send-keys` and bracketed paste helpers for PTY sessions. - Tools: add `process submit` helper to send CR for PTY sessions. - Tools: respond to PTY cursor position queries to unblock interactive TUIs. @@ -503,7 +583,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Skills: update coding-agent guidance to prefer PTY-enabled exec runs and simplify tmux usage. - TUI: refresh session token counts after runs complete or fail. (#1079) — thanks @d-ploutarchos. - Status: trim `/status` to current-provider usage only and drop the OAuth/token block. -- Directory: unify `moltbot directory` across channels and plugin channels. +- Directory: unify `openclaw directory` across channels and plugin channels. - UI: allow deleting sessions from the Control UI. - Memory: add sqlite-vec vector acceleration with CLI status details. - Memory: add experimental session transcript indexing for memory_search (opt-in via memorySearch.experimental.sessionMemory + sources). @@ -519,7 +599,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Docs: add `/help` hub, Node/npm PATH guide, and expand directory CLI docs. - Config: support env var substitution in config values. (#1044) — thanks @sebslight. - Health: add per-agent session summaries and account-level health details, and allow selective probes. (#1047) — thanks @gumadeiras. -- Hooks: add hook pack installs (npm/path/zip/tar) with `moltbot.hooks` manifests and `moltbot hooks install/update`. +- Hooks: add hook pack installs (npm/path/zip/tar) with `openclaw.hooks` manifests and `openclaw hooks install/update`. - Plugins: add zip installs and `--link` to avoid copying local paths. ### Fixes @@ -550,10 +630,10 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Sessions: hard-stop `sessions.delete` cleanup. - Channels: treat replies to the bot as implicit mentions across supported channels. - Channels: normalize object-format capabilities in channel capability parsing. -- Security: default-deny slash/control commands unless a channel computed `CommandAuthorized` (fixes accidental “open” behavior), and ensure WhatsApp + Zalo plugin channels gate inline `/…` tokens correctly. https://docs.molt.bot/gateway/security +- Security: default-deny slash/control commands unless a channel computed `CommandAuthorized` (fixes accidental “open” behavior), and ensure WhatsApp + Zalo plugin channels gate inline `/…` tokens correctly. https://docs.openclaw.ai/gateway/security - Security: redact sensitive text in gateway WS logs. - Tools: cap pending `exec` process output to avoid unbounded buffers. -- CLI: speed up `moltbot sandbox-explain` by avoiding heavy plugin imports when normalizing channel ids. +- CLI: speed up `openclaw sandbox-explain` by avoiding heavy plugin imports when normalizing channel ids. - Browser: remote profile tab operations prefer persistent Playwright and avoid silent HTTP fallbacks. (#1057) — thanks @mukhtharcm. - Browser: remote profile tab ops follow-up: shared Playwright loader, Playwright-based focus, and more coverage (incl. opt-in live Browserless test). (follow-up to #1057) — thanks @mukhtharcm. - Browser: refresh extension relay tab metadata after navigation so `/json/list` stays current. (#1073) — thanks @roshanasingh4. @@ -579,19 +659,19 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ## 2026.1.15 ### Highlights -- Plugins: add provider auth registry + `moltbot models auth login` for plugin-driven OAuth/API key flows. +- Plugins: add provider auth registry + `openclaw models auth login` for plugin-driven OAuth/API key flows. - Browser: improve remote CDP/Browserless support (auth passthrough, `wss` upgrade, timeouts, clearer errors). - Heartbeat: per-agent configuration + 24h duplicate suppression. (#980) — thanks @voidserf. - Security: audit warns on weak model tiers; app nodes store auth tokens encrypted (Keychain/SecurePrefs). ### Breaking - **BREAKING:** iOS minimum version is now 18.0 to support Textual markdown rendering in native chat. (#702) -- **BREAKING:** Microsoft Teams is now a plugin; install `@moltbot/msteams` via `moltbot plugins install @moltbot/msteams`. +- **BREAKING:** Microsoft Teams is now a plugin; install `@openclaw/msteams` via `openclaw plugins install @openclaw/msteams`. - **BREAKING:** Channel auth now prefers config over env for Discord/Telegram/Matrix (env is fallback only). (#1040) — thanks @thewilloftheshadow. ### Changes - UI/Apps: move channel/config settings to schema-driven forms and rename Connections → Channels. (#1040) — thanks @thewilloftheshadow. -- CLI: set process titles to `moltbot-` for clearer process listings. +- CLI: set process titles to `openclaw-` for clearer process listings. - CLI/macOS: sync remote SSH target/identity to config and let `gateway status` auto-infer SSH targets (ssh-config aware). - Telegram: scope inline buttons with allowlist default + callback gating in DMs/groups. - Telegram: default reaction notifications to own. @@ -599,13 +679,13 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Heartbeat: tighten prompt guidance + suppress duplicate alerts for 24h. (#980) — thanks @voidserf. - Repo: ignore local identity files to avoid accidental commits. (#1001) — thanks @gerardward2007. - Sessions/Security: add `session.dmScope` for multi-user DM isolation and audit warnings. (#948) — thanks @Alphonse-arianee. -- Plugins: add provider auth registry + `moltbot models auth login` for plugin-driven OAuth/API key flows. +- Plugins: add provider auth registry + `openclaw models auth login` for plugin-driven OAuth/API key flows. - Onboarding: switch channels setup to a single-select loop with per-channel actions and disabled hints in the picker. - TUI: show provider/model labels for the active session and default model. - Heartbeat: add per-agent heartbeat configuration and multi-agent docs example. - UI: show gateway auth guidance + doc link on unauthorized Control UI connections. - UI: add session deletion action in Control UI sessions list. (#1017) — thanks @Szpadel. -- Security: warn on weak model tiers (Haiku, below GPT-5, below Claude 4.5) in `moltbot security audit`. +- Security: warn on weak model tiers (Haiku, below GPT-5, below Claude 4.5) in `openclaw security audit`. - Apps: store node auth tokens encrypted (Keychain/SecurePrefs). - Daemon: share profile/state-dir resolution across service helpers and honor `CLAWDBOT_STATE_DIR` for Windows task scripts. - Docs: clarify multi-gateway rescue bot guidance. (#969) — thanks @bjesuiter. @@ -615,8 +695,8 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Docs: add Date & Time guide and update prompt/timezone configuration docs. - Messages: debounce rapid inbound messages across channels with per-connector overrides. (#971) — thanks @juanpablodlc. - Messages: allow media-only sends (CLI/tool) and show Telegram voice recording status for voice notes. (#957) — thanks @rdev. -- Auth/Status: keep auth profiles sticky per session (rotate on compaction/new), surface provider usage headers in `/status` and `moltbot models status`, and update docs. -- CLI: add `--json` output for `moltbot daemon` lifecycle/install commands. +- Auth/Status: keep auth profiles sticky per session (rotate on compaction/new), surface provider usage headers in `/status` and `openclaw models status`, and update docs. +- CLI: add `--json` output for `openclaw daemon` lifecycle/install commands. - Memory: make `node-llama-cpp` an optional dependency (avoid Node 25 install failures) and improve local-embeddings fallback/errors. - Browser: add `snapshot refs=aria` (Playwright aria-ref ids) for self-resolving refs across `snapshot` → `act`. - Browser: `profile="chrome"` now defaults to host control and returns clearer “attach a tab” errors. @@ -639,10 +719,10 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - iMessage: treat missing `imsg rpc` support as fatal to avoid restart loops. - Auth: merge main auth profiles into per-agent stores for sub-agents and document inheritance. (#1013) — thanks @marcmarg. - Agents: avoid JSON Schema `format` collisions in tool params by renaming snapshot format fields. (#1013) — thanks @marcmarg. -- Fix: make `moltbot update` auto-update global installs when installed via a package manager. +- Fix: make `openclaw update` auto-update global installs when installed via a package manager. - Fix: list model picker entries as provider/model pairs for explicit selection. (#970) — thanks @mcinteerj. - Fix: align OpenAI image-gen defaults with DALL-E 3 standard quality and document output formats. (#880) — thanks @mkbehr. -- Fix: persist `gateway.mode=local` after selecting Local run mode in `moltbot configure`, even if no other sections are chosen. +- Fix: persist `gateway.mode=local` after selecting Local run mode in `openclaw configure`, even if no other sections are chosen. - Daemon: fix profile-aware service label resolution (env-driven) and add coverage for launchd/systemd/schtasks. (#969) — thanks @bjesuiter. - Agents: avoid false positives when logging unsupported Google tool schema keywords. - Agents: skip Gemini history downgrades for google-antigravity to preserve tool calls. (#894) — thanks @mukhtharcm. @@ -668,13 +748,13 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Web search: `web_search`/`web_fetch` tools (Brave API) + first-time setup in onboarding/configure. - Browser control: Chrome extension relay takeover mode + remote browser control support. - Plugins: channel plugins (gateway HTTP hooks) + Zalo plugin + onboarding install flow. (#854) — thanks @longmaba. -- Security: expanded `moltbot security audit` (+ `--fix`), detect-secrets CI scan, and a `SECURITY.md` reporting policy. +- Security: expanded `openclaw security audit` (+ `--fix`), detect-secrets CI scan, and a `SECURITY.md` reporting policy. ### Changes - Docs: clarify per-agent auth stores, sandboxed skill binaries, and elevated semantics. - Docs: add FAQ entries for missing provider auth after adding agents and Gemini thinking signature errors. - Agents: add optional auth-profile copy prompt on `agents add` and improve auth error messaging. -- Security: expand `moltbot security audit` checks (model hygiene, config includes, plugin allowlists, exposure matrix) and extend `--fix` to tighten more sensitive state paths. +- Security: expand `openclaw security audit` checks (model hygiene, config includes, plugin allowlists, exposure matrix) and extend `--fix` to tighten more sensitive state paths. - Security: add `SECURITY.md` reporting policy. - Channels: add Matrix plugin (external) with docs + onboarding hooks. - Plugins: add Zalo channel plugin with gateway HTTP hooks and onboarding install prompt. (#854) — thanks @longmaba. @@ -684,7 +764,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Security: add detect-secrets CI scan and baseline guidance. (#227) — thanks @Hyaxia. - Tools: add `web_search`/`web_fetch` (Brave API), auto-enable `web_fetch` for sandboxed sessions, and remove the `brave-search` skill. - CLI/Docs: add a web tools configure section for storing Brave API keys and update onboarding tips. -- Browser: add Chrome extension relay takeover mode (toolbar button), plus `moltbot browser extension install/path` and remote browser control (standalone server + token auth). +- Browser: add Chrome extension relay takeover mode (toolbar button), plus `openclaw browser extension install/path` and remote browser control (standalone server + token auth). ### Fixes - Sessions: refactor session store updates to lock + mutate per-entry, add chat.inject, and harden subagent cleanup flow. (#944) — thanks @tyler6204. @@ -781,19 +861,19 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ### New & Improved - Memory: add custom OpenAI-compatible embedding endpoints; support OpenAI/local `node-llama-cpp` embeddings with per-agent overrides and provider metadata in tools/CLI. (#819) — thanks @mukhtharcm. -- Memory: new `moltbot memory` CLI plus `memory_search`/`memory_get` tools with snippets + line ranges; index stored under `~/.clawdbot/memory/{agentId}.sqlite` with watch-on-by-default. +- Memory: new `openclaw memory` CLI plus `memory_search`/`memory_get` tools with snippets + line ranges; index stored under `~/.clawdbot/memory/{agentId}.sqlite` with watch-on-by-default. - Agents: strengthen memory recall guidance; make workspace bootstrap truncation configurable (default 20k) with warnings; add default sub-agent model config. - Tools/Sandbox: add tool profiles + group shorthands; support tool-policy groups in `tools.sandbox.tools`; drop legacy `memory` shorthand; allow Docker bind mounts via `docker.binds`. (#790) — thanks @akonyer. - Tools: add provider/model-specific tool policy overrides (`tools.byProvider`) to trim tool exposure per provider. - Tools: add browser `scrollintoview` action; allow Claude/Gemini tool param aliases; allow thinking `xhigh` for GPT-5.2/Codex with safe downgrades. (#793) — thanks @hsrvc; (#444) — thanks @grp06. -- Gateway/CLI: add Tailscale binary discovery, custom bind mode, and probe auth retry; add `moltbot dashboard` auto-open flow; default native slash commands to `"auto"` with per-provider overrides. (#740) — thanks @jeffersonwarrior. +- Gateway/CLI: add Tailscale binary discovery, custom bind mode, and probe auth retry; add `openclaw dashboard` auto-open flow; default native slash commands to `"auto"` with per-provider overrides. (#740) — thanks @jeffersonwarrior. - Auth/Onboarding: add Chutes OAuth (PKCE + refresh + onboarding choice); normalize API key inputs; default TUI onboarding to `deliver: false`. (#726) — thanks @FrieSei; (#791) — thanks @roshanasingh4. - Providers: add `discord.allowBots`; trim legacy MiniMax M2 from default catalogs; route MiniMax vision to the Coding Plan VLM endpoint (also accepts `@/path/to/file.png` inputs). (#802) — thanks @zknicker. - Gateway: allow Tailscale Serve identity headers to satisfy token auth; rebuild Control UI assets when protocol schema is newer. (#823) — thanks @roshanasingh4; (#786) — thanks @meaningfool. - Heartbeat: default `ackMaxChars` to 300 so short `HEARTBEAT_OK` replies stay internal. ### Installer -- Install: run `moltbot doctor --non-interactive` after git installs/updates and nudge daemon restarts when detected. +- Install: run `openclaw doctor --non-interactive` after git installs/updates and nudge daemon restarts when detected. ### Fixes - Doctor: warn on pnpm workspace mismatches, missing Control UI assets, and missing tsx binaries; offer UI rebuilds. @@ -814,7 +894,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Telegram: preserve forum topic thread ids, persist polling offsets, respect account bindings in webhook mode, and show typing indicator in General topics. (#727, #739) — thanks @thewilloftheshadow; (#821) — thanks @gumadeiras; (#779) — thanks @azade-c. - Slack: accept slash commands with or without leading `/` for custom command configs. (#798) — thanks @thewilloftheshadow. - Cron: persist disabled jobs correctly; accept `jobId` aliases for update/run/remove params. (#205, #252) — thanks @thewilloftheshadow. -- Gateway/CLI: honor `CLAWDBOT_LAUNCHD_LABEL` / `CLAWDBOT_SYSTEMD_UNIT` overrides; `agents.list` respects explicit config; reduce noisy loopback WS logs during tests; run `moltbot doctor --non-interactive` during updates. (#781) — thanks @ronyrus. +- Gateway/CLI: honor `CLAWDBOT_LAUNCHD_LABEL` / `CLAWDBOT_SYSTEMD_UNIT` overrides; `agents.list` respects explicit config; reduce noisy loopback WS logs during tests; run `openclaw doctor --non-interactive` during updates. (#781) — thanks @ronyrus. - Onboarding/Control UI: refuse invalid configs (run doctor first); quote Windows browser URLs for OAuth; keep chat scroll position unless the user is near the bottom. (#764) — thanks @mukhtharcm; (#794) — thanks @roshanasingh4; (#217) — thanks @thewilloftheshadow. - Tools/UI: harden tool input schemas for strict providers; drop null-only union variants for Gemini schema cleanup; treat `maxChars: 0` as unlimited; keep TUI last streamed response instead of "(no output)". (#782) — thanks @AbhisekBasu1; (#796) — thanks @gabriel-trigo; (#747) — thanks @thewilloftheshadow. - Connections UI: polish multi-account account cards. (#816) — thanks @steipete. @@ -843,7 +923,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Auto-reply: add compact `/model` picker (models + available providers) and show provider endpoints in `/model status`. - Control UI: add Config tab model presets (MiniMax M2.1, GLM 4.7, Kimi) for one-click setup. - Plugins: add extension loader (tools/RPC/CLI/services), discovery paths, and config schema + Control UI labels (uiHints). -- Plugins: add `moltbot plugins install` (path/tgz/npm), plus `list|info|enable|disable|doctor` UX. +- Plugins: add `openclaw plugins install` (path/tgz/npm), plus `list|info|enable|disable|doctor` UX. - Plugins: voice-call plugin now real (Twilio/log), adds start/status RPC/CLI/tool + tests. - Docs: add plugins doc + cross-links from tools/skills/gateway config. - Docs: add beginner-friendly plugin quick start + expand Voice Call plugin docs. @@ -856,7 +936,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Agents: add pre-compaction memory flush config (`agents.defaults.compaction.*`) with a soft threshold + system prompt. - Config: add `$include` directive for modular config files. (#731) — thanks @pasogott. - Build: set pnpm minimum release age to 2880 minutes (2 days). (#718) — thanks @dan-dr. -- macOS: prompt to install the global `moltbot` CLI when missing in local mode; install via `molt.bot/install-cli.sh` (no onboarding) and use external launchd/CLI instead of the embedded gateway runtime. +- macOS: prompt to install the global `openclaw` CLI when missing in local mode; install via `openclaw.ai/install-cli.sh` (no onboarding) and use external launchd/CLI instead of the embedded gateway runtime. - Docs: add gog calendar event color IDs from `gog calendar colors`. (#715) — thanks @mjrussell. - Cron/CLI: add `--model` flag to cron add/edit commands. (#711) — thanks @mjrussell. - Cron/CLI: trim model overrides on cron edits and document main-session guidance. (#711) — thanks @mjrussell. @@ -870,7 +950,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ### Installer - Postinstall: replace `git apply` with builtin JS patcher (works npm/pnpm/bun; no git dependency) plus regression tests. - Postinstall: skip pnpm patch fallback when the new patcher is active. -- Installer tests: add root+non-root docker smokes, CI workflow to fetch molt.bot scripts and run install sh/cli with onboarding skipped. +- Installer tests: add root+non-root docker smokes, CI workflow to fetch openclaw.ai scripts and run install sh/cli with onboarding skipped. - Installer UX: support `CLAWDBOT_NO_ONBOARD=1` for non-interactive installs; fix npm prefix on Linux and auto-install git. - Installer UX: add `install.sh --help` with flags/env and git install hint. - Installer UX: add `--install-method git|npm` and auto-detect source checkouts (prompt to update git checkout vs migrate to npm). @@ -886,7 +966,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Auth: read Codex keychain credentials and make the lookup platform-aware. - macOS/Release: avoid bundling dist artifacts in relay builds and generate appcasts from zip-only sources. - Doctor: surface plugin diagnostics in the report. -- Plugins: treat `plugins.load.paths` directory entries as package roots when they contain `package.json` + `moltbot.extensions`; load plugin packages from config dirs; extract archives without system tar. +- Plugins: treat `plugins.load.paths` directory entries as package roots when they contain `package.json` + `openclaw.extensions`; load plugin packages from config dirs; extract archives without system tar. - Config: expand `~` in `CLAWDBOT_CONFIG_PATH` and common path-like config fields (including `plugins.load.paths`); guard invalid `$include` paths. (#731) — thanks @pasogott. - Agents: stop pre-creating session transcripts so first user messages persist in JSONL history. - Agents: skip pre-compaction memory flush when the session workspace is read-only. @@ -915,9 +995,9 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ## 2026.1.10 ### Highlights -- CLI: `moltbot status` now table-based + shows OS/update/gateway/daemon/agents/sessions; `status --all` adds a full read-only debug report (tables, log tails, Tailscale summary, and scan progress via OSC-9 + spinner). +- CLI: `openclaw status` now table-based + shows OS/update/gateway/daemon/agents/sessions; `status --all` adds a full read-only debug report (tables, log tails, Tailscale summary, and scan progress via OSC-9 + spinner). - CLI Backends: add Codex CLI fallback with resume support (text output) and JSONL parsing for new runs, plus a live CLI resume probe. -- CLI: add `moltbot update` (safe-ish git checkout update) + `--update` shorthand. (#673) — thanks @fm1randa. +- CLI: add `openclaw update` (safe-ish git checkout update) + `--update` shorthand. (#673) — thanks @fm1randa. - Gateway: add OpenAI-compatible `/v1/chat/completions` HTTP endpoint (auth, SSE streaming, per-agent routing). (#680). ### Changes @@ -927,7 +1007,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Agents/Browser: add `browser.target` (sandbox/host/custom) with sandbox host-control gating via `agents.defaults.sandbox.browser.allowHostControl`, allowlists for custom control URLs/hosts/ports, and expand browser tool docs (remote control, profiles, internals). - Onboarding/Models: add catalog-backed default model picker to onboarding + configure. (#611) — thanks @jonasjancarik. - Agents/OpenCode Zen: update fallback models + defaults, keep legacy alias mappings. (#669) — thanks @magimetal. -- CLI: add `moltbot reset` and `moltbot uninstall` flows (interactive + non-interactive) plus docker cleanup smoke test. +- CLI: add `openclaw reset` and `openclaw uninstall` flows (interactive + non-interactive) plus docker cleanup smoke test. - Providers: move provider wiring to a plugin architecture. (#661). - Providers: unify group history context wrappers across providers with per-provider/per-account `historyLimit` overrides (fallback to `messages.groupChat.historyLimit`). Set `0` to disable. (#672). - Gateway/Heartbeat: optionally deliver heartbeat `Reasoning:` output (`agents.defaults.heartbeat.includeReasoning`). (#690) @@ -936,7 +1016,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic ### Fixes - Auto-reply: suppress draft/typing streaming for `NO_REPLY` (silent system ops) so it doesn’t leak partial output. - CLI/Status: expand tables to full terminal width; clarify provider setup vs runtime warnings; richer per-provider detail; token previews in `status` while keeping `status --all` redacted; add troubleshooting link footer; keep log tails pasteable; show gateway auth used when reachable; surface provider runtime errors (Signal/iMessage/Slack); harden `tailscale status --json` parsing; make `status --all` scan progress determinate; and replace the footer with a 3-line “Next steps” recommendation (share/debug/probe). -- CLI/Gateway: clarify that `moltbot gateway status` reports RPC health (connect + RPC) and shows RPC failures separately from connect failures. +- CLI/Gateway: clarify that `openclaw gateway status` reports RPC health (connect + RPC) and shows RPC failures separately from connect failures. - CLI/Update: gate progress spinner on stdout TTY and align clean-check step label. (#701) — thanks @bjesuiter. - Telegram: add `/whoami` + `/id` commands to reveal sender id for allowlists; allow `@username` and prefixed ids in `allowFrom` prompts (with stability warning). - Heartbeat: strip markup-wrapped `HEARTBEAT_OK` so acks don’t leak to external providers (e.g., Telegram). @@ -949,7 +1029,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Agents/Pi: inject config `temperature`/`maxTokens` into streaming without replacing the session streamFn; cover with live maxTokens probe. (#732) — thanks @peschee. - macOS: clear unsigned launchd overrides on signed restarts and warn via doctor when attach-only/disable markers are set. (#695) — thanks @jeffersonwarrior. - Agents: enforce single-writer session locks and drop orphan tool results to prevent tool-call ID failures (MiniMax/Anthropic-compatible APIs). -- Docs: make `moltbot status` the first diagnostic step, clarify `status --deep` behavior, and document `/whoami` + `/id`. +- Docs: make `openclaw status` the first diagnostic step, clarify `status --deep` behavior, and document `/whoami` + `/id`. - Docs/Testing: clarify live tool+image probes and how to list your testable `provider/model` ids. - Tests/Live: make gateway bash+read probes resilient to provider formatting while still validating real tool calls. - WhatsApp: detect @lid mentions in groups using authDir reverse mapping + resolve self JID E.164 for mention gating. (#692) — thanks @peschee. @@ -969,7 +1049,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - WhatsApp: expose group participant IDs to the model so reactions can target the right sender. - Cron: `wakeMode: "now"` waits for heartbeat completion (and retries when the main lane is busy). (#666) — thanks @roshanasingh4. - Agents/OpenAI: fix Responses tool-only → follow-up turn handling (avoid standalone `reasoning` items that trigger 400 “required following item”) and replay reasoning items in Responses/Codex Responses history for tool-call-only turns. -- Sandbox: add `moltbot sandbox explain` (effective policy inspector + fix-it keys); improve “sandbox jail” tool-policy/elevated errors with actionable config key paths; link to docs. +- Sandbox: add `openclaw sandbox explain` (effective policy inspector + fix-it keys); improve “sandbox jail” tool-policy/elevated errors with actionable config key paths; link to docs. - Hooks/Gmail: keep Tailscale serve path at `/` while preserving the public path. (#668) — thanks @antons. - Hooks/Gmail: allow Tailscale target URLs to preserve internal serve paths. - Auth: update Claude Code keychain credentials in-place during refresh sync; share JSON file helpers; add CLI fallback coverage. @@ -981,12 +1061,12 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Gateway/Control UI: sniff image attachments for chat.send, drop non-images, and log mismatches. (#670) — thanks @cristip73. - macOS: force `restart-mac.sh --sign` to require identities and keep bundled Node signed for relay verification. (#580) — thanks @jeffersonwarrior. - Gateway/Agent: accept image attachments on `agent` (multimodal message) and add live gateway image probe (`CLAWDBOT_LIVE_GATEWAY_IMAGE_PROBE=1`). -- CLI: `moltbot sessions` now includes `elev:*` + `usage:*` flags in the table output. +- CLI: `openclaw sessions` now includes `elev:*` + `usage:*` flags in the table output. - CLI/Pairing: accept positional provider for `pairing list|approve` (npm-run compatible); update docs/bot hints. -- Branding: normalize legacy casing/branding to “Moltbot” (CLI, status, docs). +- Branding: normalize legacy casing/branding to “OpenClaw” (CLI, status, docs). - Auto-reply: fix native `/model` not updating the actual chat session (Telegram/Slack/Discord). (#646) -- Doctor: offer to run `moltbot update` first on git installs (keeps doctor output aligned with latest). -- Doctor: avoid false legacy workspace warning when install dir is `~/moltbot`. (#660) +- Doctor: offer to run `openclaw update` first on git installs (keeps doctor output aligned with latest). +- Doctor: avoid false legacy workspace warning when install dir is `~/openclaw`. (#660) - iMessage: fix reasoning persistence across DMs; avoid partial/duplicate replies when reasoning is enabled. (#655) — thanks @antons. - Models/Auth: allow MiniMax API configs without `models.providers.minimax.apiKey` (auth profiles / `MINIMAX_API_KEY`). (#656) — thanks @mneves75. - Agents: avoid duplicate replies when the message tool sends. (#659) — thanks @mickahouan. @@ -1017,12 +1097,12 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Control UI/TUI: queued messages, session links, reasoning view, mobile polish, logs UX. ### Breaking -- CLI: `moltbot message` now subcommands (`message send|poll|...`) and requires `--provider` unless only one provider configured. +- CLI: `openclaw message` now subcommands (`message send|poll|...`) and requires `--provider` unless only one provider configured. - Commands/Tools: `/restart` and gateway restart tool disabled by default; enable with `commands.restart=true`. ### New Features and Changes - Models/Auth: OpenCode Zen onboarding (#623) — thanks @magimetal; MiniMax Anthropic-compatible API + hosted onboarding (#590, #495) — thanks @mneves75, @tobiasbischoff. -- Models/Auth: setup-token + token auth profiles; `moltbot models auth order {get,set,clear}`; per-agent auth candidates in `/model status`; OAuth expiry checks in doctor/status. +- Models/Auth: setup-token + token auth profiles; `openclaw models auth order {get,set,clear}`; per-agent auth candidates in `/model status`; OAuth expiry checks in doctor/status. - Agent/System: claude-cli runner; `session_status` tool (and sandbox allow); adaptive context pruning default; system prompt messaging guidance + no auto self-update; eligible skills list injection; sub-agent context trimmed. - Commands: `/commands` list; `/models` alias; `/usage` alias; `/debug` runtime overrides + effective config view; `/config` chat updates + `/config get`; `config --section`. - CLI/Gateway: unified message tool + message subcommands; gateway discover (local + wide-area DNS-SD) with JSON/timeout; gateway status human-readable + JSON + SSH loopback; wide-area records include gatewayPort/sshPort/cliPath + tailnet DNS fallback. @@ -1080,7 +1160,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Previously, if you didn’t configure an allowlist, your bot could be **open to anyone** (especially discoverable Telegram bots). - New default: DM pairing (`dmPolicy="pairing"` / `discord.dm.policy="pairing"` / `slack.dm.policy="pairing"`). - To keep old “open to everyone” behavior: set `dmPolicy="open"` and include `"*"` in the relevant `allowFrom` (Discord/Slack: `discord.dm.allowFrom` / `slack.dm.allowFrom`). - - Approve requests via `moltbot pairing list ` + `moltbot pairing approve `. + - Approve requests via `openclaw pairing list ` + `openclaw pairing approve `. - Sandbox: default `agent.sandbox.scope` to `"agent"` (one container/workspace per agent). Use `"session"` for per-session isolation; `"shared"` disables cross-session isolation. - Timestamps in agent envelopes are now UTC (compact `YYYY-MM-DDTHH:mmZ`); removed `messages.timestampPrefix`. Add `agent.userTimezone` to tell the model the user’s local time (system prompt only). - Model config schema changes (auth profiles + model lists); doctor auto-migrates and the gateway rewrites legacy configs on startup. @@ -1094,7 +1174,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - **Agent loop + compaction:** compaction/pruning tuning, overflow handling, safer bootstrap context, and per-provider threading/confirmations; opt-in tool-result pruning + compact tracking. - **Sandbox + tools:** per-agent sandbox overrides, workspaceAccess controls, session tool visibility, tool policy overrides, process isolation, and tool schema/timeout/reaction unification. - **Providers (Telegram/WhatsApp/Discord/Slack/Signal/iMessage):** retry/backoff, threading, reactions, media groups/attachments, mention gating, typing behavior, and error/log stability; long polling + forum topic isolation for Telegram. -- **Gateway/CLI UX:** `moltbot logs`, cron list colors/aliases, docs search, agents list/add/delete flows, status usage snapshots, runtime/auth source display, and `/status`/commands auth unification. +- **Gateway/CLI UX:** `openclaw logs`, cron list colors/aliases, docs search, agents list/add/delete flows, status usage snapshots, runtime/auth source display, and `/status`/commands auth unification. - **Control UI/Web:** logs tab, focus mode polish, config form resilience, streaming stability, tool output caps, windowed chat history, and reconnect/password URL auth. - **macOS/Android/TUI/Build:** macOS gateway races, QR bundling, JSON5 config safety, Voice Wake hardening; Android EXIF rotation + APK naming/versioning; TUI key handling; tooling/bundling fixes. - **Packaging/compat:** npm dist folder coverage, Node 25 qrcode-terminal import fixes, Bun/Playwright/WebSocket patches, and Docker Bun install. @@ -1136,4 +1216,4 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic - Agent tools: honor `agent.tools` allow/deny policy even when sandbox is off. - Discord: avoid duplicate replies when OpenAI emits repeated `message_end` events. - Commands: unify /status (inline) and command auth across providers; group bypass for authorized control commands; remove Discord /clawd slash handler. -- CLI: run `moltbot agent` via the Gateway by default; use `--local` to force embedded mode. +- CLI: run `openclaw agent` via the Gateway by default; use `--local` to force embedded mode. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 509d5b11a2..777c723f97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,11 @@ -# Contributing to Moltbot +# Contributing to OpenClaw Welcome to the lobster tank! 🦞 ## Quick Links -- **GitHub:** https://github.com/moltbot/moltbot +- **GitHub:** https://github.com/openclaw/openclaw - **Discord:** https://discord.gg/qkhbAGHRBT -- **X/Twitter:** [@steipete](https://x.com/steipete) / [@moltbot](https://x.com/moltbot) +- **X/Twitter:** [@steipete](https://x.com/steipete) / [@openclaw](https://x.com/openclaw) ## Maintainers @@ -20,11 +20,11 @@ Welcome to the lobster tank! 🦞 ## How to Contribute 1. **Bugs & small fixes** → Open a PR! -2. **New features / architecture** → Start a [GitHub Discussion](https://github.com/moltbot/moltbot/discussions) or ask in Discord first +2. **New features / architecture** → Start a [GitHub Discussion](https://github.com/openclaw/openclaw/discussions) or ask in Discord first 3. **Questions** → Discord #setup-help ## Before You PR -- Test locally with your Moltbot instance +- Test locally with your OpenClaw instance - Run linter: `npm run lint` - Keep PRs focused (one thing per PR) - Describe what & why @@ -49,4 +49,4 @@ We are currently prioritizing: - **Skills**: Expanding the library of bundled skills and improving the Skill Creation developer experience. - **Performance**: Optimizing token usage and compaction logic. -Check the [GitHub Issues](https://github.com/moltbot/moltbot/issues) for "good first issue" labels! +Check the [GitHub Issues](https://github.com/openclaw/openclaw/issues) for "good first issue" labels! diff --git a/Dockerfile b/Dockerfile index 9c6aa7036c..904d1d97d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,10 +8,10 @@ RUN corepack enable WORKDIR /app -ARG CLAWDBOT_DOCKER_APT_PACKAGES="" -RUN if [ -n "$CLAWDBOT_DOCKER_APT_PACKAGES" ]; then \ +ARG OPENCLAW_DOCKER_APT_PACKAGES="" +RUN if [ -n "$OPENCLAW_DOCKER_APT_PACKAGES" ]; then \ apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $CLAWDBOT_DOCKER_APT_PACKAGES && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $OPENCLAW_DOCKER_APT_PACKAGES && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ fi @@ -24,9 +24,9 @@ COPY scripts ./scripts RUN pnpm install --frozen-lockfile COPY . . -RUN CLAWDBOT_A2UI_SKIP_MISSING=1 pnpm build +RUN OPENCLAW_A2UI_SKIP_MISSING=1 pnpm build # Force pnpm for UI build (Bun may fail on ARM/Synology architectures) -ENV CLAWDBOT_PREFER_PNPM=1 +ENV OPENCLAW_PREFER_PNPM=1 RUN pnpm ui:install RUN pnpm ui:build diff --git a/Dockerfile.sandbox-browser b/Dockerfile.sandbox-browser index 8d8a087016..05090881e8 100644 --- a/Dockerfile.sandbox-browser +++ b/Dockerfile.sandbox-browser @@ -20,9 +20,9 @@ RUN apt-get update \ xvfb \ && rm -rf /var/lib/apt/lists/* -COPY scripts/sandbox-browser-entrypoint.sh /usr/local/bin/moltbot-sandbox-browser -RUN chmod +x /usr/local/bin/moltbot-sandbox-browser +COPY scripts/sandbox-browser-entrypoint.sh /usr/local/bin/openclaw-sandbox-browser +RUN chmod +x /usr/local/bin/openclaw-sandbox-browser EXPOSE 9222 5900 6080 -CMD ["moltbot-sandbox-browser"] +CMD ["openclaw-sandbox-browser"] diff --git a/README.md b/README.md index ec970bb5b4..88857af42a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# 🦞 Moltbot — Personal AI Assistant +# 🦞 OpenClaw — Personal AI Assistant

- Clawdbot + OpenClaw

@@ -9,68 +9,67 @@

- CI status - GitHub release - DeepWiki + CI status + GitHub release + DeepWiki Discord MIT License

-**Moltbot** is a *personal AI assistant* you run on your own devices. +**OpenClaw** is a *personal AI assistant* you run on your own devices. It answers you on the channels you already use (WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, Microsoft Teams, WebChat), plus extension channels like BlueBubbles, Matrix, Zalo, and Zalo Personal. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant. If you want a personal, single-user assistant that feels local, fast, and always-on, this is it. -[Website](https://molt.bot) · [Docs](https://docs.molt.bot) · [Getting Started](https://docs.molt.bot/start/getting-started) · [Updating](https://docs.molt.bot/install/updating) · [Showcase](https://docs.molt.bot/start/showcase) · [FAQ](https://docs.molt.bot/start/faq) · [Wizard](https://docs.molt.bot/start/wizard) · [Nix](https://github.com/moltbot/nix-clawdbot) · [Docker](https://docs.molt.bot/install/docker) · [Discord](https://discord.gg/clawd) +[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/start/faq) · [Wizard](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-clawdbot) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd) -Preferred setup: run the onboarding wizard (`moltbot onboard`). It walks through gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**. +Preferred setup: run the onboarding wizard (`openclaw onboard`). It walks through gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**. Works with npm, pnpm, or bun. -New install? Start here: [Getting started](https://docs.molt.bot/start/getting-started) +New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started) **Subscriptions (OAuth):** - **[Anthropic](https://www.anthropic.com/)** (Claude Pro/Max) - **[OpenAI](https://openai.com/)** (ChatGPT/Codex) -Model note: while any model is supported, I strongly recommend **Anthropic Pro/Max (100/200) + Opus 4.5** for long‑context strength and better prompt‑injection resistance. See [Onboarding](https://docs.molt.bot/start/onboarding). +Model note: while any model is supported, I strongly recommend **Anthropic Pro/Max (100/200) + Opus 4.5** for long‑context strength and better prompt‑injection resistance. See [Onboarding](https://docs.openclaw.ai/start/onboarding). ## Models (selection + auth) -- Models config + CLI: [Models](https://docs.molt.bot/concepts/models) -- Auth profile rotation (OAuth vs API keys) + fallbacks: [Model failover](https://docs.molt.bot/concepts/model-failover) +- Models config + CLI: [Models](https://docs.openclaw.ai/concepts/models) +- Auth profile rotation (OAuth vs API keys) + fallbacks: [Model failover](https://docs.openclaw.ai/concepts/model-failover) ## Install (recommended) Runtime: **Node ≥22**. ```bash -npm install -g moltbot@latest -# or: pnpm add -g moltbot@latest +npm install -g openclaw@latest +# or: pnpm add -g openclaw@latest -moltbot onboard --install-daemon +openclaw onboard --install-daemon ``` The wizard installs the Gateway daemon (launchd/systemd user service) so it stays running. -Legacy note: `clawdbot` remains available as a compatibility shim. ## Quick start (TL;DR) Runtime: **Node ≥22**. -Full beginner guide (auth, pairing, channels): [Getting started](https://docs.molt.bot/start/getting-started) +Full beginner guide (auth, pairing, channels): [Getting started](https://docs.openclaw.ai/start/getting-started) ```bash -moltbot onboard --install-daemon +openclaw onboard --install-daemon -moltbot gateway --port 18789 --verbose +openclaw gateway --port 18789 --verbose # Send a message -moltbot message send --to +1234567890 --message "Hello from Moltbot" +openclaw message send --to +1234567890 --message "Hello from OpenClaw" # Talk to the assistant (optionally deliver back to any connected channel: WhatsApp/Telegram/Slack/Discord/Google Chat/Signal/iMessage/BlueBubbles/Microsoft Teams/Matrix/Zalo/Zalo Personal/WebChat) -moltbot agent --message "Ship checklist" --thinking high +openclaw agent --message "Ship checklist" --thinking high ``` -Upgrading? [Updating guide](https://docs.molt.bot/install/updating) (and run `moltbot doctor`). +Upgrading? [Updating guide](https://docs.openclaw.ai/install/updating) (and run `openclaw doctor`). ## Development channels @@ -78,94 +77,94 @@ Upgrading? [Updating guide](https://docs.molt.bot/install/updating) (and run `mo - **beta**: prerelease tags (`vYYYY.M.D-beta.N`), npm dist-tag `beta` (macOS app may be missing). - **dev**: moving head of `main`, npm dist-tag `dev` (when published). -Switch channels (git + npm): `moltbot update --channel stable|beta|dev`. -Details: [Development channels](https://docs.molt.bot/install/development-channels). +Switch channels (git + npm): `openclaw update --channel stable|beta|dev`. +Details: [Development channels](https://docs.openclaw.ai/install/development-channels). ## From source (development) Prefer `pnpm` for builds from source. Bun is optional for running TypeScript directly. ```bash -git clone https://github.com/moltbot/moltbot.git -cd moltbot +git clone https://github.com/openclaw/openclaw.git +cd openclaw pnpm install pnpm ui:build # auto-installs UI deps on first run pnpm build -pnpm moltbot onboard --install-daemon +pnpm openclaw onboard --install-daemon # Dev loop (auto-reload on TS changes) pnpm gateway:watch ``` -Note: `pnpm moltbot ...` runs TypeScript directly (via `tsx`). `pnpm build` produces `dist/` for running via Node / the packaged `moltbot` binary. +Note: `pnpm openclaw ...` runs TypeScript directly (via `tsx`). `pnpm build` produces `dist/` for running via Node / the packaged `openclaw` binary. ## Security defaults (DM access) -Moltbot connects to real messaging surfaces. Treat inbound DMs as **untrusted input**. +OpenClaw connects to real messaging surfaces. Treat inbound DMs as **untrusted input**. -Full security guide: [Security](https://docs.molt.bot/gateway/security) +Full security guide: [Security](https://docs.openclaw.ai/gateway/security) Default behavior on Telegram/WhatsApp/Signal/iMessage/Microsoft Teams/Discord/Google Chat/Slack: - **DM pairing** (`dmPolicy="pairing"` / `channels.discord.dm.policy="pairing"` / `channels.slack.dm.policy="pairing"`): unknown senders receive a short pairing code and the bot does not process their message. -- Approve with: `moltbot pairing approve ` (then the sender is added to a local allowlist store). +- Approve with: `openclaw pairing approve ` (then the sender is added to a local allowlist store). - Public inbound DMs require an explicit opt-in: set `dmPolicy="open"` and include `"*"` in the channel allowlist (`allowFrom` / `channels.discord.dm.allowFrom` / `channels.slack.dm.allowFrom`). -Run `moltbot doctor` to surface risky/misconfigured DM policies. +Run `openclaw doctor` to surface risky/misconfigured DM policies. ## Highlights -- **[Local-first Gateway](https://docs.molt.bot/gateway)** — single control plane for sessions, channels, tools, and events. -- **[Multi-channel inbox](https://docs.molt.bot/channels)** — WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, BlueBubbles, Microsoft Teams, Matrix, Zalo, Zalo Personal, WebChat, macOS, iOS/Android. -- **[Multi-agent routing](https://docs.molt.bot/gateway/configuration)** — route inbound channels/accounts/peers to isolated agents (workspaces + per-agent sessions). -- **[Voice Wake](https://docs.molt.bot/nodes/voicewake) + [Talk Mode](https://docs.molt.bot/nodes/talk)** — always-on speech for macOS/iOS/Android with ElevenLabs. -- **[Live Canvas](https://docs.molt.bot/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.molt.bot/platforms/mac/canvas#canvas-a2ui). -- **[First-class tools](https://docs.molt.bot/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions. -- **[Companion apps](https://docs.molt.bot/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.molt.bot/nodes). -- **[Onboarding](https://docs.molt.bot/start/wizard) + [skills](https://docs.molt.bot/tools/skills)** — wizard-driven setup with bundled/managed/workspace skills. +- **[Local-first Gateway](https://docs.openclaw.ai/gateway)** — single control plane for sessions, channels, tools, and events. +- **[Multi-channel inbox](https://docs.openclaw.ai/channels)** — WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, BlueBubbles, Microsoft Teams, Matrix, Zalo, Zalo Personal, WebChat, macOS, iOS/Android. +- **[Multi-agent routing](https://docs.openclaw.ai/gateway/configuration)** — route inbound channels/accounts/peers to isolated agents (workspaces + per-agent sessions). +- **[Voice Wake](https://docs.openclaw.ai/nodes/voicewake) + [Talk Mode](https://docs.openclaw.ai/nodes/talk)** — always-on speech for macOS/iOS/Android with ElevenLabs. +- **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui). +- **[First-class tools](https://docs.openclaw.ai/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions. +- **[Companion apps](https://docs.openclaw.ai/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.openclaw.ai/nodes). +- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — wizard-driven setup with bundled/managed/workspace skills. ## Star History -[![Star History Chart](https://api.star-history.com/svg?repos=moltbot/moltbot&type=date&legend=top-left)](https://www.star-history.com/#moltbot/moltbot&type=date&legend=top-left) +[![Star History Chart](https://api.star-history.com/svg?repos=openclaw/openclaw&type=date&legend=top-left)](https://www.star-history.com/#openclaw/openclaw&type=date&legend=top-left) ## Everything we built so far ### Core platform -- [Gateway WS control plane](https://docs.molt.bot/gateway) with sessions, presence, config, cron, webhooks, [Control UI](https://docs.molt.bot/web), and [Canvas host](https://docs.molt.bot/platforms/mac/canvas#canvas-a2ui). -- [CLI surface](https://docs.molt.bot/tools/agent-send): gateway, agent, send, [wizard](https://docs.molt.bot/start/wizard), and [doctor](https://docs.molt.bot/gateway/doctor). -- [Pi agent runtime](https://docs.molt.bot/concepts/agent) in RPC mode with tool streaming and block streaming. -- [Session model](https://docs.molt.bot/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.molt.bot/concepts/groups). -- [Media pipeline](https://docs.molt.bot/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.molt.bot/nodes/audio). +- [Gateway WS control plane](https://docs.openclaw.ai/gateway) with sessions, presence, config, cron, webhooks, [Control UI](https://docs.openclaw.ai/web), and [Canvas host](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui). +- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [wizard](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor). +- [Pi agent runtime](https://docs.openclaw.ai/concepts/agent) in RPC mode with tool streaming and block streaming. +- [Session model](https://docs.openclaw.ai/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.openclaw.ai/concepts/groups). +- [Media pipeline](https://docs.openclaw.ai/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.openclaw.ai/nodes/audio). ### Channels -- [Channels](https://docs.molt.bot/channels): [WhatsApp](https://docs.molt.bot/channels/whatsapp) (Baileys), [Telegram](https://docs.molt.bot/channels/telegram) (grammY), [Slack](https://docs.molt.bot/channels/slack) (Bolt), [Discord](https://docs.molt.bot/channels/discord) (discord.js), [Google Chat](https://docs.molt.bot/channels/googlechat) (Chat API), [Signal](https://docs.molt.bot/channels/signal) (signal-cli), [iMessage](https://docs.molt.bot/channels/imessage) (imsg), [BlueBubbles](https://docs.molt.bot/channels/bluebubbles) (extension), [Microsoft Teams](https://docs.molt.bot/channels/msteams) (extension), [Matrix](https://docs.molt.bot/channels/matrix) (extension), [Zalo](https://docs.molt.bot/channels/zalo) (extension), [Zalo Personal](https://docs.molt.bot/channels/zalouser) (extension), [WebChat](https://docs.molt.bot/web/webchat). -- [Group routing](https://docs.molt.bot/concepts/group-messages): mention gating, reply tags, per-channel chunking and routing. Channel rules: [Channels](https://docs.molt.bot/channels). +- [Channels](https://docs.openclaw.ai/channels): [WhatsApp](https://docs.openclaw.ai/channels/whatsapp) (Baileys), [Telegram](https://docs.openclaw.ai/channels/telegram) (grammY), [Slack](https://docs.openclaw.ai/channels/slack) (Bolt), [Discord](https://docs.openclaw.ai/channels/discord) (discord.js), [Google Chat](https://docs.openclaw.ai/channels/googlechat) (Chat API), [Signal](https://docs.openclaw.ai/channels/signal) (signal-cli), [iMessage](https://docs.openclaw.ai/channels/imessage) (imsg), [BlueBubbles](https://docs.openclaw.ai/channels/bluebubbles) (extension), [Microsoft Teams](https://docs.openclaw.ai/channels/msteams) (extension), [Matrix](https://docs.openclaw.ai/channels/matrix) (extension), [Zalo](https://docs.openclaw.ai/channels/zalo) (extension), [Zalo Personal](https://docs.openclaw.ai/channels/zalouser) (extension), [WebChat](https://docs.openclaw.ai/web/webchat). +- [Group routing](https://docs.openclaw.ai/concepts/group-messages): mention gating, reply tags, per-channel chunking and routing. Channel rules: [Channels](https://docs.openclaw.ai/channels). ### Apps + nodes -- [macOS app](https://docs.molt.bot/platforms/macos): menu bar control plane, [Voice Wake](https://docs.molt.bot/nodes/voicewake)/PTT, [Talk Mode](https://docs.molt.bot/nodes/talk) overlay, [WebChat](https://docs.molt.bot/web/webchat), debug tools, [remote gateway](https://docs.molt.bot/gateway/remote) control. -- [iOS node](https://docs.molt.bot/platforms/ios): [Canvas](https://docs.molt.bot/platforms/mac/canvas), [Voice Wake](https://docs.molt.bot/nodes/voicewake), [Talk Mode](https://docs.molt.bot/nodes/talk), camera, screen recording, Bonjour pairing. -- [Android node](https://docs.molt.bot/platforms/android): [Canvas](https://docs.molt.bot/platforms/mac/canvas), [Talk Mode](https://docs.molt.bot/nodes/talk), camera, screen recording, optional SMS. -- [macOS node mode](https://docs.molt.bot/nodes): system.run/notify + canvas/camera exposure. +- [macOS app](https://docs.openclaw.ai/platforms/macos): menu bar control plane, [Voice Wake](https://docs.openclaw.ai/nodes/voicewake)/PTT, [Talk Mode](https://docs.openclaw.ai/nodes/talk) overlay, [WebChat](https://docs.openclaw.ai/web/webchat), debug tools, [remote gateway](https://docs.openclaw.ai/gateway/remote) control. +- [iOS node](https://docs.openclaw.ai/platforms/ios): [Canvas](https://docs.openclaw.ai/platforms/mac/canvas), [Voice Wake](https://docs.openclaw.ai/nodes/voicewake), [Talk Mode](https://docs.openclaw.ai/nodes/talk), camera, screen recording, Bonjour pairing. +- [Android node](https://docs.openclaw.ai/platforms/android): [Canvas](https://docs.openclaw.ai/platforms/mac/canvas), [Talk Mode](https://docs.openclaw.ai/nodes/talk), camera, screen recording, optional SMS. +- [macOS node mode](https://docs.openclaw.ai/nodes): system.run/notify + canvas/camera exposure. ### Tools + automation -- [Browser control](https://docs.molt.bot/tools/browser): dedicated moltbot Chrome/Chromium, snapshots, actions, uploads, profiles. -- [Canvas](https://docs.molt.bot/platforms/mac/canvas): [A2UI](https://docs.molt.bot/platforms/mac/canvas#canvas-a2ui) push/reset, eval, snapshot. -- [Nodes](https://docs.molt.bot/nodes): camera snap/clip, screen record, [location.get](https://docs.molt.bot/nodes/location-command), notifications. -- [Cron + wakeups](https://docs.molt.bot/automation/cron-jobs); [webhooks](https://docs.molt.bot/automation/webhook); [Gmail Pub/Sub](https://docs.molt.bot/automation/gmail-pubsub). -- [Skills platform](https://docs.molt.bot/tools/skills): bundled, managed, and workspace skills with install gating + UI. +- [Browser control](https://docs.openclaw.ai/tools/browser): dedicated openclaw Chrome/Chromium, snapshots, actions, uploads, profiles. +- [Canvas](https://docs.openclaw.ai/platforms/mac/canvas): [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui) push/reset, eval, snapshot. +- [Nodes](https://docs.openclaw.ai/nodes): camera snap/clip, screen record, [location.get](https://docs.openclaw.ai/nodes/location-command), notifications. +- [Cron + wakeups](https://docs.openclaw.ai/automation/cron-jobs); [webhooks](https://docs.openclaw.ai/automation/webhook); [Gmail Pub/Sub](https://docs.openclaw.ai/automation/gmail-pubsub). +- [Skills platform](https://docs.openclaw.ai/tools/skills): bundled, managed, and workspace skills with install gating + UI. ### Runtime + safety -- [Channel routing](https://docs.molt.bot/concepts/channel-routing), [retry policy](https://docs.molt.bot/concepts/retry), and [streaming/chunking](https://docs.molt.bot/concepts/streaming). -- [Presence](https://docs.molt.bot/concepts/presence), [typing indicators](https://docs.molt.bot/concepts/typing-indicators), and [usage tracking](https://docs.molt.bot/concepts/usage-tracking). -- [Models](https://docs.molt.bot/concepts/models), [model failover](https://docs.molt.bot/concepts/model-failover), and [session pruning](https://docs.molt.bot/concepts/session-pruning). -- [Security](https://docs.molt.bot/gateway/security) and [troubleshooting](https://docs.molt.bot/channels/troubleshooting). +- [Channel routing](https://docs.openclaw.ai/concepts/channel-routing), [retry policy](https://docs.openclaw.ai/concepts/retry), and [streaming/chunking](https://docs.openclaw.ai/concepts/streaming). +- [Presence](https://docs.openclaw.ai/concepts/presence), [typing indicators](https://docs.openclaw.ai/concepts/typing-indicators), and [usage tracking](https://docs.openclaw.ai/concepts/usage-tracking). +- [Models](https://docs.openclaw.ai/concepts/models), [model failover](https://docs.openclaw.ai/concepts/model-failover), and [session pruning](https://docs.openclaw.ai/concepts/session-pruning). +- [Security](https://docs.openclaw.ai/gateway/security) and [troubleshooting](https://docs.openclaw.ai/channels/troubleshooting). ### Ops + packaging -- [Control UI](https://docs.molt.bot/web) + [WebChat](https://docs.molt.bot/web/webchat) served directly from the Gateway. -- [Tailscale Serve/Funnel](https://docs.molt.bot/gateway/tailscale) or [SSH tunnels](https://docs.molt.bot/gateway/remote) with token/password auth. -- [Nix mode](https://docs.molt.bot/install/nix) for declarative config; [Docker](https://docs.molt.bot/install/docker)-based installs. -- [Doctor](https://docs.molt.bot/gateway/doctor) migrations, [logging](https://docs.molt.bot/logging). +- [Control UI](https://docs.openclaw.ai/web) + [WebChat](https://docs.openclaw.ai/web/webchat) served directly from the Gateway. +- [Tailscale Serve/Funnel](https://docs.openclaw.ai/gateway/tailscale) or [SSH tunnels](https://docs.openclaw.ai/gateway/remote) with token/password auth. +- [Nix mode](https://docs.openclaw.ai/install/nix) for declarative config; [Docker](https://docs.openclaw.ai/install/docker)-based installs. +- [Doctor](https://docs.openclaw.ai/gateway/doctor) migrations, [logging](https://docs.openclaw.ai/logging). ## How it works (short) @@ -180,7 +179,7 @@ WhatsApp / Telegram / Slack / Discord / Google Chat / Signal / iMessage / BlueBu └──────────────┬────────────────┘ │ ├─ Pi agent (RPC) - ├─ CLI (moltbot …) + ├─ CLI (openclaw …) ├─ WebChat UI ├─ macOS app └─ iOS / Android nodes @@ -188,28 +187,28 @@ WhatsApp / Telegram / Slack / Discord / Google Chat / Signal / iMessage / BlueBu ## Key subsystems -- **[Gateway WebSocket network](https://docs.molt.bot/concepts/architecture)** — single WS control plane for clients, tools, and events (plus ops: [Gateway runbook](https://docs.molt.bot/gateway)). -- **[Tailscale exposure](https://docs.molt.bot/gateway/tailscale)** — Serve/Funnel for the Gateway dashboard + WS (remote access: [Remote](https://docs.molt.bot/gateway/remote)). -- **[Browser control](https://docs.molt.bot/tools/browser)** — moltbot‑managed Chrome/Chromium with CDP control. -- **[Canvas + A2UI](https://docs.molt.bot/platforms/mac/canvas)** — agent‑driven visual workspace (A2UI host: [Canvas/A2UI](https://docs.molt.bot/platforms/mac/canvas#canvas-a2ui)). -- **[Voice Wake](https://docs.molt.bot/nodes/voicewake) + [Talk Mode](https://docs.molt.bot/nodes/talk)** — always‑on speech and continuous conversation. -- **[Nodes](https://docs.molt.bot/nodes)** — Canvas, camera snap/clip, screen record, `location.get`, notifications, plus macOS‑only `system.run`/`system.notify`. +- **[Gateway WebSocket network](https://docs.openclaw.ai/concepts/architecture)** — single WS control plane for clients, tools, and events (plus ops: [Gateway runbook](https://docs.openclaw.ai/gateway)). +- **[Tailscale exposure](https://docs.openclaw.ai/gateway/tailscale)** — Serve/Funnel for the Gateway dashboard + WS (remote access: [Remote](https://docs.openclaw.ai/gateway/remote)). +- **[Browser control](https://docs.openclaw.ai/tools/browser)** — openclaw‑managed Chrome/Chromium with CDP control. +- **[Canvas + A2UI](https://docs.openclaw.ai/platforms/mac/canvas)** — agent‑driven visual workspace (A2UI host: [Canvas/A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui)). +- **[Voice Wake](https://docs.openclaw.ai/nodes/voicewake) + [Talk Mode](https://docs.openclaw.ai/nodes/talk)** — always‑on speech and continuous conversation. +- **[Nodes](https://docs.openclaw.ai/nodes)** — Canvas, camera snap/clip, screen record, `location.get`, notifications, plus macOS‑only `system.run`/`system.notify`. ## Tailscale access (Gateway dashboard) -Moltbot can auto-configure Tailscale **Serve** (tailnet-only) or **Funnel** (public) while the Gateway stays bound to loopback. Configure `gateway.tailscale.mode`: +OpenClaw can auto-configure Tailscale **Serve** (tailnet-only) or **Funnel** (public) while the Gateway stays bound to loopback. Configure `gateway.tailscale.mode`: - `off`: no Tailscale automation (default). - `serve`: tailnet-only HTTPS via `tailscale serve` (uses Tailscale identity headers by default). - `funnel`: public HTTPS via `tailscale funnel` (requires shared password auth). Notes: -- `gateway.bind` must stay `loopback` when Serve/Funnel is enabled (Moltbot enforces this). +- `gateway.bind` must stay `loopback` when Serve/Funnel is enabled (OpenClaw enforces this). - Serve can be forced to require a password by setting `gateway.auth.mode: "password"` or `gateway.auth.allowTailscale: false`. - Funnel refuses to start unless `gateway.auth.mode: "password"` is set. - Optional: `gateway.tailscale.resetOnExit` to undo Serve/Funnel on shutdown. -Details: [Tailscale guide](https://docs.molt.bot/gateway/tailscale) · [Web surfaces](https://docs.molt.bot/web) +Details: [Tailscale guide](https://docs.openclaw.ai/gateway/tailscale) · [Web surfaces](https://docs.openclaw.ai/web) ## Remote Gateway (Linux is great) @@ -219,7 +218,7 @@ It’s perfectly fine to run the Gateway on a small Linux instance. Clients (mac - **Device nodes** run device‑local actions (`system.run`, camera, screen recording, notifications) via `node.invoke`. In short: exec runs where the Gateway lives; device actions run where the device lives. -Details: [Remote access](https://docs.molt.bot/gateway/remote) · [Nodes](https://docs.molt.bot/nodes) · [Security](https://docs.molt.bot/gateway/security) +Details: [Remote access](https://docs.openclaw.ai/gateway/remote) · [Nodes](https://docs.openclaw.ai/nodes) · [Security](https://docs.openclaw.ai/gateway/security) ## macOS permissions via the Gateway protocol @@ -234,7 +233,7 @@ Elevated bash (host permissions) is separate from macOS TCC: - Use `/elevated on|off` to toggle per‑session elevated access when enabled + allowlisted. - Gateway persists the per‑session toggle via `sessions.patch` (WS method) alongside `thinkingLevel`, `verboseLevel`, `model`, `sendPolicy`, and `groupActivation`. -Details: [Nodes](https://docs.molt.bot/nodes) · [macOS app](https://docs.molt.bot/platforms/macos) · [Gateway protocol](https://docs.molt.bot/concepts/architecture) +Details: [Nodes](https://docs.openclaw.ai/nodes) · [macOS app](https://docs.openclaw.ai/platforms/macos) · [Gateway protocol](https://docs.openclaw.ai/concepts/architecture) ## Agent to Agent (sessions_* tools) @@ -243,7 +242,7 @@ Details: [Nodes](https://docs.molt.bot/nodes) · [macOS app](https://docs.molt.b - `sessions_history` — fetch transcript logs for a session. - `sessions_send` — message another session; optional reply‑back ping‑pong + announce step (`REPLY_SKIP`, `ANNOUNCE_SKIP`). -Details: [Session tools](https://docs.molt.bot/concepts/session-tool) +Details: [Session tools](https://docs.openclaw.ai/concepts/session-tool) ## Skills registry (ClawdHub) @@ -270,7 +269,7 @@ The Gateway alone delivers a great experience. All apps are optional and add ext If you plan to build/run companion apps, follow the platform runbooks below. -### macOS (Moltbot.app) (optional) +### macOS (OpenClaw.app) (optional) - Menu bar control for the Gateway and health. - Voice Wake + push-to-talk overlay. @@ -283,25 +282,25 @@ Note: signed builds required for macOS permissions to stick across rebuilds (see - Pairs as a node via the Bridge. - Voice trigger forwarding + Canvas surface. -- Controlled via `moltbot nodes …`. +- Controlled via `openclaw nodes …`. -Runbook: [iOS connect](https://docs.molt.bot/platforms/ios). +Runbook: [iOS connect](https://docs.openclaw.ai/platforms/ios). ### Android node (optional) - Pairs via the same Bridge + pairing flow as iOS. - Exposes Canvas, Camera, and Screen capture commands. -- Runbook: [Android connect](https://docs.molt.bot/platforms/android). +- Runbook: [Android connect](https://docs.openclaw.ai/platforms/android). ## Agent workspace + skills -- Workspace root: `~/clawd` (configurable via `agents.defaults.workspace`). +- Workspace root: `~/.openclaw/workspace` (configurable via `agents.defaults.workspace`). - Injected prompt files: `AGENTS.md`, `SOUL.md`, `TOOLS.md`. -- Skills: `~/clawd/skills//SKILL.md`. +- Skills: `~/.openclaw/workspace/skills//SKILL.md`. ## Configuration -Minimal `~/.clawdbot/moltbot.json` (model + defaults): +Minimal `~/.openclaw/openclaw.json` (model + defaults): ```json5 { @@ -311,7 +310,7 @@ Minimal `~/.clawdbot/moltbot.json` (model + defaults): } ``` -[Full configuration reference (all keys + examples).](https://docs.molt.bot/gateway/configuration) +[Full configuration reference (all keys + examples).](https://docs.openclaw.ai/gateway/configuration) ## Security model (important) @@ -319,15 +318,15 @@ Minimal `~/.clawdbot/moltbot.json` (model + defaults): - **Group/channel safety:** set `agents.defaults.sandbox.mode: "non-main"` to run **non‑main sessions** (groups/channels) inside per‑session Docker sandboxes; bash then runs in Docker for those sessions. - **Sandbox defaults:** allowlist `bash`, `process`, `read`, `write`, `edit`, `sessions_list`, `sessions_history`, `sessions_send`, `sessions_spawn`; denylist `browser`, `canvas`, `nodes`, `cron`, `discord`, `gateway`. -Details: [Security guide](https://docs.molt.bot/gateway/security) · [Docker + sandboxing](https://docs.molt.bot/install/docker) · [Sandbox config](https://docs.molt.bot/gateway/configuration) +Details: [Security guide](https://docs.openclaw.ai/gateway/security) · [Docker + sandboxing](https://docs.openclaw.ai/install/docker) · [Sandbox config](https://docs.openclaw.ai/gateway/configuration) -### [WhatsApp](https://docs.molt.bot/channels/whatsapp) +### [WhatsApp](https://docs.openclaw.ai/channels/whatsapp) -- Link the device: `pnpm moltbot channels login` (stores creds in `~/.clawdbot/credentials`). +- Link the device: `pnpm openclaw channels login` (stores creds in `~/.openclaw/credentials`). - Allowlist who can talk to the assistant via `channels.whatsapp.allowFrom`. - If `channels.whatsapp.groups` is set, it becomes a group allowlist; include `"*"` to allow all. -### [Telegram](https://docs.molt.bot/channels/telegram) +### [Telegram](https://docs.openclaw.ai/channels/telegram) - Set `TELEGRAM_BOT_TOKEN` or `channels.telegram.botToken` (env wins). - Optional: set `channels.telegram.groups` (with `channels.telegram.groups."*".requireMention`); when set, it is a group allowlist (include `"*"` to allow all). Also `channels.telegram.allowFrom` or `channels.telegram.webhookUrl` as needed. @@ -342,11 +341,11 @@ Details: [Security guide](https://docs.molt.bot/gateway/security) · [Docker + s } ``` -### [Slack](https://docs.molt.bot/channels/slack) +### [Slack](https://docs.openclaw.ai/channels/slack) - Set `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` (or `channels.slack.botToken` + `channels.slack.appToken`). -### [Discord](https://docs.molt.bot/channels/discord) +### [Discord](https://docs.openclaw.ai/channels/discord) - Set `DISCORD_BOT_TOKEN` or `channels.discord.token` (env wins). - Optional: set `commands.native`, `commands.text`, or `commands.useAccessGroups`, plus `channels.discord.dm.allowFrom`, `channels.discord.guilds`, or `channels.discord.mediaMaxMb` as needed. @@ -361,21 +360,21 @@ Details: [Security guide](https://docs.molt.bot/gateway/security) · [Docker + s } ``` -### [Signal](https://docs.molt.bot/channels/signal) +### [Signal](https://docs.openclaw.ai/channels/signal) - Requires `signal-cli` and a `channels.signal` config section. -### [iMessage](https://docs.molt.bot/channels/imessage) +### [iMessage](https://docs.openclaw.ai/channels/imessage) - macOS only; Messages must be signed in. - If `channels.imessage.groups` is set, it becomes a group allowlist; include `"*"` to allow all. -### [Microsoft Teams](https://docs.molt.bot/channels/msteams) +### [Microsoft Teams](https://docs.openclaw.ai/channels/msteams) - Configure a Teams app + Bot Framework, then add a `msteams` config section. - Allowlist who can talk via `msteams.allowFrom`; group access via `msteams.groupAllowFrom` or `msteams.groupPolicy: "open"`. -### [WebChat](https://docs.molt.bot/web/webchat) +### [WebChat](https://docs.openclaw.ai/web/webchat) - Uses the Gateway WebSocket; no separate WebChat port/config. @@ -393,79 +392,79 @@ Browser control (optional): ## Docs Use these when you’re past the onboarding flow and want the deeper reference. -- [Start with the docs index for navigation and “what’s where.”](https://docs.molt.bot) -- [Read the architecture overview for the gateway + protocol model.](https://docs.molt.bot/concepts/architecture) -- [Use the full configuration reference when you need every key and example.](https://docs.molt.bot/gateway/configuration) -- [Run the Gateway by the book with the operational runbook.](https://docs.molt.bot/gateway) -- [Learn how the Control UI/Web surfaces work and how to expose them safely.](https://docs.molt.bot/web) -- [Understand remote access over SSH tunnels or tailnets.](https://docs.molt.bot/gateway/remote) -- [Follow the onboarding wizard flow for a guided setup.](https://docs.molt.bot/start/wizard) -- [Wire external triggers via the webhook surface.](https://docs.molt.bot/automation/webhook) -- [Set up Gmail Pub/Sub triggers.](https://docs.molt.bot/automation/gmail-pubsub) -- [Learn the macOS menu bar companion details.](https://docs.molt.bot/platforms/mac/menu-bar) -- [Platform guides: Windows (WSL2)](https://docs.molt.bot/platforms/windows), [Linux](https://docs.molt.bot/platforms/linux), [macOS](https://docs.molt.bot/platforms/macos), [iOS](https://docs.molt.bot/platforms/ios), [Android](https://docs.molt.bot/platforms/android) -- [Debug common failures with the troubleshooting guide.](https://docs.molt.bot/channels/troubleshooting) -- [Review security guidance before exposing anything.](https://docs.molt.bot/gateway/security) +- [Start with the docs index for navigation and “what’s where.”](https://docs.openclaw.ai) +- [Read the architecture overview for the gateway + protocol model.](https://docs.openclaw.ai/concepts/architecture) +- [Use the full configuration reference when you need every key and example.](https://docs.openclaw.ai/gateway/configuration) +- [Run the Gateway by the book with the operational runbook.](https://docs.openclaw.ai/gateway) +- [Learn how the Control UI/Web surfaces work and how to expose them safely.](https://docs.openclaw.ai/web) +- [Understand remote access over SSH tunnels or tailnets.](https://docs.openclaw.ai/gateway/remote) +- [Follow the onboarding wizard flow for a guided setup.](https://docs.openclaw.ai/start/wizard) +- [Wire external triggers via the webhook surface.](https://docs.openclaw.ai/automation/webhook) +- [Set up Gmail Pub/Sub triggers.](https://docs.openclaw.ai/automation/gmail-pubsub) +- [Learn the macOS menu bar companion details.](https://docs.openclaw.ai/platforms/mac/menu-bar) +- [Platform guides: Windows (WSL2)](https://docs.openclaw.ai/platforms/windows), [Linux](https://docs.openclaw.ai/platforms/linux), [macOS](https://docs.openclaw.ai/platforms/macos), [iOS](https://docs.openclaw.ai/platforms/ios), [Android](https://docs.openclaw.ai/platforms/android) +- [Debug common failures with the troubleshooting guide.](https://docs.openclaw.ai/channels/troubleshooting) +- [Review security guidance before exposing anything.](https://docs.openclaw.ai/gateway/security) ## Advanced docs (discovery + control) -- [Discovery + transports](https://docs.molt.bot/gateway/discovery) -- [Bonjour/mDNS](https://docs.molt.bot/gateway/bonjour) -- [Gateway pairing](https://docs.molt.bot/gateway/pairing) -- [Remote gateway README](https://docs.molt.bot/gateway/remote-gateway-readme) -- [Control UI](https://docs.molt.bot/web/control-ui) -- [Dashboard](https://docs.molt.bot/web/dashboard) +- [Discovery + transports](https://docs.openclaw.ai/gateway/discovery) +- [Bonjour/mDNS](https://docs.openclaw.ai/gateway/bonjour) +- [Gateway pairing](https://docs.openclaw.ai/gateway/pairing) +- [Remote gateway README](https://docs.openclaw.ai/gateway/remote-gateway-readme) +- [Control UI](https://docs.openclaw.ai/web/control-ui) +- [Dashboard](https://docs.openclaw.ai/web/dashboard) ## Operations & troubleshooting -- [Health checks](https://docs.molt.bot/gateway/health) -- [Gateway lock](https://docs.molt.bot/gateway/gateway-lock) -- [Background process](https://docs.molt.bot/gateway/background-process) -- [Browser troubleshooting (Linux)](https://docs.molt.bot/tools/browser-linux-troubleshooting) -- [Logging](https://docs.molt.bot/logging) +- [Health checks](https://docs.openclaw.ai/gateway/health) +- [Gateway lock](https://docs.openclaw.ai/gateway/gateway-lock) +- [Background process](https://docs.openclaw.ai/gateway/background-process) +- [Browser troubleshooting (Linux)](https://docs.openclaw.ai/tools/browser-linux-troubleshooting) +- [Logging](https://docs.openclaw.ai/logging) ## Deep dives -- [Agent loop](https://docs.molt.bot/concepts/agent-loop) -- [Presence](https://docs.molt.bot/concepts/presence) -- [TypeBox schemas](https://docs.molt.bot/concepts/typebox) -- [RPC adapters](https://docs.molt.bot/reference/rpc) -- [Queue](https://docs.molt.bot/concepts/queue) +- [Agent loop](https://docs.openclaw.ai/concepts/agent-loop) +- [Presence](https://docs.openclaw.ai/concepts/presence) +- [TypeBox schemas](https://docs.openclaw.ai/concepts/typebox) +- [RPC adapters](https://docs.openclaw.ai/reference/rpc) +- [Queue](https://docs.openclaw.ai/concepts/queue) ## Workspace & skills -- [Skills config](https://docs.molt.bot/tools/skills-config) -- [Default AGENTS](https://docs.molt.bot/reference/AGENTS.default) -- [Templates: AGENTS](https://docs.molt.bot/reference/templates/AGENTS) -- [Templates: BOOTSTRAP](https://docs.molt.bot/reference/templates/BOOTSTRAP) -- [Templates: IDENTITY](https://docs.molt.bot/reference/templates/IDENTITY) -- [Templates: SOUL](https://docs.molt.bot/reference/templates/SOUL) -- [Templates: TOOLS](https://docs.molt.bot/reference/templates/TOOLS) -- [Templates: USER](https://docs.molt.bot/reference/templates/USER) +- [Skills config](https://docs.openclaw.ai/tools/skills-config) +- [Default AGENTS](https://docs.openclaw.ai/reference/AGENTS.default) +- [Templates: AGENTS](https://docs.openclaw.ai/reference/templates/AGENTS) +- [Templates: BOOTSTRAP](https://docs.openclaw.ai/reference/templates/BOOTSTRAP) +- [Templates: IDENTITY](https://docs.openclaw.ai/reference/templates/IDENTITY) +- [Templates: SOUL](https://docs.openclaw.ai/reference/templates/SOUL) +- [Templates: TOOLS](https://docs.openclaw.ai/reference/templates/TOOLS) +- [Templates: USER](https://docs.openclaw.ai/reference/templates/USER) ## Platform internals -- [macOS dev setup](https://docs.molt.bot/platforms/mac/dev-setup) -- [macOS menu bar](https://docs.molt.bot/platforms/mac/menu-bar) -- [macOS voice wake](https://docs.molt.bot/platforms/mac/voicewake) -- [iOS node](https://docs.molt.bot/platforms/ios) -- [Android node](https://docs.molt.bot/platforms/android) -- [Windows (WSL2)](https://docs.molt.bot/platforms/windows) -- [Linux app](https://docs.molt.bot/platforms/linux) +- [macOS dev setup](https://docs.openclaw.ai/platforms/mac/dev-setup) +- [macOS menu bar](https://docs.openclaw.ai/platforms/mac/menu-bar) +- [macOS voice wake](https://docs.openclaw.ai/platforms/mac/voicewake) +- [iOS node](https://docs.openclaw.ai/platforms/ios) +- [Android node](https://docs.openclaw.ai/platforms/android) +- [Windows (WSL2)](https://docs.openclaw.ai/platforms/windows) +- [Linux app](https://docs.openclaw.ai/platforms/linux) ## Email hooks (Gmail) -- [docs.molt.bot/gmail-pubsub](https://docs.molt.bot/automation/gmail-pubsub) +- [docs.openclaw.ai/gmail-pubsub](https://docs.openclaw.ai/automation/gmail-pubsub) ## Molty -Moltbot was built for **Molty**, a space lobster AI assistant. 🦞 +OpenClaw was built for **Molty**, a space lobster AI assistant. 🦞 by Peter Steinberger and the community. -- [clawd.me](https://clawd.me) +- [openclaw.ai](https://openclaw.ai) - [soul.md](https://soul.md) - [steipete.me](https://steipete.me) -- [@moltbot](https://x.com/moltbot) +- [@openclaw](https://x.com/openclaw) ## Community @@ -479,38 +478,38 @@ Thanks to all clawtributors:

steipete plum-dawg bohdanpodvirnyi iHildy jaydenfyi joaohlisboa mneves75 MatthieuBizien MaudeBot Glucksberg - rahthakor vrknetha radek-paclt vignesh07 joshp123 Tobias Bischoff czekaj mukhtharcm sebslight maxsumrall - xadenryan rodrigouroz juanpablodlc tyler6204 hsrvc magimetal zerone0x meaningfool patelhiren NicholasSpisak - jonisjongithub abhisekbasu1 jamesgroat claude JustYannicc SocialNerd42069 Mariano Belinky Hyaxia dantelex daveonkels - google-labs-jules[bot] lc0rp adam91holt mousberg hougangdev shakkernerd gumadeiras mteam88 hirefrank joeynyc - orlyjamie Eng. Juan Combetto dbhurley TSavo julianengel bradleypriest benithors rohannagpal elliotsecops timolins - benostein f-trycua nachx639 pvoo sreekaransrinath gupsammy cristip73 stefangalescu nachoiacovino Vasanth Rao Naik Sabavat + rahthakor vrknetha radek-paclt vignesh07 Tobias Bischoff joshp123 czekaj mukhtharcm sebslight maxsumrall + xadenryan rodrigouroz juanpablodlc hsrvc magimetal zerone0x tyler6204 meaningfool patelhiren NicholasSpisak + jonisjongithub abhisekbasu1 jamesgroat claude JustYannicc Mariano Belinky Hyaxia dantelex SocialNerd42069 daveonkels + google-labs-jules[bot] lc0rp mousberg adam91holt hougangdev shakkernerd gumadeiras mteam88 hirefrank joeynyc + orlyjamie dbhurley Eng. Juan Combetto TSavo julianengel bradleypriest benithors rohannagpal timolins f-trycua + benostein elliotsecops nachx639 pvoo sreekaransrinath gupsammy cristip73 stefangalescu nachoiacovino Vasanth Rao Naik Sabavat petter-b thewilloftheshadow cpojer scald andranik-sahakyan davidguttman sleontenko denysvitali sircrumpet peschee - rafaelreis-r nonggialiang dominicnunez lploc94 ratulsarna lutr0 kiranjd danielz1z AdeboyeDN Alg0rix - papago2355 emanuelst KristijanJovanovski CashWilliams rdev rhuanssauro osolmaz joshrad-dev adityashaw2 sheeek - ryancontent artuskg Takhoffman onutc pauloportella HirokiKobayashi-R neooriginal obviyus manuelhettich minghinmatthewlam - myfunc travisirby buddyh connorshea kyleok mcinteerj dependabot[bot] John-Rood timkrase uos-status - gerardward2007 roshanasingh4 tosh-hamburg azade-c dlauer JonUleis shivamraut101 bjesuiter cheeeee robbyczgw-cla - conroywhitney Josh Phillips YuriNachos pookNast Whoaa512 chriseidhof ngutman ysqander aj47 kennyklee - superman32432432 Yurii Chukhlib grp06 antons austinm911 blacksmith-sh[bot] damoahdominic dan-dr HeimdallStrategy imfing - jalehman jarvis-medmatic kkarimi mahmoudashraf93 pkrmf RandyVentures Ryan Lisse dougvk erikpr1994 fal3 - Ghost jonasjancarik Keith the Silly Goose L36 Server Marc mitschabaude-bot mkbehr neist sibbl chrisrodz - Friederike Seiler gabriel-trigo iamadig Jonathan D. Rhyne (DJ-D) Joshua Mitchell Kit koala73 manmal ogulcancelik pasogott - petradonka rubyrunsstuff siddhantjain suminhthanh svkozak VACInc wes-davis zats 24601 ameno- - Chris Taylor dguido Django Navarro evalexpr henrino3 humanwritten larlyssa Lukavyi odysseus0 oswalpalash - pcty-nextgen-service-account pi0 rmorse Roopak Nijhara Syhids Aaron Konyer aaronveklabs andreabadesso Andrii cash-echo-bot - Clawd ClawdFx EnzeD erik-agens Evizero fcatuhe itsjaydesu ivancasco ivanrvpereira Jarvis - jayhickey jeffersonwarrior jeffersonwarrior jverdi longmaba MarvinCui mickahouan mjrussell odnxe p6l-richard - philipp-spiess Pocket Clawd robaxelsen Sash Catanzarite Suksham-sharma T5-AndyML tewatia travisp VAC william arzt - zknicker 0oAstro abhaymundhara aduk059 alejandro maza Alex-Alaniz alexstyl andrewting19 anpoirier araa47 - arthyn Asleep123 bguidolim bolismauro chenyuan99 Chloe-VP Clawdbot Maintainers conhecendoia dasilva333 David-Marsh-Photo - Developer Dimitrios Ploutarchos Drake Thomsen dylanneve1 Felix Krause foeken frankekn ganghyun kim grrowl gtsifrikas - HazAT hrdwdmrbl hugobarauna Jamie Openshaw Jane Jarvis Deploy Jefferson Nunn jogi47 kentaro Kevin Lin - kira-ariaki kitze Kiwitwitter levifig Lloyd longjos loukotal louzhixian martinpucik Matt mini - mertcicekci0 Miles mrdbstn MSch Mustafa Tag Eldeen mylukin ndraiman nexty5870 Noctivoro ppamment - prathamdby ptn1411 reeltimeapps RLTCmpe Rolf Fredheim Rony Kelner Samrat Jha senoldogann Seredeep sergical - shiv19 shiyuanhai siraht snopoke techboss testingabc321 The Admiral thesash Ubuntu voidserf - Vultr-Clawd Admin Wimmie wolfred wstock YangHuang2280 yazinsai YiWang24 ymat19 Zach Knickerbocker zackerthescar - 0xJonHoldsCrypto aaronn Alphonse-arianee atalovesyou Azade carlulsoe ddyo Erik latitudeki5223 Manuel Maly - Mourad Boustani odrobnik pcty-nextgen-ios-builder Quentin Randy Torres rhjoh ronak-guliani William Stock + nonggialiang rafaelreis-r dominicnunez lploc94 ratulsarna lutr0 danielz1z AdeboyeDN Alg0rix papago2355 + emanuelst KristijanJovanovski rdev rhuanssauro joshrad-dev kiranjd osolmaz adityashaw2 CashWilliams sheeek + ryancontent artuskg Takhoffman onutc pauloportella neooriginal manuelhettich minghinmatthewlam myfunc travisirby + obviyus buddyh connorshea kyleok mcinteerj dependabot[bot] John-Rood timkrase uos-status gerardward2007 + roshanasingh4 tosh-hamburg azade-c dlauer JonUleis shivamraut101 bjesuiter cheeeee robbyczgw-cla Josh Phillips + YuriNachos pookNast Whoaa512 chriseidhof ngutman ysqander aj47 kennyklee superman32432432 Yurii Chukhlib + grp06 antons austinm911 blacksmith-sh[bot] damoahdominic dan-dr HeimdallStrategy imfing jalehman jarvis-medmatic + kkarimi mahmoudashraf93 pkrmf RandyVentures Ryan Lisse dougvk erikpr1994 fal3 Ghost jonasjancarik + Keith the Silly Goose L36 Server Marc mitschabaude-bot mkbehr neist sibbl chrisrodz Friederike Seiler gabriel-trigo + iamadig Jonathan D. Rhyne (DJ-D) Joshua Mitchell Kit koala73 manmal ogulcancelik pasogott petradonka rubyrunsstuff + siddhantjain suminhthanh svkozak VACInc wes-davis zats 24601 ameno- Chris Taylor dguido + Django Navarro evalexpr henrino3 humanwritten larlyssa Lukavyi odysseus0 oswalpalash pcty-nextgen-service-account pi0 + rmorse Roopak Nijhara Syhids Aaron Konyer aaronveklabs andreabadesso Andrii cash-echo-bot Clawd ClawdFx + EnzeD erik-agens Evizero fcatuhe itsjaydesu ivancasco ivanrvpereira Jarvis jayhickey jeffersonwarrior + jeffersonwarrior jverdi longmaba MarvinCui mickahouan mjrussell odnxe p6l-richard philipp-spiess Pocket Clawd + robaxelsen Sash Catanzarite Suksham-sharma T5-AndyML tewatia travisp VAC william arzt zknicker 0oAstro + abhaymundhara aduk059 alejandro maza Alex-Alaniz alexstyl andrewting19 anpoirier araa47 arthyn Asleep123 + bguidolim bolismauro chenyuan99 OpenClaw Maintainers conhecendoia dasilva333 David-Marsh-Photo Developer Dimitrios Ploutarchos Drake Thomsen + dylanneve1 Felix Krause foeken frankekn ganghyun kim grrowl gtsifrikas HazAT hrdwdmrbl hugobarauna + Jamie Openshaw Jane Jarvis Deploy Jefferson Nunn jogi47 kentaro Kevin Lin kira-ariaki kitze Kiwitwitter + levifig Lloyd longjos loukotal louzhixian martinpucik Matt mini mertcicekci0 Miles mrdbstn + MSch Mustafa Tag Eldeen ndraiman nexty5870 Noctivoro ppamment prathamdby ptn1411 reeltimeapps RLTCmpe + Rolf Fredheim Rony Kelner Samrat Jha senoldogann sergical shiv19 shiyuanhai siraht snopoke techboss + testingabc321 The Admiral thesash Ubuntu voidserf Vultr-Clawd Admin Wimmie wolfred wstock YangHuang2280 + yazinsai YiWang24 ymat19 Zach Knickerbocker zackerthescar 0xJonHoldsCrypto aaronn Alphonse-arianee atalovesyou Azade + carlulsoe ddyo Erik latitudeki5223 Manuel Maly Mourad Boustani odrobnik pcty-nextgen-ios-builder Quentin Randy Torres + rhjoh ronak-guliani William Stock

diff --git a/SECURITY.md b/SECURITY.md index 414def17f3..39ad03d749 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,6 @@ # Security Policy -If you believe you've found a security issue in Moltbot, please report it privately. +If you believe you've found a security issue in OpenClaw, please report it privately. ## Reporting @@ -9,19 +9,19 @@ If you believe you've found a security issue in Moltbot, please report it privat ## Operational Guidance -For threat model + hardening guidance (including `moltbot security audit --deep` and `--fix`), see: +For threat model + hardening guidance (including `openclaw security audit --deep` and `--fix`), see: -- `https://docs.molt.bot/gateway/security` +- `https://docs.openclaw.ai/gateway/security` ### Web Interface Safety -Moltbot's web interface is intended for local use only. Do **not** bind it to the public internet; it is not hardened for public exposure. +OpenClaw's web interface is intended for local use only. Do **not** bind it to the public internet; it is not hardened for public exposure. ## Runtime Requirements ### Node.js Version -Moltbot requires **Node.js 22.12.0 or later** (LTS). This version includes important security patches: +OpenClaw requires **Node.js 22.12.0 or later** (LTS). This version includes important security patches: - CVE-2025-59466: async_hooks DoS vulnerability - CVE-2026-21636: Permission model bypass vulnerability @@ -34,7 +34,7 @@ node --version # Should be v22.12.0 or later ### Docker Security -When running Moltbot in Docker: +When running OpenClaw in Docker: 1. The official image runs as a non-root user (`node`) for reduced attack surface 2. Use `--read-only` flag when possible for additional filesystem protection @@ -44,8 +44,8 @@ Example secure Docker run: ```bash docker run --read-only --cap-drop=ALL \ - -v moltbot-data:/app/data \ - moltbot/moltbot:latest + -v openclaw-data:/app/data \ + openclaw/openclaw:latest ``` ## Security Scanning diff --git a/Swabble/Package.resolved b/Swabble/Package.resolved index 24de6ea3a7..f52a51fbe5 100644 --- a/Swabble/Package.resolved +++ b/Swabble/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "c0677e232394b5f6b0191b6dbb5bae553d55264f65ae725cd03a8ffdfda9cdd3", + "originHash" : "24a723309d7a0039d3df3051106f77ac1ed7068a02508e3a6804e41d757e6c72", "pins" : [ { "identity" : "commander", @@ -10,6 +10,24 @@ "version" : "0.2.1" } }, + { + "identity" : "elevenlabskit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/steipete/ElevenLabsKit", + "state" : { + "revision" : "7e3c948d8340abe3977014f3de020edf221e9269", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "5a3825302b1a0d744183200915a47b508c828e6f", + "version" : "1.3.2" + } + }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", @@ -27,6 +45,24 @@ "revision" : "399f76dcd91e4c688ca2301fa24a8cc6d9927211", "version" : "0.99.0" } + }, + { + "identity" : "swiftui-math", + "kind" : "remoteSourceControl", + "location" : "https://github.com/gonzalezreal/swiftui-math", + "state" : { + "revision" : "0b5c2cfaaec8d6193db206f675048eeb5ce95f71", + "version" : "0.1.0" + } + }, + { + "identity" : "textual", + "kind" : "remoteSourceControl", + "location" : "https://github.com/gonzalezreal/textual", + "state" : { + "revision" : "5b06b811c0f5313b6b84bbef98c635a630638c38", + "version" : "0.3.1" + } } ], "version" : 3 diff --git a/appcast.xml b/appcast.xml index 568632fd76..2d9296655b 100644 --- a/appcast.xml +++ b/appcast.xml @@ -1,55 +1,55 @@ - Moltbot + OpenClaw 2026.1.24-1 Sun, 25 Jan 2026 14:05:25 +0000 - https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml + https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml 7952 2026.1.24-1 15.0 - Moltbot 2026.1.24-1 + OpenClaw 2026.1.24-1

Fixes

  • Packaging: include dist/shared output in npm tarball (fixes missing reasoning-tags import on install).
-

View full changelog

+

View full changelog

]]>
- +
2026.1.24 Sun, 25 Jan 2026 13:31:05 +0000 - https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml + https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml 7944 2026.1.24 15.0 - Moltbot 2026.1.24 + OpenClaw 2026.1.24

Highlights

    -
  • Providers: Ollama discovery + docs; Venice guide upgrades + cross-links. (#1606) Thanks @abhaymundhara. https://docs.molt.bot/providers/ollama https://docs.molt.bot/providers/venice
  • +
  • Providers: Ollama discovery + docs; Venice guide upgrades + cross-links. (#1606) Thanks @abhaymundhara. https://docs.openclaw.ai/providers/ollama https://docs.openclaw.ai/providers/venice
  • Channels: LINE plugin (Messaging API) with rich replies + quick replies. (#1630) Thanks @plum-dawg.
  • -
  • TTS: Edge fallback (keyless) + /tts auto modes. (#1668, #1667) Thanks @steipete, @sebslight. https://docs.molt.bot/tts
  • -
  • Exec approvals: approve in-chat via /approve across all channels (including plugins). (#1621) Thanks @czekaj. https://docs.molt.bot/tools/exec-approvals https://docs.molt.bot/tools/slash-commands
  • -
  • Telegram: DM topics as separate sessions + outbound link preview toggle. (#1597, #1700) Thanks @rohannagpal, @zerone0x. https://docs.molt.bot/channels/telegram
  • +
  • TTS: Edge fallback (keyless) + /tts auto modes. (#1668, #1667) Thanks @steipete, @sebslight. https://docs.openclaw.ai/tts
  • +
  • Exec approvals: approve in-chat via /approve across all channels (including plugins). (#1621) Thanks @czekaj. https://docs.openclaw.ai/tools/exec-approvals https://docs.openclaw.ai/tools/slash-commands
  • +
  • Telegram: DM topics as separate sessions + outbound link preview toggle. (#1597, #1700) Thanks @rohannagpal, @zerone0x. https://docs.openclaw.ai/channels/telegram

Changes

  • Channels: add LINE plugin (Messaging API) with rich replies, quick replies, and plugin HTTP registry. (#1630) Thanks @plum-dawg.
  • -
  • TTS: add Edge TTS provider fallback, defaulting to keyless Edge with MP3 retry on format failures. (#1668) Thanks @steipete. https://docs.molt.bot/tts
  • -
  • TTS: add auto mode enum (off/always/inbound/tagged) with per-session /tts override. (#1667) Thanks @sebslight. https://docs.molt.bot/tts
  • +
  • TTS: add Edge TTS provider fallback, defaulting to keyless Edge with MP3 retry on format failures. (#1668) Thanks @steipete. https://docs.openclaw.ai/tts
  • +
  • TTS: add auto mode enum (off/always/inbound/tagged) with per-session /tts override. (#1667) Thanks @sebslight. https://docs.openclaw.ai/tts
  • Telegram: treat DM topics as separate sessions and keep DM history limits stable with thread suffixes. (#1597) Thanks @rohannagpal.
  • -
  • Telegram: add channels.telegram.linkPreview to toggle outbound link previews. (#1700) Thanks @zerone0x. https://docs.molt.bot/channels/telegram
  • -
  • Web search: add Brave freshness filter parameter for time-scoped results. (#1688) Thanks @JonUleis. https://docs.molt.bot/tools/web
  • +
  • Telegram: add channels.telegram.linkPreview to toggle outbound link previews. (#1700) Thanks @zerone0x. https://docs.openclaw.ai/channels/telegram
  • +
  • Web search: add Brave freshness filter parameter for time-scoped results. (#1688) Thanks @JonUleis. https://docs.openclaw.ai/tools/web
  • UI: refresh Control UI dashboard design system (typography, colors, spacing). (#1786) Thanks @mousberg.
  • -
  • Exec approvals: forward approval prompts to chat with /approve for all channels (including plugins). (#1621) Thanks @czekaj. https://docs.molt.bot/tools/exec-approvals https://docs.molt.bot/tools/slash-commands
  • +
  • Exec approvals: forward approval prompts to chat with /approve for all channels (including plugins). (#1621) Thanks @czekaj. https://docs.openclaw.ai/tools/exec-approvals https://docs.openclaw.ai/tools/slash-commands
  • Gateway: expose config.patch in the gateway tool with safe partial updates + restart sentinel. (#1653) Thanks @Glucksberg.
  • -
  • Diagnostics: add diagnostic flags for targeted debug logs (config + env override). https://docs.molt.bot/diagnostics/flags
  • +
  • Diagnostics: add diagnostic flags for targeted debug logs (config + env override). https://docs.openclaw.ai/diagnostics/flags
  • Docs: expand FAQ (migration, scheduling, concurrency, model recommendations, OpenAI subscription auth, Pi sizing, hackable install, docs SSL workaround).
  • Docs: add verbose installer troubleshooting guidance.
  • Docs: add macOS VM guide with local/hosted options + VPS/nodes guidance. (#1693) Thanks @f-trycua.
  • -
  • Docs: add Bedrock EC2 instance role setup + IAM steps. (#1625) Thanks @sergical. https://docs.molt.bot/bedrock
  • +
  • Docs: add Bedrock EC2 instance role setup + IAM steps. (#1625) Thanks @sergical. https://docs.openclaw.ai/bedrock
  • Docs: update Fly.io guide notes.
  • Dev: add prek pre-commit hooks + dependabot config for weekly updates. (#1720) Thanks @dguido.
@@ -61,10 +61,10 @@
  • Web UI: hide internal message_id hints in chat bubbles.
  • Gateway: allow Control UI token-only auth to skip device pairing even when device identity is present (gateway.controlUi.allowInsecureAuth). (#1679) Thanks @steipete.
  • Matrix: decrypt E2EE media attachments with preflight size guard. (#1744) Thanks @araa47.
  • -
  • BlueBubbles: route phone-number targets to DMs, avoid leaking routing IDs, and auto-create missing DMs (Private API required). (#1751) Thanks @tyler6204. https://docs.molt.bot/channels/bluebubbles
  • +
  • BlueBubbles: route phone-number targets to DMs, avoid leaking routing IDs, and auto-create missing DMs (Private API required). (#1751) Thanks @tyler6204. https://docs.openclaw.ai/channels/bluebubbles
  • BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing.
  • Signal: repair reaction sends (group/UUID targets + CLI author flags). (#1651) Thanks @vilkasdev.
  • -
  • Signal: add configurable signal-cli startup timeout + external daemon mode docs. (#1677) https://docs.molt.bot/channels/signal
  • +
  • Signal: add configurable signal-cli startup timeout + external daemon mode docs. (#1677) https://docs.openclaw.ai/channels/signal
  • Telegram: set fetch duplex="half" for uploads on Node 22 to avoid sendPhoto failures. (#1684) Thanks @commdata2338.
  • Telegram: use wrapped fetch for long-polling on Node to normalize AbortSignal handling. (#1639)
  • Telegram: honor per-account proxy for outbound API calls. (#1774) Thanks @radek-paclt.
  • @@ -93,18 +93,18 @@
  • Tests: avoid fake-timer dependency in embedded runner stream mock to reduce CI flakes. (#1597) Thanks @rohannagpal.
  • Tests: increase embedded runner ordering test timeout to reduce CI flakes. (#1597) Thanks @rohannagpal.
  • -

    View full changelog

    +

    View full changelog

    ]]>
    - +
    2026.1.23 Sat, 24 Jan 2026 13:02:18 +0000 - https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml + https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml 7750 2026.1.23 15.0 - Moltbot 2026.1.23 + OpenClaw 2026.1.23

    Highlights

    • TTS: allow model-driven TTS tags by default for expressive audio replies (laughter, singing cues, etc.).
    • @@ -117,9 +117,9 @@
    • Browser: add node-host proxy auto-routing for remote gateways (configurable per gateway/node).
    • Heartbeat: add per-channel visibility controls (OK/alerts/indicator). (#1452) Thanks @dlauer.
    • Plugins: add optional llm-task JSON-only tool for workflows. (#1498) Thanks @vignesh07.
    • -
    • CLI: restart the gateway by default after moltbot update; add --no-restart to skip it.
    • -
    • CLI: add live auth probes to moltbot models status for per-profile verification.
    • -
    • CLI: add moltbot system for system events + heartbeat controls; remove standalone wake.
    • +
    • CLI: restart the gateway by default after openclaw update; add --no-restart to skip it.
    • +
    • CLI: add live auth probes to openclaw models status for per-profile verification.
    • +
    • CLI: add openclaw system for system events + heartbeat controls; remove standalone wake.
    • Agents: add Bedrock auto-discovery defaults + config overrides. (#1553) Thanks @fal3.
    • Docs: add cron vs heartbeat decision guide (with Lobster workflow notes). (#1533) Thanks @JustYannicc.
    • Docs: clarify HEARTBEAT.md empty file skips heartbeats, missing file still runs. (#1535) Thanks @JustYannicc.
    • @@ -154,10 +154,10 @@
    • Exec: honor tools.exec ask/security defaults for elevated approvals (avoid unwanted prompts).
    • TUI: forward unknown slash commands (for example, /context) to the Gateway.
    • TUI: include Gateway slash commands in autocomplete and /help.
    • -
    • CLI: skip usage lines in moltbot models status when provider usage is unavailable.
    • +
    • CLI: skip usage lines in openclaw models status when provider usage is unavailable.
    • CLI: suppress diagnostic session/run noise during auth probes.
    • CLI: hide auth probe timeout warnings from embedded runs.
    • -
    • CLI: render auth probe results as a table in moltbot models status.
    • +
    • CLI: render auth probe results as a table in openclaw models status.
    • CLI: suppress probe-only embedded logs unless --verbose is set.
    • CLI: move auth probe errors below the table to reduce wrapping.
    • CLI: prevent ANSI color bleed when table cells wrap.
    • @@ -180,9 +180,9 @@
    • Browser: keep extension relay tabs controllable when the extension reuses a session id after switching tabs. (#1160)
    • Agents: warn and ignore tool allowlists that only reference unknown or unloaded plugin tools. (#1566)
    -

    View full changelog

    +

    View full changelog

    ]]>
    - +
    \ No newline at end of file diff --git a/apps/android/README.md b/apps/android/README.md index ca09676437..c2ae5a2179 100644 --- a/apps/android/README.md +++ b/apps/android/README.md @@ -1,6 +1,6 @@ -## Clawdbot Node (Android) (internal) +## OpenClaw Node (Android) (internal) -Modern Android node app: connects to the **Gateway WebSocket** (`_clawdbot-gw._tcp`) and exposes **Canvas + Chat + Camera**. +Modern Android node app: connects to the **Gateway WebSocket** (`_openclaw-gw._tcp`) and exposes **Canvas + Chat + Camera**. Notes: - The node keeps the connection alive via a **foreground service** (persistent notification with a Disconnect action). @@ -25,7 +25,7 @@ cd apps/android 1) Start the gateway (on your “master” machine): ```bash -pnpm clawdbot gateway --port 18789 --verbose +pnpm openclaw gateway --port 18789 --verbose ``` 2) In the Android app: @@ -34,8 +34,8 @@ pnpm clawdbot gateway --port 18789 --verbose 3) Approve pairing (on the gateway machine): ```bash -clawdbot nodes pending -clawdbot nodes approve +openclaw nodes pending +openclaw nodes approve ``` More details: `docs/platforms/android.md`. diff --git a/apps/android/app/build.gradle.kts b/apps/android/app/build.gradle.kts index 97f9a250e4..31323942e0 100644 --- a/apps/android/app/build.gradle.kts +++ b/apps/android/app/build.gradle.kts @@ -8,17 +8,17 @@ plugins { } android { - namespace = "bot.molt.android" + namespace = "ai.openclaw.android" compileSdk = 36 sourceSets { getByName("main") { - assets.srcDir(file("../../shared/MoltbotKit/Sources/MoltbotKit/Resources")) + assets.srcDir(file("../../shared/OpenClawKit/Sources/OpenClawKit/Resources")) } } defaultConfig { - applicationId = "bot.molt.android" + applicationId = "ai.openclaw.android" minSdk = 31 targetSdk = 36 versionCode = 202601290 @@ -65,7 +65,7 @@ androidComponents { val versionName = output.versionName.orNull ?: "0" val buildType = variant.buildType - val outputFileName = "moltbot-${versionName}-${buildType}.apk" + val outputFileName = "openclaw-${versionName}-${buildType}.apk" output.outputFileName = outputFileName } } diff --git a/apps/android/app/src/main/AndroidManifest.xml b/apps/android/app/src/main/AndroidManifest.xml index e0aab841e0..bc0de1f87c 100644 --- a/apps/android/app/src/main/AndroidManifest.xml +++ b/apps/android/app/src/main/AndroidManifest.xml @@ -32,7 +32,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config" - android:theme="@style/Theme.MoltbotNode"> + android:theme="@style/Theme.OpenClawNode"> Quint(status, server, connected, voiceMode, voiceListening) }.collect { (status, server, connected, voiceMode, voiceListening) -> - val title = if (connected) "Moltbot Node · Connected" else "Moltbot Node" + val title = if (connected) "OpenClaw Node · Connected" else "OpenClaw Node" val voiceSuffix = if (voiceMode == VoiceWakeMode.Always) { if (voiceListening) " · Voice Wake: Listening" else " · Voice Wake: Paused" @@ -91,7 +91,7 @@ class NodeForegroundService : Service() { "Connection", NotificationManager.IMPORTANCE_LOW, ).apply { - description = "Moltbot node connection status" + description = "OpenClaw node connection status" setShowBadge(false) } mgr.createNotificationChannel(channel) @@ -163,7 +163,7 @@ class NodeForegroundService : Service() { private const val CHANNEL_ID = "connection" private const val NOTIFICATION_ID = 1 - private const val ACTION_STOP = "bot.molt.android.action.STOP" + private const val ACTION_STOP = "ai.openclaw.android.action.STOP" fun start(context: Context) { val intent = Intent(context, NodeForegroundService::class.java) diff --git a/apps/android/app/src/main/java/bot/molt/android/NodeRuntime.kt b/apps/android/app/src/main/java/ai/openclaw/android/NodeRuntime.kt similarity index 89% rename from apps/android/app/src/main/java/bot/molt/android/NodeRuntime.kt rename to apps/android/app/src/main/java/ai/openclaw/android/NodeRuntime.kt index 5fd429e9e0..e6ceae598d 100644 --- a/apps/android/app/src/main/java/bot/molt/android/NodeRuntime.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/NodeRuntime.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android import android.Manifest import android.content.Context @@ -7,35 +7,35 @@ import android.location.LocationManager import android.os.Build import android.os.SystemClock import androidx.core.content.ContextCompat -import bot.molt.android.chat.ChatController -import bot.molt.android.chat.ChatMessage -import bot.molt.android.chat.ChatPendingToolCall -import bot.molt.android.chat.ChatSessionEntry -import bot.molt.android.chat.OutgoingAttachment -import bot.molt.android.gateway.DeviceAuthStore -import bot.molt.android.gateway.DeviceIdentityStore -import bot.molt.android.gateway.GatewayClientInfo -import bot.molt.android.gateway.GatewayConnectOptions -import bot.molt.android.gateway.GatewayDiscovery -import bot.molt.android.gateway.GatewayEndpoint -import bot.molt.android.gateway.GatewaySession -import bot.molt.android.gateway.GatewayTlsParams -import bot.molt.android.node.CameraCaptureManager -import bot.molt.android.node.LocationCaptureManager -import bot.molt.android.BuildConfig -import bot.molt.android.node.CanvasController -import bot.molt.android.node.ScreenRecordManager -import bot.molt.android.node.SmsManager -import bot.molt.android.protocol.MoltbotCapability -import bot.molt.android.protocol.MoltbotCameraCommand -import bot.molt.android.protocol.MoltbotCanvasA2UIAction -import bot.molt.android.protocol.MoltbotCanvasA2UICommand -import bot.molt.android.protocol.MoltbotCanvasCommand -import bot.molt.android.protocol.MoltbotScreenCommand -import bot.molt.android.protocol.MoltbotLocationCommand -import bot.molt.android.protocol.MoltbotSmsCommand -import bot.molt.android.voice.TalkModeManager -import bot.molt.android.voice.VoiceWakeManager +import ai.openclaw.android.chat.ChatController +import ai.openclaw.android.chat.ChatMessage +import ai.openclaw.android.chat.ChatPendingToolCall +import ai.openclaw.android.chat.ChatSessionEntry +import ai.openclaw.android.chat.OutgoingAttachment +import ai.openclaw.android.gateway.DeviceAuthStore +import ai.openclaw.android.gateway.DeviceIdentityStore +import ai.openclaw.android.gateway.GatewayClientInfo +import ai.openclaw.android.gateway.GatewayConnectOptions +import ai.openclaw.android.gateway.GatewayDiscovery +import ai.openclaw.android.gateway.GatewayEndpoint +import ai.openclaw.android.gateway.GatewaySession +import ai.openclaw.android.gateway.GatewayTlsParams +import ai.openclaw.android.node.CameraCaptureManager +import ai.openclaw.android.node.LocationCaptureManager +import ai.openclaw.android.BuildConfig +import ai.openclaw.android.node.CanvasController +import ai.openclaw.android.node.ScreenRecordManager +import ai.openclaw.android.node.SmsManager +import ai.openclaw.android.protocol.OpenClawCapability +import ai.openclaw.android.protocol.OpenClawCameraCommand +import ai.openclaw.android.protocol.OpenClawCanvasA2UIAction +import ai.openclaw.android.protocol.OpenClawCanvasA2UICommand +import ai.openclaw.android.protocol.OpenClawCanvasCommand +import ai.openclaw.android.protocol.OpenClawScreenCommand +import ai.openclaw.android.protocol.OpenClawLocationCommand +import ai.openclaw.android.protocol.OpenClawSmsCommand +import ai.openclaw.android.voice.TalkModeManager +import ai.openclaw.android.voice.VoiceWakeManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -451,38 +451,38 @@ class NodeRuntime(context: Context) { private fun buildInvokeCommands(): List = buildList { - add(MoltbotCanvasCommand.Present.rawValue) - add(MoltbotCanvasCommand.Hide.rawValue) - add(MoltbotCanvasCommand.Navigate.rawValue) - add(MoltbotCanvasCommand.Eval.rawValue) - add(MoltbotCanvasCommand.Snapshot.rawValue) - add(MoltbotCanvasA2UICommand.Push.rawValue) - add(MoltbotCanvasA2UICommand.PushJSONL.rawValue) - add(MoltbotCanvasA2UICommand.Reset.rawValue) - add(MoltbotScreenCommand.Record.rawValue) + add(OpenClawCanvasCommand.Present.rawValue) + add(OpenClawCanvasCommand.Hide.rawValue) + add(OpenClawCanvasCommand.Navigate.rawValue) + add(OpenClawCanvasCommand.Eval.rawValue) + add(OpenClawCanvasCommand.Snapshot.rawValue) + add(OpenClawCanvasA2UICommand.Push.rawValue) + add(OpenClawCanvasA2UICommand.PushJSONL.rawValue) + add(OpenClawCanvasA2UICommand.Reset.rawValue) + add(OpenClawScreenCommand.Record.rawValue) if (cameraEnabled.value) { - add(MoltbotCameraCommand.Snap.rawValue) - add(MoltbotCameraCommand.Clip.rawValue) + add(OpenClawCameraCommand.Snap.rawValue) + add(OpenClawCameraCommand.Clip.rawValue) } if (locationMode.value != LocationMode.Off) { - add(MoltbotLocationCommand.Get.rawValue) + add(OpenClawLocationCommand.Get.rawValue) } if (sms.canSendSms()) { - add(MoltbotSmsCommand.Send.rawValue) + add(OpenClawSmsCommand.Send.rawValue) } } private fun buildCapabilities(): List = buildList { - add(MoltbotCapability.Canvas.rawValue) - add(MoltbotCapability.Screen.rawValue) - if (cameraEnabled.value) add(MoltbotCapability.Camera.rawValue) - if (sms.canSendSms()) add(MoltbotCapability.Sms.rawValue) + add(OpenClawCapability.Canvas.rawValue) + add(OpenClawCapability.Screen.rawValue) + if (cameraEnabled.value) add(OpenClawCapability.Camera.rawValue) + if (sms.canSendSms()) add(OpenClawCapability.Sms.rawValue) if (voiceWakeMode.value != VoiceWakeMode.Off && hasRecordAudioPermission()) { - add(MoltbotCapability.VoiceWake.rawValue) + add(OpenClawCapability.VoiceWake.rawValue) } if (locationMode.value != LocationMode.Off) { - add(MoltbotCapability.Location.rawValue) + add(OpenClawCapability.Location.rawValue) } } @@ -506,7 +506,7 @@ class NodeRuntime(context: Context) { val version = resolvedVersionName() val release = Build.VERSION.RELEASE?.trim().orEmpty() val releaseLabel = if (release.isEmpty()) "unknown" else release - return "MoltbotAndroid/$version (Android $releaseLabel; SDK ${Build.VERSION.SDK_INT})" + return "OpenClawAndroid/$version (Android $releaseLabel; SDK ${Build.VERSION.SDK_INT})" } private fun buildClientInfo(clientId: String, clientMode: String): GatewayClientInfo { @@ -529,7 +529,7 @@ class NodeRuntime(context: Context) { caps = buildCapabilities(), commands = buildInvokeCommands(), permissions = emptyMap(), - client = buildClientInfo(clientId = "moltbot-android", clientMode = "node"), + client = buildClientInfo(clientId = "openclaw-android", clientMode = "node"), userAgent = buildUserAgent(), ) } @@ -541,7 +541,7 @@ class NodeRuntime(context: Context) { caps = emptyList(), commands = emptyList(), permissions = emptyMap(), - client = buildClientInfo(clientId = "moltbot-control-ui", clientMode = "ui"), + client = buildClientInfo(clientId = "openclaw-control-ui", clientMode = "ui"), userAgent = buildUserAgent(), ) } @@ -665,7 +665,7 @@ class NodeRuntime(context: Context) { val actionId = (userActionObj["id"] as? JsonPrimitive)?.content?.trim().orEmpty().ifEmpty { java.util.UUID.randomUUID().toString() } - val name = MoltbotCanvasA2UIAction.extractActionName(userActionObj) ?: return@launch + val name = OpenClawCanvasA2UIAction.extractActionName(userActionObj) ?: return@launch val surfaceId = (userActionObj["surfaceId"] as? JsonPrimitive)?.content?.trim().orEmpty().ifEmpty { "main" } @@ -675,7 +675,7 @@ class NodeRuntime(context: Context) { val sessionKey = resolveMainSessionKey() val message = - MoltbotCanvasA2UIAction.formatAgentMessage( + OpenClawCanvasA2UIAction.formatAgentMessage( actionName = name, sessionKey = sessionKey, surfaceId = surfaceId, @@ -709,7 +709,7 @@ class NodeRuntime(context: Context) { try { canvas.eval( - MoltbotCanvasA2UIAction.jsDispatchA2UIActionStatus( + OpenClawCanvasA2UIAction.jsDispatchA2UIActionStatus( actionId = actionId, ok = connected && error == null, error = error, @@ -827,10 +827,10 @@ class NodeRuntime(context: Context) { private suspend fun handleInvoke(command: String, paramsJson: String?): GatewaySession.InvokeResult { if ( - command.startsWith(MoltbotCanvasCommand.NamespacePrefix) || - command.startsWith(MoltbotCanvasA2UICommand.NamespacePrefix) || - command.startsWith(MoltbotCameraCommand.NamespacePrefix) || - command.startsWith(MoltbotScreenCommand.NamespacePrefix) + command.startsWith(OpenClawCanvasCommand.NamespacePrefix) || + command.startsWith(OpenClawCanvasA2UICommand.NamespacePrefix) || + command.startsWith(OpenClawCameraCommand.NamespacePrefix) || + command.startsWith(OpenClawScreenCommand.NamespacePrefix) ) { if (!isForeground.value) { return GatewaySession.InvokeResult.error( @@ -839,13 +839,13 @@ class NodeRuntime(context: Context) { ) } } - if (command.startsWith(MoltbotCameraCommand.NamespacePrefix) && !cameraEnabled.value) { + if (command.startsWith(OpenClawCameraCommand.NamespacePrefix) && !cameraEnabled.value) { return GatewaySession.InvokeResult.error( code = "CAMERA_DISABLED", message = "CAMERA_DISABLED: enable Camera in Settings", ) } - if (command.startsWith(MoltbotLocationCommand.NamespacePrefix) && + if (command.startsWith(OpenClawLocationCommand.NamespacePrefix) && locationMode.value == LocationMode.Off ) { return GatewaySession.InvokeResult.error( @@ -855,18 +855,18 @@ class NodeRuntime(context: Context) { } return when (command) { - MoltbotCanvasCommand.Present.rawValue -> { + OpenClawCanvasCommand.Present.rawValue -> { val url = CanvasController.parseNavigateUrl(paramsJson) canvas.navigate(url) GatewaySession.InvokeResult.ok(null) } - MoltbotCanvasCommand.Hide.rawValue -> GatewaySession.InvokeResult.ok(null) - MoltbotCanvasCommand.Navigate.rawValue -> { + OpenClawCanvasCommand.Hide.rawValue -> GatewaySession.InvokeResult.ok(null) + OpenClawCanvasCommand.Navigate.rawValue -> { val url = CanvasController.parseNavigateUrl(paramsJson) canvas.navigate(url) GatewaySession.InvokeResult.ok(null) } - MoltbotCanvasCommand.Eval.rawValue -> { + OpenClawCanvasCommand.Eval.rawValue -> { val js = CanvasController.parseEvalJs(paramsJson) ?: return GatewaySession.InvokeResult.error( @@ -884,7 +884,7 @@ class NodeRuntime(context: Context) { } GatewaySession.InvokeResult.ok("""{"result":${result.toJsonString()}}""") } - MoltbotCanvasCommand.Snapshot.rawValue -> { + OpenClawCanvasCommand.Snapshot.rawValue -> { val snapshotParams = CanvasController.parseSnapshotParams(paramsJson) val base64 = try { @@ -901,7 +901,7 @@ class NodeRuntime(context: Context) { } GatewaySession.InvokeResult.ok("""{"format":"${snapshotParams.format.rawValue}","base64":"$base64"}""") } - MoltbotCanvasA2UICommand.Reset.rawValue -> { + OpenClawCanvasA2UICommand.Reset.rawValue -> { val a2uiUrl = resolveA2uiHostUrl() ?: return GatewaySession.InvokeResult.error( code = "A2UI_HOST_NOT_CONFIGURED", @@ -917,7 +917,7 @@ class NodeRuntime(context: Context) { val res = canvas.eval(a2uiResetJS) GatewaySession.InvokeResult.ok(res) } - MoltbotCanvasA2UICommand.Push.rawValue, MoltbotCanvasA2UICommand.PushJSONL.rawValue -> { + OpenClawCanvasA2UICommand.Push.rawValue, OpenClawCanvasA2UICommand.PushJSONL.rawValue -> { val messages = try { decodeA2uiMessages(command, paramsJson) @@ -940,7 +940,7 @@ class NodeRuntime(context: Context) { val res = canvas.eval(js) GatewaySession.InvokeResult.ok(res) } - MoltbotCameraCommand.Snap.rawValue -> { + OpenClawCameraCommand.Snap.rawValue -> { showCameraHud(message = "Taking photo…", kind = CameraHudKind.Photo) triggerCameraFlash() val res = @@ -954,7 +954,7 @@ class NodeRuntime(context: Context) { showCameraHud(message = "Photo captured", kind = CameraHudKind.Success, autoHideMs = 1600) GatewaySession.InvokeResult.ok(res.payloadJson) } - MoltbotCameraCommand.Clip.rawValue -> { + OpenClawCameraCommand.Clip.rawValue -> { val includeAudio = paramsJson?.contains("\"includeAudio\":true") != false if (includeAudio) externalAudioCaptureActive.value = true try { @@ -973,7 +973,7 @@ class NodeRuntime(context: Context) { if (includeAudio) externalAudioCaptureActive.value = false } } - MoltbotLocationCommand.Get.rawValue -> { + OpenClawLocationCommand.Get.rawValue -> { val mode = locationMode.value if (!isForeground.value && mode != LocationMode.Always) { return GatewaySession.InvokeResult.error( @@ -1026,7 +1026,7 @@ class NodeRuntime(context: Context) { GatewaySession.InvokeResult.error(code = "LOCATION_UNAVAILABLE", message = message) } } - MoltbotScreenCommand.Record.rawValue -> { + OpenClawScreenCommand.Record.rawValue -> { // Status pill mirrors screen recording state so it stays visible without overlay stacking. _screenRecordActive.value = true try { @@ -1042,7 +1042,7 @@ class NodeRuntime(context: Context) { _screenRecordActive.value = false } } - MoltbotSmsCommand.Send.rawValue -> { + OpenClawSmsCommand.Send.rawValue -> { val res = sms.send(paramsJson) if (res.ok) { GatewaySession.InvokeResult.ok(res.payloadJson) @@ -1115,7 +1115,7 @@ class NodeRuntime(context: Context) { val raw = if (nodeRaw.isNotBlank()) nodeRaw else operatorRaw if (raw.isBlank()) return null val base = raw.trimEnd('/') - return "${base}/__moltbot__/a2ui/?platform=android" + return "${base}/__openclaw__/a2ui/?platform=android" } private suspend fun ensureA2uiReady(a2uiUrl: String): Boolean { @@ -1150,7 +1150,7 @@ class NodeRuntime(context: Context) { val jsonlField = (obj["jsonl"] as? JsonPrimitive)?.content?.trim().orEmpty() val hasMessagesArray = obj["messages"] is JsonArray - if (command == MoltbotCanvasA2UICommand.PushJSONL.rawValue || (!hasMessagesArray && jsonlField.isNotBlank())) { + if (command == OpenClawCanvasA2UICommand.PushJSONL.rawValue || (!hasMessagesArray && jsonlField.isNotBlank())) { val jsonl = jsonlField if (jsonl.isBlank()) throw IllegalArgumentException("INVALID_REQUEST: jsonl required") val messages = @@ -1207,7 +1207,8 @@ private const val a2uiReadyCheckJS: String = """ (() => { try { - return !!globalThis.clawdbotA2UI && typeof globalThis.clawdbotA2UI.applyMessages === 'function'; + const host = globalThis.openclawA2UI; + return !!host && typeof host.applyMessages === 'function'; } catch (_) { return false; } @@ -1218,8 +1219,9 @@ private const val a2uiResetJS: String = """ (() => { try { - if (!globalThis.clawdbotA2UI) return { ok: false, error: "missing moltbotA2UI" }; - return globalThis.clawdbotA2UI.reset(); + const host = globalThis.openclawA2UI; + if (!host) return { ok: false, error: "missing openclawA2UI" }; + return host.reset(); } catch (e) { return { ok: false, error: String(e?.message ?? e) }; } @@ -1230,9 +1232,10 @@ private fun a2uiApplyMessagesJS(messagesJson: String): String { return """ (() => { try { - if (!globalThis.clawdbotA2UI) return { ok: false, error: "missing moltbotA2UI" }; + const host = globalThis.openclawA2UI; + if (!host) return { ok: false, error: "missing openclawA2UI" }; const messages = $messagesJson; - return globalThis.clawdbotA2UI.applyMessages(messages); + return host.applyMessages(messages); } catch (e) { return { ok: false, error: String(e?.message ?? e) }; } diff --git a/apps/android/app/src/main/java/bot/molt/android/PermissionRequester.kt b/apps/android/app/src/main/java/ai/openclaw/android/PermissionRequester.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/PermissionRequester.kt rename to apps/android/app/src/main/java/ai/openclaw/android/PermissionRequester.kt index 78ae0b62b1..0ee267b558 100644 --- a/apps/android/app/src/main/java/bot/molt/android/PermissionRequester.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/PermissionRequester.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android import android.content.pm.PackageManager import android.content.Intent @@ -115,7 +115,7 @@ class PermissionRequester(private val activity: ComponentActivity) { private fun buildRationaleMessage(permissions: List): String { val labels = permissions.map { permissionLabel(it) } - return "Moltbot needs ${labels.joinToString(", ")} permissions to continue." + return "OpenClaw needs ${labels.joinToString(", ")} permissions to continue." } private fun buildSettingsMessage(permissions: List): String { diff --git a/apps/android/app/src/main/java/bot/molt/android/ScreenCaptureRequester.kt b/apps/android/app/src/main/java/ai/openclaw/android/ScreenCaptureRequester.kt similarity index 95% rename from apps/android/app/src/main/java/bot/molt/android/ScreenCaptureRequester.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ScreenCaptureRequester.kt index 29d6620441..c215103b54 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ScreenCaptureRequester.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ScreenCaptureRequester.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android import android.app.Activity import android.content.Context @@ -55,7 +55,7 @@ class ScreenCaptureRequester(private val activity: ComponentActivity) { suspendCancellableCoroutine { cont -> AlertDialog.Builder(activity) .setTitle("Screen recording required") - .setMessage("Moltbot needs to record the screen for this command.") + .setMessage("OpenClaw needs to record the screen for this command.") .setPositiveButton("Continue") { _, _ -> cont.resume(true) } .setNegativeButton("Not now") { _, _ -> cont.resume(false) } .setOnCancelListener { cont.resume(false) } diff --git a/apps/android/app/src/main/java/bot/molt/android/SecurePrefs.kt b/apps/android/app/src/main/java/ai/openclaw/android/SecurePrefs.kt similarity index 79% rename from apps/android/app/src/main/java/bot/molt/android/SecurePrefs.kt rename to apps/android/app/src/main/java/ai/openclaw/android/SecurePrefs.kt index 7ee3294dc3..881d724fd1 100644 --- a/apps/android/app/src/main/java/bot/molt/android/SecurePrefs.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/SecurePrefs.kt @@ -1,8 +1,9 @@ @file:Suppress("DEPRECATION") -package bot.molt.android +package ai.openclaw.android import android.content.Context +import android.content.SharedPreferences import androidx.core.content.edit import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey @@ -16,11 +17,12 @@ import java.util.UUID class SecurePrefs(context: Context) { companion object { - val defaultWakeWords: List = listOf("clawd", "claude") + val defaultWakeWords: List = listOf("openclaw", "claude") private const val displayNameKey = "node.displayName" private const val voiceWakeModeKey = "voiceWake.mode" } + private val appContext = context.applicationContext private val json = Json { ignoreUnknownKeys = true } private val masterKey = @@ -28,14 +30,9 @@ class SecurePrefs(context: Context) { .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() - private val prefs = - EncryptedSharedPreferences.create( - context, - "moltbot.node.secure", - masterKey, - EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, - EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, - ) + private val prefs: SharedPreferences by lazy { + createPrefs(appContext, "openclaw.node.secure") + } private val _instanceId = MutableStateFlow(loadOrCreateInstanceId()) val instanceId: StateFlow = _instanceId @@ -59,28 +56,24 @@ class SecurePrefs(context: Context) { val preventSleep: StateFlow = _preventSleep private val _manualEnabled = - MutableStateFlow(readBoolWithMigration("gateway.manual.enabled", "bridge.manual.enabled", false)) + MutableStateFlow(prefs.getBoolean("gateway.manual.enabled", false)) val manualEnabled: StateFlow = _manualEnabled private val _manualHost = - MutableStateFlow(readStringWithMigration("gateway.manual.host", "bridge.manual.host", "")) + MutableStateFlow(prefs.getString("gateway.manual.host", "") ?: "") val manualHost: StateFlow = _manualHost private val _manualPort = - MutableStateFlow(readIntWithMigration("gateway.manual.port", "bridge.manual.port", 18789)) + MutableStateFlow(prefs.getInt("gateway.manual.port", 18789)) val manualPort: StateFlow = _manualPort private val _manualTls = - MutableStateFlow(readBoolWithMigration("gateway.manual.tls", null, true)) + MutableStateFlow(prefs.getBoolean("gateway.manual.tls", true)) val manualTls: StateFlow = _manualTls private val _lastDiscoveredStableId = MutableStateFlow( - readStringWithMigration( - "gateway.lastDiscoveredStableID", - "bridge.lastDiscoveredStableId", - "", - ), + prefs.getString("gateway.lastDiscoveredStableID", "") ?: "", ) val lastDiscoveredStableId: StateFlow = _lastDiscoveredStableId @@ -158,9 +151,7 @@ class SecurePrefs(context: Context) { fun loadGatewayToken(): String? { val key = "gateway.token.${_instanceId.value}" val stored = prefs.getString(key, null)?.trim() - if (!stored.isNullOrEmpty()) return stored - val legacy = prefs.getString("bridge.token.${_instanceId.value}", null)?.trim() - return legacy?.takeIf { it.isNotEmpty() } + return stored?.takeIf { it.isNotEmpty() } } fun saveGatewayToken(token: String) { @@ -201,6 +192,16 @@ class SecurePrefs(context: Context) { prefs.edit { remove(key) } } + private fun createPrefs(context: Context, name: String): SharedPreferences { + return EncryptedSharedPreferences.create( + context, + name, + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, + ) + } + private fun loadOrCreateInstanceId(): String { val existing = prefs.getString("node.instanceId", null)?.trim() if (!existing.isNullOrBlank()) return existing @@ -270,39 +271,4 @@ class SecurePrefs(context: Context) { } } - private fun readBoolWithMigration(newKey: String, oldKey: String?, defaultValue: Boolean): Boolean { - if (prefs.contains(newKey)) { - return prefs.getBoolean(newKey, defaultValue) - } - if (oldKey != null && prefs.contains(oldKey)) { - val value = prefs.getBoolean(oldKey, defaultValue) - prefs.edit { putBoolean(newKey, value) } - return value - } - return defaultValue - } - - private fun readStringWithMigration(newKey: String, oldKey: String?, defaultValue: String): String { - if (prefs.contains(newKey)) { - return prefs.getString(newKey, defaultValue) ?: defaultValue - } - if (oldKey != null && prefs.contains(oldKey)) { - val value = prefs.getString(oldKey, defaultValue) ?: defaultValue - prefs.edit { putString(newKey, value) } - return value - } - return defaultValue - } - - private fun readIntWithMigration(newKey: String, oldKey: String?, defaultValue: Int): Int { - if (prefs.contains(newKey)) { - return prefs.getInt(newKey, defaultValue) - } - if (oldKey != null && prefs.contains(oldKey)) { - val value = prefs.getInt(oldKey, defaultValue) - prefs.edit { putInt(newKey, value) } - return value - } - return defaultValue - } } diff --git a/apps/android/app/src/main/java/bot/molt/android/SessionKey.kt b/apps/android/app/src/main/java/ai/openclaw/android/SessionKey.kt similarity index 92% rename from apps/android/app/src/main/java/bot/molt/android/SessionKey.kt rename to apps/android/app/src/main/java/ai/openclaw/android/SessionKey.kt index e640516495..8148a17029 100644 --- a/apps/android/app/src/main/java/bot/molt/android/SessionKey.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/SessionKey.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android internal fun normalizeMainKey(raw: String?): String { val trimmed = raw?.trim() diff --git a/apps/android/app/src/main/java/bot/molt/android/VoiceWakeMode.kt b/apps/android/app/src/main/java/ai/openclaw/android/VoiceWakeMode.kt similarity index 91% rename from apps/android/app/src/main/java/bot/molt/android/VoiceWakeMode.kt rename to apps/android/app/src/main/java/ai/openclaw/android/VoiceWakeMode.kt index e0862cc25d..75c2fe3446 100644 --- a/apps/android/app/src/main/java/bot/molt/android/VoiceWakeMode.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/VoiceWakeMode.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android enum class VoiceWakeMode(val rawValue: String) { Off("off"), diff --git a/apps/android/app/src/main/java/bot/molt/android/WakeWords.kt b/apps/android/app/src/main/java/ai/openclaw/android/WakeWords.kt similarity index 95% rename from apps/android/app/src/main/java/bot/molt/android/WakeWords.kt rename to apps/android/app/src/main/java/ai/openclaw/android/WakeWords.kt index 56b85a5df9..b64cb1dd74 100644 --- a/apps/android/app/src/main/java/bot/molt/android/WakeWords.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/WakeWords.kt @@ -1,4 +1,4 @@ -package bot.molt.android +package ai.openclaw.android object WakeWords { const val maxWords: Int = 32 diff --git a/apps/android/app/src/main/java/bot/molt/android/chat/ChatController.kt b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/chat/ChatController.kt rename to apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt index eef66fece4..3ed69ee5b2 100644 --- a/apps/android/app/src/main/java/bot/molt/android/chat/ChatController.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatController.kt @@ -1,6 +1,6 @@ -package bot.molt.android.chat +package ai.openclaw.android.chat -import bot.molt.android.gateway.GatewaySession +import ai.openclaw.android.gateway.GatewaySession import java.util.UUID import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.CoroutineScope diff --git a/apps/android/app/src/main/java/bot/molt/android/chat/ChatModels.kt b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatModels.kt similarity index 96% rename from apps/android/app/src/main/java/bot/molt/android/chat/ChatModels.kt rename to apps/android/app/src/main/java/ai/openclaw/android/chat/ChatModels.kt index 3406244521..dd17a8c1ae 100644 --- a/apps/android/app/src/main/java/bot/molt/android/chat/ChatModels.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/chat/ChatModels.kt @@ -1,4 +1,4 @@ -package bot.molt.android.chat +package ai.openclaw.android.chat data class ChatMessage( val id: String, diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/BonjourEscapes.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/BonjourEscapes.kt similarity index 96% rename from apps/android/app/src/main/java/bot/molt/android/gateway/BonjourEscapes.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/BonjourEscapes.kt index 2c0c34d68e..1606df79ec 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/BonjourEscapes.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/BonjourEscapes.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway object BonjourEscapes { fun decode(input: String): String { diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/DeviceAuthStore.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceAuthStore.kt similarity index 90% rename from apps/android/app/src/main/java/bot/molt/android/gateway/DeviceAuthStore.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceAuthStore.kt index 6b90b46729..810e029fba 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/DeviceAuthStore.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceAuthStore.kt @@ -1,6 +1,6 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway -import bot.molt.android.SecurePrefs +import ai.openclaw.android.SecurePrefs class DeviceAuthStore(private val prefs: SecurePrefs) { fun loadToken(deviceId: String, role: String): String? { diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/DeviceIdentityStore.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceIdentityStore.kt similarity index 93% rename from apps/android/app/src/main/java/bot/molt/android/gateway/DeviceIdentityStore.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceIdentityStore.kt index 58a0acefff..accbb79e4d 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/DeviceIdentityStore.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/DeviceIdentityStore.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway import android.content.Context import android.util.Base64 @@ -21,7 +21,7 @@ data class DeviceIdentity( class DeviceIdentityStore(context: Context) { private val json = Json { ignoreUnknownKeys = true } - private val identityFile = File(context.filesDir, "moltbot/identity/device.json") + private val identityFile = File(context.filesDir, "openclaw/identity/device.json") @Synchronized fun loadOrCreate(): DeviceIdentity { @@ -65,9 +65,13 @@ class DeviceIdentityStore(context: Context) { } private fun load(): DeviceIdentity? { + return readIdentity(identityFile) + } + + private fun readIdentity(file: File): DeviceIdentity? { return try { - if (!identityFile.exists()) return null - val raw = identityFile.readText(Charsets.UTF_8) + if (!file.exists()) return null + val raw = file.readText(Charsets.UTF_8) val decoded = json.decodeFromString(DeviceIdentity.serializer(), raw) if (decoded.deviceId.isBlank() || decoded.publicKeyRawBase64.isBlank() || diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayDiscovery.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayDiscovery.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/gateway/GatewayDiscovery.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayDiscovery.kt index 53bdb5588a..2ad8ec0cb1 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayDiscovery.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayDiscovery.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway import android.content.Context import android.net.ConnectivityManager @@ -51,9 +51,9 @@ class GatewayDiscovery( private val nsd = context.getSystemService(NsdManager::class.java) private val connectivity = context.getSystemService(ConnectivityManager::class.java) private val dns = DnsResolver.getInstance() - private val serviceType = "_moltbot-gw._tcp." - private val wideAreaDomain = "moltbot.internal." - private val logTag = "Moltbot/GatewayDiscovery" + private val serviceType = "_openclaw-gw._tcp." + private val wideAreaDomain = System.getenv("OPENCLAW_WIDE_AREA_DOMAIN") + private val logTag = "OpenClaw/GatewayDiscovery" private val localById = ConcurrentHashMap() private val unicastById = ConcurrentHashMap() @@ -91,7 +91,9 @@ class GatewayDiscovery( init { startLocalDiscovery() - startUnicastDiscovery(wideAreaDomain) + if (!wideAreaDomain.isNullOrBlank()) { + startUnicastDiscovery(wideAreaDomain) + } } private fun startLocalDiscovery() { diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayEndpoint.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayEndpoint.kt similarity index 94% rename from apps/android/app/src/main/java/bot/molt/android/gateway/GatewayEndpoint.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayEndpoint.kt index 2c524cc679..9a30106028 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayEndpoint.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayEndpoint.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway data class GatewayEndpoint( val stableId: String, diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayProtocol.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayProtocol.kt similarity index 52% rename from apps/android/app/src/main/java/bot/molt/android/gateway/GatewayProtocol.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayProtocol.kt index 6836331be7..da8fa4c693 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayProtocol.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayProtocol.kt @@ -1,3 +1,3 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway const val GATEWAY_PROTOCOL_VERSION = 3 diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewaySession.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewaySession.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/gateway/GatewaySession.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewaySession.kt index 13074b9188..a8979d2e52 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewaySession.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewaySession.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway import android.util.Log import java.util.Locale @@ -148,7 +148,7 @@ class GatewaySession( try { conn.request("node.event", params, timeoutMs = 8_000) } catch (err: Throwable) { - Log.w("MoltbotGateway", "node.event failed: ${err.message ?: err::class.java.simpleName}") + Log.w("OpenClawGateway", "node.event failed: ${err.message ?: err::class.java.simpleName}") } } @@ -181,7 +181,7 @@ class GatewaySession( private val connectNonceDeferred = CompletableDeferred() private val client: OkHttpClient = buildClient() private var socket: WebSocket? = null - private val loggerTag = "MoltbotGateway" + private val loggerTag = "OpenClawGateway" val remoteAddress: String = if (endpoint.host.contains(":")) { diff --git a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayTls.kt b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayTls.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/gateway/GatewayTls.kt rename to apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayTls.kt index 673d60c8fe..dc17aa7329 100644 --- a/apps/android/app/src/main/java/bot/molt/android/gateway/GatewayTls.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/gateway/GatewayTls.kt @@ -1,4 +1,4 @@ -package bot.molt.android.gateway +package ai.openclaw.android.gateway import android.annotation.SuppressLint import java.security.MessageDigest diff --git a/apps/android/app/src/main/java/bot/molt/android/node/CameraCaptureManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/node/CameraCaptureManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt index cb15a3915b..536c8cbda8 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/CameraCaptureManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import android.Manifest import android.content.Context @@ -22,7 +22,7 @@ import androidx.camera.video.VideoRecordEvent import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.checkSelfPermission import androidx.core.graphics.scale -import bot.molt.android.PermissionRequester +import ai.openclaw.android.PermissionRequester import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout @@ -155,7 +155,7 @@ class CameraCaptureManager(private val context: Context) { provider.unbindAll() provider.bindToLifecycle(owner, selector, videoCapture) - val file = File.createTempFile("moltbot-clip-", ".mp4") + val file = File.createTempFile("openclaw-clip-", ".mp4") val outputOptions = FileOutputOptions.Builder(file).build() val finalized = kotlinx.coroutines.CompletableDeferred() @@ -285,7 +285,7 @@ private suspend fun Context.cameraProvider(): ProcessCameraProvider = /** Returns (jpegBytes, exifOrientation) so caller can rotate the decoded bitmap. */ private suspend fun ImageCapture.takeJpegWithExif(executor: Executor): Pair = suspendCancellableCoroutine { cont -> - val file = File.createTempFile("moltbot-snap-", ".jpg") + val file = File.createTempFile("openclaw-snap-", ".jpg") val options = ImageCapture.OutputFileOptions.Builder(file).build() takePicture( options, diff --git a/apps/android/app/src/main/java/bot/molt/android/node/CanvasController.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/CanvasController.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/node/CanvasController.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/CanvasController.kt index 4d33ed0a65..c46770a636 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/CanvasController.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/CanvasController.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import android.graphics.Bitmap import android.graphics.Canvas @@ -17,7 +17,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -import bot.molt.android.BuildConfig +import ai.openclaw.android.BuildConfig import kotlin.coroutines.resume class CanvasController { @@ -84,12 +84,12 @@ class CanvasController { withWebViewOnMain { wv -> if (currentUrl == null) { if (BuildConfig.DEBUG) { - Log.d("MoltbotCanvas", "load scaffold: $scaffoldAssetUrl") + Log.d("OpenClawCanvas", "load scaffold: $scaffoldAssetUrl") } wv.loadUrl(scaffoldAssetUrl) } else { if (BuildConfig.DEBUG) { - Log.d("MoltbotCanvas", "load url: $currentUrl") + Log.d("OpenClawCanvas", "load url: $currentUrl") } wv.loadUrl(currentUrl) } @@ -106,7 +106,7 @@ class CanvasController { val js = """ (() => { try { - const api = globalThis.__moltbot; + const api = globalThis.__openclaw; if (!api) return; if (typeof api.setDebugStatusEnabled === 'function') { api.setDebugStatusEnabled(${if (enabled) "true" else "false"}); diff --git a/apps/android/app/src/main/java/bot/molt/android/node/JpegSizeLimiter.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/JpegSizeLimiter.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/node/JpegSizeLimiter.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/JpegSizeLimiter.kt index 8fb6c35d40..d6018467e6 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/JpegSizeLimiter.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/JpegSizeLimiter.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import kotlin.math.max import kotlin.math.min diff --git a/apps/android/app/src/main/java/bot/molt/android/node/LocationCaptureManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/LocationCaptureManager.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/node/LocationCaptureManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/LocationCaptureManager.kt index c56eee03ab..87762e87fa 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/LocationCaptureManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/LocationCaptureManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import android.Manifest import android.content.Context diff --git a/apps/android/app/src/main/java/bot/molt/android/node/ScreenRecordManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/ScreenRecordManager.kt similarity index 95% rename from apps/android/app/src/main/java/bot/molt/android/node/ScreenRecordManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/ScreenRecordManager.kt index 0e785c2454..337a953866 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/ScreenRecordManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/ScreenRecordManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import android.content.Context import android.hardware.display.DisplayManager @@ -6,7 +6,7 @@ import android.media.MediaRecorder import android.media.projection.MediaProjectionManager import android.os.Build import android.util.Base64 -import bot.molt.android.ScreenCaptureRequester +import ai.openclaw.android.ScreenCaptureRequester import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -17,13 +17,13 @@ class ScreenRecordManager(private val context: Context) { data class Payload(val payloadJson: String) @Volatile private var screenCaptureRequester: ScreenCaptureRequester? = null - @Volatile private var permissionRequester: bot.molt.android.PermissionRequester? = null + @Volatile private var permissionRequester: ai.openclaw.android.PermissionRequester? = null fun attachScreenCaptureRequester(requester: ScreenCaptureRequester) { screenCaptureRequester = requester } - fun attachPermissionRequester(requester: bot.molt.android.PermissionRequester) { + fun attachPermissionRequester(requester: ai.openclaw.android.PermissionRequester) { permissionRequester = requester } @@ -63,7 +63,7 @@ class ScreenRecordManager(private val context: Context) { val height = metrics.heightPixels val densityDpi = metrics.densityDpi - val file = File.createTempFile("moltbot-screen-", ".mp4") + val file = File.createTempFile("openclaw-screen-", ".mp4") if (includeAudio) ensureMicPermission() val recorder = createMediaRecorder() @@ -90,7 +90,7 @@ class ScreenRecordManager(private val context: Context) { val surface = recorder.surface virtualDisplay = projection.createVirtualDisplay( - "moltbot-screen", + "openclaw-screen", width, height, densityDpi, diff --git a/apps/android/app/src/main/java/bot/molt/android/node/SmsManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/SmsManager.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/node/SmsManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/node/SmsManager.kt index 0314ee1a78..d727bfd276 100644 --- a/apps/android/app/src/main/java/bot/molt/android/node/SmsManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/SmsManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.node +package ai.openclaw.android.node import android.Manifest import android.content.Context @@ -11,7 +11,7 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject import kotlinx.serialization.encodeToString -import bot.molt.android.PermissionRequester +import ai.openclaw.android.PermissionRequester /** * Sends SMS messages via the Android SMS API. diff --git a/apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotCanvasA2UIAction.kt b/apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawCanvasA2UIAction.kt similarity index 89% rename from apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotCanvasA2UIAction.kt rename to apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawCanvasA2UIAction.kt index f73879bb2a..7e1a5bf127 100644 --- a/apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotCanvasA2UIAction.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawCanvasA2UIAction.kt @@ -1,9 +1,9 @@ -package bot.molt.android.protocol +package ai.openclaw.android.protocol import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -object MoltbotCanvasA2UIAction { +object OpenClawCanvasA2UIAction { fun extractActionName(userAction: JsonObject): String? { val name = (userAction["name"] as? JsonPrimitive) @@ -61,6 +61,6 @@ object MoltbotCanvasA2UIAction { val err = (error ?: "").replace("\\", "\\\\").replace("\"", "\\\"") val okLiteral = if (ok) "true" else "false" val idEscaped = actionId.replace("\\", "\\\\").replace("\"", "\\\"") - return "window.dispatchEvent(new CustomEvent('moltbot:a2ui-action-status', { detail: { id: \"${idEscaped}\", ok: ${okLiteral}, error: \"${err}\" } }));" + return "window.dispatchEvent(new CustomEvent('openclaw:a2ui-action-status', { detail: { id: \"${idEscaped}\", ok: ${okLiteral}, error: \"${err}\" } }));" } } diff --git a/apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotProtocolConstants.kt b/apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawProtocolConstants.kt similarity index 69% rename from apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotProtocolConstants.kt rename to apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawProtocolConstants.kt index 27d46c3f1b..ccca40c4c3 100644 --- a/apps/android/app/src/main/java/bot/molt/android/protocol/ClawdbotProtocolConstants.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/protocol/OpenClawProtocolConstants.kt @@ -1,6 +1,6 @@ -package bot.molt.android.protocol +package ai.openclaw.android.protocol -enum class MoltbotCapability(val rawValue: String) { +enum class OpenClawCapability(val rawValue: String) { Canvas("canvas"), Camera("camera"), Screen("screen"), @@ -9,7 +9,7 @@ enum class MoltbotCapability(val rawValue: String) { Location("location"), } -enum class MoltbotCanvasCommand(val rawValue: String) { +enum class OpenClawCanvasCommand(val rawValue: String) { Present("canvas.present"), Hide("canvas.hide"), Navigate("canvas.navigate"), @@ -22,7 +22,7 @@ enum class MoltbotCanvasCommand(val rawValue: String) { } } -enum class MoltbotCanvasA2UICommand(val rawValue: String) { +enum class OpenClawCanvasA2UICommand(val rawValue: String) { Push("canvas.a2ui.push"), PushJSONL("canvas.a2ui.pushJSONL"), Reset("canvas.a2ui.reset"), @@ -33,7 +33,7 @@ enum class MoltbotCanvasA2UICommand(val rawValue: String) { } } -enum class MoltbotCameraCommand(val rawValue: String) { +enum class OpenClawCameraCommand(val rawValue: String) { Snap("camera.snap"), Clip("camera.clip"), ; @@ -43,7 +43,7 @@ enum class MoltbotCameraCommand(val rawValue: String) { } } -enum class MoltbotScreenCommand(val rawValue: String) { +enum class OpenClawScreenCommand(val rawValue: String) { Record("screen.record"), ; @@ -52,7 +52,7 @@ enum class MoltbotScreenCommand(val rawValue: String) { } } -enum class MoltbotSmsCommand(val rawValue: String) { +enum class OpenClawSmsCommand(val rawValue: String) { Send("sms.send"), ; @@ -61,7 +61,7 @@ enum class MoltbotSmsCommand(val rawValue: String) { } } -enum class MoltbotLocationCommand(val rawValue: String) { +enum class OpenClawLocationCommand(val rawValue: String) { Get("location.get"), ; diff --git a/apps/android/app/src/main/java/bot/molt/android/tools/ToolDisplay.kt b/apps/android/app/src/main/java/ai/openclaw/android/tools/ToolDisplay.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/tools/ToolDisplay.kt rename to apps/android/app/src/main/java/ai/openclaw/android/tools/ToolDisplay.kt index 6f48628875..1c5561767e 100644 --- a/apps/android/app/src/main/java/bot/molt/android/tools/ToolDisplay.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/tools/ToolDisplay.kt @@ -1,4 +1,4 @@ -package bot.molt.android.tools +package ai.openclaw.android.tools import android.content.Context import kotlinx.serialization.Serializable diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/CameraHudOverlay.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/CameraHudOverlay.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/ui/CameraHudOverlay.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/CameraHudOverlay.kt index 7b45efae9e..21043d739b 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/CameraHudOverlay.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/CameraHudOverlay.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/ChatSheet.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/ChatSheet.kt similarity index 53% rename from apps/android/app/src/main/java/bot/molt/android/ui/ChatSheet.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/ChatSheet.kt index 21af1a4c65..85f20364c6 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/ChatSheet.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/ChatSheet.kt @@ -1,8 +1,8 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import androidx.compose.runtime.Composable -import bot.molt.android.MainViewModel -import bot.molt.android.ui.chat.ChatSheetContent +import ai.openclaw.android.MainViewModel +import ai.openclaw.android.ui.chat.ChatSheetContent @Composable fun ChatSheet(viewModel: MainViewModel) { diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/ClawdbotTheme.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/OpenClawTheme.kt similarity index 92% rename from apps/android/app/src/main/java/bot/molt/android/ui/ClawdbotTheme.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/OpenClawTheme.kt index c292aa25dc..aad743a6d7 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/ClawdbotTheme.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/OpenClawTheme.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme @@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @Composable -fun MoltbotTheme(content: @Composable () -> Unit) { +fun OpenClawTheme(content: @Composable () -> Unit) { val context = LocalContext.current val isDark = isSystemInDarkTheme() val colorScheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/RootScreen.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/RootScreen.kt similarity index 93% rename from apps/android/app/src/main/java/bot/molt/android/ui/RootScreen.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/RootScreen.kt index 67d76b82fa..af0cfe628a 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/RootScreen.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/RootScreen.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import android.annotation.SuppressLint import android.Manifest @@ -65,8 +65,8 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import androidx.core.content.ContextCompat -import bot.molt.android.CameraHudKind -import bot.molt.android.MainViewModel +import ai.openclaw.android.CameraHudKind +import ai.openclaw.android.MainViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -333,7 +333,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) disableForceDarkIfSupported(settings) } if (isDebuggable) { - Log.d("MoltbotWebView", "userAgent: ${settings.userAgentString}") + Log.d("OpenClawWebView", "userAgent: ${settings.userAgentString}") } isScrollContainer = true overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS @@ -348,7 +348,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) ) { if (!isDebuggable) return if (!request.isForMainFrame) return - Log.e("MoltbotWebView", "onReceivedError: ${error.errorCode} ${error.description} ${request.url}") + Log.e("OpenClawWebView", "onReceivedError: ${error.errorCode} ${error.description} ${request.url}") } override fun onReceivedHttpError( @@ -359,14 +359,14 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) if (!isDebuggable) return if (!request.isForMainFrame) return Log.e( - "MoltbotWebView", + "OpenClawWebView", "onReceivedHttpError: ${errorResponse.statusCode} ${errorResponse.reasonPhrase} ${request.url}", ) } override fun onPageFinished(view: WebView, url: String?) { if (isDebuggable) { - Log.d("MoltbotWebView", "onPageFinished: $url") + Log.d("OpenClawWebView", "onPageFinished: $url") } viewModel.canvas.onPageFinished() } @@ -377,7 +377,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) ): Boolean { if (isDebuggable) { Log.e( - "MoltbotWebView", + "OpenClawWebView", "onRenderProcessGone didCrash=${detail.didCrash()} priorityAtExit=${detail.rendererPriorityAtExit()}", ) } @@ -390,7 +390,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) if (!isDebuggable) return false val msg = consoleMessage ?: return false Log.d( - "MoltbotWebView", + "OpenClawWebView", "console ${msg.messageLevel()} @ ${msg.sourceId()}:${msg.lineNumber()} ${msg.message()}", ) return false @@ -403,10 +403,6 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) viewModel.handleCanvasA2UIActionFromWebView(payload) } addJavascriptInterface(a2uiBridge, CanvasA2UIActionBridge.interfaceName) - addJavascriptInterface( - CanvasA2UIActionLegacyBridge(a2uiBridge), - CanvasA2UIActionLegacyBridge.interfaceName, - ) viewModel.canvas.attach(this) } }, @@ -428,22 +424,6 @@ private class CanvasA2UIActionBridge(private val onMessage: (String) -> Unit) { } companion object { - const val interfaceName: String = "moltbotCanvasA2UIAction" - } -} - -private class CanvasA2UIActionLegacyBridge(private val bridge: CanvasA2UIActionBridge) { - @JavascriptInterface - fun canvasAction(payload: String?) { - bridge.postMessage(payload) - } - - @JavascriptInterface - fun postMessage(payload: String?) { - bridge.postMessage(payload) - } - - companion object { - const val interfaceName: String = "Android" + const val interfaceName: String = "openclawCanvasA2UIAction" } } diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/SettingsSheet.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/SettingsSheet.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/ui/SettingsSheet.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/SettingsSheet.kt index f96731acfb..fa32f7bb85 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/SettingsSheet.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/SettingsSheet.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import android.Manifest import android.content.Context @@ -58,12 +58,12 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat -import bot.molt.android.BuildConfig -import bot.molt.android.LocationMode -import bot.molt.android.MainViewModel -import bot.molt.android.NodeForegroundService -import bot.molt.android.VoiceWakeMode -import bot.molt.android.WakeWords +import ai.openclaw.android.BuildConfig +import ai.openclaw.android.LocationMode +import ai.openclaw.android.MainViewModel +import ai.openclaw.android.NodeForegroundService +import ai.openclaw.android.VoiceWakeMode +import ai.openclaw.android.WakeWords @Composable fun SettingsSheet(viewModel: MainViewModel) { @@ -457,7 +457,7 @@ fun SettingsSheet(viewModel: MainViewModel) { Column(verticalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.fillMaxWidth()) { ListItem( headlineContent = { Text("Foreground Only") }, - supportingContent = { Text("Listens only while Moltbot is open.") }, + supportingContent = { Text("Listens only while OpenClaw is open.") }, trailingContent = { RadioButton( selected = voiceWakeMode == VoiceWakeMode.Foreground, @@ -603,7 +603,7 @@ fun SettingsSheet(viewModel: MainViewModel) { ) ListItem( headlineContent = { Text("While Using") }, - supportingContent = { Text("Only while Moltbot is open.") }, + supportingContent = { Text("Only while OpenClaw is open.") }, trailingContent = { RadioButton( selected = locationMode == LocationMode.WhileUsing, @@ -650,7 +650,7 @@ fun SettingsSheet(viewModel: MainViewModel) { item { ListItem( headlineContent = { Text("Prevent Sleep") }, - supportingContent = { Text("Keeps the screen awake while Moltbot is open.") }, + supportingContent = { Text("Keeps the screen awake while OpenClaw is open.") }, trailingContent = { Switch(checked = preventSleep, onCheckedChange = viewModel::setPreventSleep) }, ) } diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/StatusPill.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/StatusPill.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/ui/StatusPill.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/StatusPill.kt index 199bcbf820..d608fc38a7 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/StatusPill.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/StatusPill.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/TalkOrbOverlay.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/TalkOrbOverlay.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/ui/TalkOrbOverlay.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/TalkOrbOverlay.kt index 9098c06ff3..f89b298d1f 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/TalkOrbOverlay.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/TalkOrbOverlay.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui +package ai.openclaw.android.ui import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatComposer.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatComposer.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatComposer.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatComposer.kt index bc0d9917f5..492516b51b 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatComposer.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatComposer.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -38,7 +38,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import bot.molt.android.chat.ChatSessionEntry +import ai.openclaw.android.chat.ChatSessionEntry @Composable fun ChatComposer( @@ -143,7 +143,7 @@ fun ChatComposer( value = input, onValueChange = { input = it }, modifier = Modifier.fillMaxWidth(), - placeholder = { Text("Message Clawd…") }, + placeholder = { Text("Message OpenClaw…") }, minLines = 2, maxLines = 6, ) diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMarkdown.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMarkdown.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMarkdown.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMarkdown.kt index 10cf25b813..77dba2275a 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMarkdown.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMarkdown.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import android.graphics.BitmapFactory import android.util.Base64 diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageListCard.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageListCard.kt similarity index 95% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageListCard.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageListCard.kt index 1091de6c80..d263463729 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageListCard.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageListCard.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -20,8 +20,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.unit.dp -import bot.molt.android.chat.ChatMessage -import bot.molt.android.chat.ChatPendingToolCall +import ai.openclaw.android.chat.ChatMessage +import ai.openclaw.android.chat.ChatPendingToolCall @Composable fun ChatMessageListCard( @@ -103,7 +103,7 @@ private fun EmptyChatHint(modifier: Modifier = Modifier) { tint = MaterialTheme.colorScheme.onSurfaceVariant, ) Text( - text = "Message Clawd…", + text = "Message OpenClaw…", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageViews.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageViews.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageViews.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageViews.kt index 59445be374..1f87db32a5 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatMessageViews.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatMessageViews.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import android.graphics.BitmapFactory import android.util.Base64 @@ -31,10 +31,10 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.foundation.Image -import bot.molt.android.chat.ChatMessage -import bot.molt.android.chat.ChatMessageContent -import bot.molt.android.chat.ChatPendingToolCall -import bot.molt.android.tools.ToolDisplayRegistry +import ai.openclaw.android.chat.ChatMessage +import ai.openclaw.android.chat.ChatMessageContent +import ai.openclaw.android.chat.ChatPendingToolCall +import ai.openclaw.android.tools.ToolDisplayRegistry import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import androidx.compose.ui.platform.LocalContext diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSessionsDialog.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSessionsDialog.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSessionsDialog.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSessionsDialog.kt index 377a13daa6..56b5cfb1fa 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSessionsDialog.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSessionsDialog.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -20,7 +20,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bot.molt.android.chat.ChatSessionEntry +import ai.openclaw.android.chat.ChatSessionEntry @Composable fun ChatSessionsDialog( diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSheetContent.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSheetContent.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSheetContent.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSheetContent.kt index 5632be70fe..effee6708e 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/ChatSheetContent.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/ChatSheetContent.kt @@ -1,4 +1,4 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat import android.content.ContentResolver import android.net.Uri @@ -19,8 +19,8 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import bot.molt.android.MainViewModel -import bot.molt.android.chat.OutgoingAttachment +import ai.openclaw.android.MainViewModel +import ai.openclaw.android.chat.OutgoingAttachment import java.io.ByteArrayOutputStream import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/apps/android/app/src/main/java/bot/molt/android/ui/chat/SessionFilters.kt b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/SessionFilters.kt similarity index 94% rename from apps/android/app/src/main/java/bot/molt/android/ui/chat/SessionFilters.kt rename to apps/android/app/src/main/java/ai/openclaw/android/ui/chat/SessionFilters.kt index 227fb0a02a..4efca2d0cf 100644 --- a/apps/android/app/src/main/java/bot/molt/android/ui/chat/SessionFilters.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/ui/chat/SessionFilters.kt @@ -1,6 +1,6 @@ -package bot.molt.android.ui.chat +package ai.openclaw.android.ui.chat -import bot.molt.android.chat.ChatSessionEntry +import ai.openclaw.android.chat.ChatSessionEntry private const val RECENT_WINDOW_MS = 24 * 60 * 60 * 1000L diff --git a/apps/android/app/src/main/java/bot/molt/android/voice/StreamingMediaDataSource.kt b/apps/android/app/src/main/java/ai/openclaw/android/voice/StreamingMediaDataSource.kt similarity index 98% rename from apps/android/app/src/main/java/bot/molt/android/voice/StreamingMediaDataSource.kt rename to apps/android/app/src/main/java/ai/openclaw/android/voice/StreamingMediaDataSource.kt index 7a7f61165f..329707ad56 100644 --- a/apps/android/app/src/main/java/bot/molt/android/voice/StreamingMediaDataSource.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/voice/StreamingMediaDataSource.kt @@ -1,4 +1,4 @@ -package bot.molt.android.voice +package ai.openclaw.android.voice import android.media.MediaDataSource import kotlin.math.min diff --git a/apps/android/app/src/main/java/bot/molt/android/voice/TalkDirectiveParser.kt b/apps/android/app/src/main/java/ai/openclaw/android/voice/TalkDirectiveParser.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/voice/TalkDirectiveParser.kt rename to apps/android/app/src/main/java/ai/openclaw/android/voice/TalkDirectiveParser.kt index 0d969e4d14..5c80cc1f4f 100644 --- a/apps/android/app/src/main/java/bot/molt/android/voice/TalkDirectiveParser.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/voice/TalkDirectiveParser.kt @@ -1,4 +1,4 @@ -package bot.molt.android.voice +package ai.openclaw.android.voice import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement diff --git a/apps/android/app/src/main/java/bot/molt/android/voice/TalkModeManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/voice/TalkModeManager.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/voice/TalkModeManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/voice/TalkModeManager.kt index f050f8bd24..d4ca06f50f 100644 --- a/apps/android/app/src/main/java/bot/molt/android/voice/TalkModeManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/voice/TalkModeManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.voice +package ai.openclaw.android.voice import android.Manifest import android.content.Context @@ -20,9 +20,9 @@ import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import android.util.Log import androidx.core.content.ContextCompat -import bot.molt.android.gateway.GatewaySession -import bot.molt.android.isCanonicalMainSessionKey -import bot.molt.android.normalizeMainKey +import ai.openclaw.android.gateway.GatewaySession +import ai.openclaw.android.isCanonicalMainSessionKey +import ai.openclaw.android.normalizeMainKey import java.net.HttpURLConnection import java.net.URL import java.util.UUID diff --git a/apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeCommandExtractor.kt b/apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeCommandExtractor.kt similarity index 97% rename from apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeCommandExtractor.kt rename to apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeCommandExtractor.kt index 8da4e32894..dccd3950c9 100644 --- a/apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeCommandExtractor.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeCommandExtractor.kt @@ -1,4 +1,4 @@ -package bot.molt.android.voice +package ai.openclaw.android.voice object VoiceWakeCommandExtractor { fun extractCommand(text: String, triggerWords: List): String? { diff --git a/apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeManager.kt similarity index 99% rename from apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeManager.kt rename to apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeManager.kt index b27d0e3c70..334f985a02 100644 --- a/apps/android/app/src/main/java/bot/molt/android/voice/VoiceWakeManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/voice/VoiceWakeManager.kt @@ -1,4 +1,4 @@ -package bot.molt.android.voice +package ai.openclaw.android.voice import android.content.Context import android.content.Intent diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 0aae9e7392..0098cee20f 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - Moltbot Node + OpenClaw Node diff --git a/apps/android/app/src/main/res/values/themes.xml b/apps/android/app/src/main/res/values/themes.xml index f90f40dc96..3ac5d04d83 100644 --- a/apps/android/app/src/main/res/values/themes.xml +++ b/apps/android/app/src/main/res/values/themes.xml @@ -1,5 +1,5 @@ - - -
    + +
    -
    Ready
    -
    Waiting for agent
    +
    Ready
    +
    Waiting for agent
    diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/Resources/tool-display.json b/apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/Resources/tool-display.json rename to apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/ScreenCommands.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/ScreenCommands.swift similarity index 80% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/ScreenCommands.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/ScreenCommands.swift index 00c9bb5fc3..dfb57ce2ab 100644 --- a/apps/shared/MoltbotKit/Sources/MoltbotKit/ScreenCommands.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/ScreenCommands.swift @@ -1,10 +1,10 @@ import Foundation -public enum MoltbotScreenCommand: String, Codable, Sendable { +public enum OpenClawScreenCommand: String, Codable, Sendable { case record = "screen.record" } -public struct MoltbotScreenRecordParams: Codable, Sendable, Equatable { +public struct OpenClawScreenRecordParams: Codable, Sendable, Equatable { public var screenIndex: Int? public var durationMs: Int? public var fps: Double? diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/StoragePaths.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/StoragePaths.swift similarity index 80% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/StoragePaths.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/StoragePaths.swift index 437c96777c..d754229571 100644 --- a/apps/shared/MoltbotKit/Sources/MoltbotKit/StoragePaths.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/StoragePaths.swift @@ -1,14 +1,14 @@ import Foundation -public enum MoltbotNodeStorage { +public enum OpenClawNodeStorage { public static func appSupportDir() throws -> URL { let base = FileManager().urls(for: .applicationSupportDirectory, in: .userDomainMask).first guard let base else { - throw NSError(domain: "MoltbotNodeStorage", code: 1, userInfo: [ + throw NSError(domain: "OpenClawNodeStorage", code: 1, userInfo: [ NSLocalizedDescriptionKey: "Application Support directory unavailable", ]) } - return base.appendingPathComponent("Moltbot", isDirectory: true) + return base.appendingPathComponent("OpenClaw", isDirectory: true) } public static func canvasRoot(sessionKey: String) throws -> URL { @@ -21,11 +21,11 @@ public enum MoltbotNodeStorage { public static func cachesDir() throws -> URL { let base = FileManager().urls(for: .cachesDirectory, in: .userDomainMask).first guard let base else { - throw NSError(domain: "MoltbotNodeStorage", code: 2, userInfo: [ + throw NSError(domain: "OpenClawNodeStorage", code: 2, userInfo: [ NSLocalizedDescriptionKey: "Caches directory unavailable", ]) } - return base.appendingPathComponent("Moltbot", isDirectory: true) + return base.appendingPathComponent("OpenClaw", isDirectory: true) } public static func canvasSnapshotsRoot(sessionKey: String) throws -> URL { diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/SystemCommands.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/SystemCommands.swift similarity index 74% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/SystemCommands.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/SystemCommands.swift index 5e42734c5d..a2c8349058 100644 --- a/apps/shared/MoltbotKit/Sources/MoltbotKit/SystemCommands.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/SystemCommands.swift @@ -1,6 +1,6 @@ import Foundation -public enum MoltbotSystemCommand: String, Codable, Sendable { +public enum OpenClawSystemCommand: String, Codable, Sendable { case run = "system.run" case which = "system.which" case notify = "system.notify" @@ -8,19 +8,19 @@ public enum MoltbotSystemCommand: String, Codable, Sendable { case execApprovalsSet = "system.execApprovals.set" } -public enum MoltbotNotificationPriority: String, Codable, Sendable { +public enum OpenClawNotificationPriority: String, Codable, Sendable { case passive case active case timeSensitive } -public enum MoltbotNotificationDelivery: String, Codable, Sendable { +public enum OpenClawNotificationDelivery: String, Codable, Sendable { case system case overlay case auto } -public struct MoltbotSystemRunParams: Codable, Sendable, Equatable { +public struct OpenClawSystemRunParams: Codable, Sendable, Equatable { public var command: [String] public var rawCommand: String? public var cwd: String? @@ -57,7 +57,7 @@ public struct MoltbotSystemRunParams: Codable, Sendable, Equatable { } } -public struct MoltbotSystemWhichParams: Codable, Sendable, Equatable { +public struct OpenClawSystemWhichParams: Codable, Sendable, Equatable { public var bins: [String] public init(bins: [String]) { @@ -65,19 +65,19 @@ public struct MoltbotSystemWhichParams: Codable, Sendable, Equatable { } } -public struct MoltbotSystemNotifyParams: Codable, Sendable, Equatable { +public struct OpenClawSystemNotifyParams: Codable, Sendable, Equatable { public var title: String public var body: String public var sound: String? - public var priority: MoltbotNotificationPriority? - public var delivery: MoltbotNotificationDelivery? + public var priority: OpenClawNotificationPriority? + public var delivery: OpenClawNotificationDelivery? public init( title: String, body: String, sound: String? = nil, - priority: MoltbotNotificationPriority? = nil, - delivery: MoltbotNotificationDelivery? = nil) + priority: OpenClawNotificationPriority? = nil, + delivery: OpenClawNotificationDelivery? = nil) { self.title = title self.body = body diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/TalkDirective.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/TalkDirective.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/TalkDirective.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/TalkDirective.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/TalkHistoryTimestamp.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/TalkHistoryTimestamp.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/TalkHistoryTimestamp.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/TalkHistoryTimestamp.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/TalkPromptBuilder.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/TalkPromptBuilder.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/TalkPromptBuilder.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/TalkPromptBuilder.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/TalkSystemSpeechSynthesizer.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/TalkSystemSpeechSynthesizer.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/TalkSystemSpeechSynthesizer.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/TalkSystemSpeechSynthesizer.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotKit/ToolDisplay.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/ToolDisplay.swift similarity index 98% rename from apps/shared/MoltbotKit/Sources/MoltbotKit/ToolDisplay.swift rename to apps/shared/OpenClawKit/Sources/OpenClawKit/ToolDisplay.swift index 9016d158e5..d52e24ca85 100644 --- a/apps/shared/MoltbotKit/Sources/MoltbotKit/ToolDisplay.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/ToolDisplay.swift @@ -90,7 +90,7 @@ public enum ToolDisplayRegistry { } private static func loadConfig() -> ToolDisplayConfig { - guard let url = MoltbotKitResources.bundle.url(forResource: "tool-display", withExtension: "json") else { + guard let url = OpenClawKitResources.bundle.url(forResource: "tool-display", withExtension: "json") else { return self.defaultConfig() } do { diff --git a/apps/shared/MoltbotKit/Sources/MoltbotProtocol/AnyCodable.swift b/apps/shared/OpenClawKit/Sources/OpenClawProtocol/AnyCodable.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotProtocol/AnyCodable.swift rename to apps/shared/OpenClawKit/Sources/OpenClawProtocol/AnyCodable.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotProtocol/GatewayModels.swift b/apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotProtocol/GatewayModels.swift rename to apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift diff --git a/apps/shared/MoltbotKit/Sources/MoltbotProtocol/WizardHelpers.swift b/apps/shared/OpenClawKit/Sources/OpenClawProtocol/WizardHelpers.swift similarity index 100% rename from apps/shared/MoltbotKit/Sources/MoltbotProtocol/WizardHelpers.swift rename to apps/shared/OpenClawKit/Sources/OpenClawProtocol/WizardHelpers.swift diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/AssistantTextParserTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/AssistantTextParserTests.swift similarity index 97% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/AssistantTextParserTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/AssistantTextParserTests.swift index 5bb2517a4f..5f36bb9c26 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/AssistantTextParserTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/AssistantTextParserTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import MoltbotChatUI +@testable import OpenClawChatUI @Suite struct AssistantTextParserTests { @Test func splitsThinkAndFinalSegments() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/BonjourEscapesTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/BonjourEscapesTests.swift similarity index 87% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/BonjourEscapesTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/BonjourEscapesTests.swift index 0ccd6a61de..a7fa1438d3 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/BonjourEscapesTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/BonjourEscapesTests.swift @@ -1,4 +1,4 @@ -import MoltbotKit +import OpenClawKit import Testing @Suite struct BonjourEscapesTests { @@ -8,7 +8,7 @@ import Testing } @Test func decodeSpaces() { - #expect(BonjourEscapes.decode("Moltbot\\032Gateway") == "Moltbot Gateway") + #expect(BonjourEscapes.decode("OpenClaw\\032Gateway") == "OpenClaw Gateway") } @Test func decodeMultipleEscapes() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UIActionTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UIActionTests.swift similarity index 53% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UIActionTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UIActionTests.swift index fd7e079115..f6070f6de8 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UIActionTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UIActionTests.swift @@ -1,28 +1,28 @@ -import MoltbotKit +import OpenClawKit import Foundation import Testing @Suite struct CanvasA2UIActionTests { @Test func sanitizeTagValueIsStable() { - #expect(MoltbotCanvasA2UIAction.sanitizeTagValue("Hello World!") == "Hello_World_") - #expect(MoltbotCanvasA2UIAction.sanitizeTagValue(" ") == "-") - #expect(MoltbotCanvasA2UIAction.sanitizeTagValue("macOS 26.2") == "macOS_26.2") + #expect(OpenClawCanvasA2UIAction.sanitizeTagValue("Hello World!") == "Hello_World_") + #expect(OpenClawCanvasA2UIAction.sanitizeTagValue(" ") == "-") + #expect(OpenClawCanvasA2UIAction.sanitizeTagValue("macOS 26.2") == "macOS_26.2") } @Test func extractActionNameAcceptsNameOrAction() { - #expect(MoltbotCanvasA2UIAction.extractActionName(["name": "Hello"]) == "Hello") - #expect(MoltbotCanvasA2UIAction.extractActionName(["action": "Wave"]) == "Wave") - #expect(MoltbotCanvasA2UIAction.extractActionName(["name": " ", "action": "Fallback"]) == "Fallback") - #expect(MoltbotCanvasA2UIAction.extractActionName(["action": " "]) == nil) + #expect(OpenClawCanvasA2UIAction.extractActionName(["name": "Hello"]) == "Hello") + #expect(OpenClawCanvasA2UIAction.extractActionName(["action": "Wave"]) == "Wave") + #expect(OpenClawCanvasA2UIAction.extractActionName(["name": " ", "action": "Fallback"]) == "Fallback") + #expect(OpenClawCanvasA2UIAction.extractActionName(["action": " "]) == nil) } @Test func formatAgentMessageIsTokenEfficientAndUnambiguous() { - let messageContext = MoltbotCanvasA2UIAction.AgentMessageContext( + let messageContext = OpenClawCanvasA2UIAction.AgentMessageContext( actionName: "Get Weather", session: .init(key: "main", surfaceId: "main"), component: .init(id: "btnWeather", host: "Peter’s iPad", instanceId: "ipad16,6"), contextJSON: "{\"city\":\"Vienna\"}") - let msg = MoltbotCanvasA2UIAction.formatAgentMessage(messageContext) + let msg = OpenClawCanvasA2UIAction.formatAgentMessage(messageContext) #expect(msg.contains("CANVAS_A2UI ")) #expect(msg.contains("action=Get_Weather")) diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UITests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UITests.swift similarity index 61% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UITests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UITests.swift index c063f80e0f..4c420cc944 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasA2UITests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasA2UITests.swift @@ -1,11 +1,11 @@ -import MoltbotKit +import OpenClawKit import Testing @Suite struct CanvasA2UITests { @Test func commandStringsAreStable() { - #expect(MoltbotCanvasA2UICommand.push.rawValue == "canvas.a2ui.push") - #expect(MoltbotCanvasA2UICommand.pushJSONL.rawValue == "canvas.a2ui.pushJSONL") - #expect(MoltbotCanvasA2UICommand.reset.rawValue == "canvas.a2ui.reset") + #expect(OpenClawCanvasA2UICommand.push.rawValue == "canvas.a2ui.push") + #expect(OpenClawCanvasA2UICommand.pushJSONL.rawValue == "canvas.a2ui.pushJSONL") + #expect(OpenClawCanvasA2UICommand.reset.rawValue == "canvas.a2ui.reset") } @Test func jsonlDecodesAndValidatesV0_8() throws { @@ -16,7 +16,7 @@ import Testing {"deleteSurface":{"surfaceId":"main"}} """ - let messages = try MoltbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) + let messages = try OpenClawCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) #expect(messages.count == 4) } @@ -26,7 +26,7 @@ import Testing """ #expect(throws: Error.self) { - _ = try MoltbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) + _ = try OpenClawCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) } } @@ -36,7 +36,7 @@ import Testing """ #expect(throws: Error.self) { - _ = try MoltbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) + _ = try OpenClawCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl) } } } diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasSnapshotFormatTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasSnapshotFormatTests.swift similarity index 83% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasSnapshotFormatTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasSnapshotFormatTests.swift index d83a919523..ab49a4f465 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/CanvasSnapshotFormatTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/CanvasSnapshotFormatTests.swift @@ -1,11 +1,11 @@ -import MoltbotKit +import OpenClawKit import Foundation import Testing @Suite struct CanvasSnapshotFormatTests { @Test func acceptsJpgAlias() throws { struct Wrapper: Codable { - var format: MoltbotCanvasSnapshotFormat + var format: OpenClawCanvasSnapshotFormat } let data = try #require("{\"format\":\"jpg\"}".data(using: .utf8)) diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatMarkdownPreprocessorTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatMarkdownPreprocessorTests.swift similarity index 94% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatMarkdownPreprocessorTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatMarkdownPreprocessorTests.swift index ba855977b6..808f74af64 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatMarkdownPreprocessorTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatMarkdownPreprocessorTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import MoltbotChatUI +@testable import OpenClawChatUI @Suite("ChatMarkdownPreprocessor") struct ChatMarkdownPreprocessorTests { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatThemeTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatThemeTests.swift similarity index 76% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatThemeTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatThemeTests.swift index 97a1238a72..2c7a5fff1e 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatThemeTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatThemeTests.swift @@ -1,6 +1,6 @@ import Foundation import Testing -@testable import MoltbotChatUI +@testable import OpenClawChatUI #if os(macOS) import AppKit @@ -19,8 +19,8 @@ private func luminance(_ color: NSColor) throws -> CGFloat { let lightAppearance = try #require(NSAppearance(named: .aqua)) let darkAppearance = try #require(NSAppearance(named: .darkAqua)) - let lightResolved = MoltbotChatTheme.resolvedAssistantBubbleColor(for: lightAppearance) - let darkResolved = MoltbotChatTheme.resolvedAssistantBubbleColor(for: darkAppearance) + let lightResolved = OpenClawChatTheme.resolvedAssistantBubbleColor(for: lightAppearance) + let darkResolved = OpenClawChatTheme.resolvedAssistantBubbleColor(for: darkAppearance) #expect(try luminance(lightResolved) > luminance(darkResolved)) #else #expect(Bool(true)) diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatViewModelTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift similarity index 84% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatViewModelTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift index 9c197ec3ef..3babe8b9a3 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ChatViewModelTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift @@ -1,7 +1,7 @@ -import MoltbotKit +import OpenClawKit import Foundation import Testing -@testable import MoltbotChatUI +@testable import OpenClawChatUI private struct TimeoutError: Error, CustomStringConvertible { let label: String @@ -31,40 +31,40 @@ private actor TestChatTransportState { var abortedRunIds: [String] = [] } -private final class TestChatTransport: @unchecked Sendable, MoltbotChatTransport { +private final class TestChatTransport: @unchecked Sendable, OpenClawChatTransport { private let state = TestChatTransportState() - private let historyResponses: [MoltbotChatHistoryPayload] - private let sessionsResponses: [MoltbotChatSessionsListResponse] + private let historyResponses: [OpenClawChatHistoryPayload] + private let sessionsResponses: [OpenClawChatSessionsListResponse] - private let stream: AsyncStream - private let continuation: AsyncStream.Continuation + private let stream: AsyncStream + private let continuation: AsyncStream.Continuation init( - historyResponses: [MoltbotChatHistoryPayload], - sessionsResponses: [MoltbotChatSessionsListResponse] = []) + historyResponses: [OpenClawChatHistoryPayload], + sessionsResponses: [OpenClawChatSessionsListResponse] = []) { self.historyResponses = historyResponses self.sessionsResponses = sessionsResponses - var cont: AsyncStream.Continuation! + var cont: AsyncStream.Continuation! self.stream = AsyncStream { c in cont = c } self.continuation = cont } - func events() -> AsyncStream { + func events() -> AsyncStream { self.stream } func setActiveSessionKey(_: String) async throws {} - func requestHistory(sessionKey: String) async throws -> MoltbotChatHistoryPayload { + func requestHistory(sessionKey: String) async throws -> OpenClawChatHistoryPayload { let idx = await self.state.historyCallCount await self.state.setHistoryCallCount(idx + 1) if idx < self.historyResponses.count { return self.historyResponses[idx] } - return self.historyResponses.last ?? MoltbotChatHistoryPayload( + return self.historyResponses.last ?? OpenClawChatHistoryPayload( sessionKey: sessionKey, sessionId: nil, messages: [], @@ -76,23 +76,23 @@ private final class TestChatTransport: @unchecked Sendable, MoltbotChatTransport message _: String, thinking _: String, idempotencyKey: String, - attachments _: [MoltbotChatAttachmentPayload]) async throws -> MoltbotChatSendResponse + attachments _: [OpenClawChatAttachmentPayload]) async throws -> OpenClawChatSendResponse { await self.state.sentRunIdsAppend(idempotencyKey) - return MoltbotChatSendResponse(runId: idempotencyKey, status: "ok") + return OpenClawChatSendResponse(runId: idempotencyKey, status: "ok") } func abortRun(sessionKey _: String, runId: String) async throws { await self.state.abortedRunIdsAppend(runId) } - func listSessions(limit _: Int?) async throws -> MoltbotChatSessionsListResponse { + func listSessions(limit _: Int?) async throws -> OpenClawChatSessionsListResponse { let idx = await self.state.sessionsCallCount await self.state.setSessionsCallCount(idx + 1) if idx < self.sessionsResponses.count { return self.sessionsResponses[idx] } - return self.sessionsResponses.last ?? MoltbotChatSessionsListResponse( + return self.sessionsResponses.last ?? OpenClawChatSessionsListResponse( ts: nil, path: nil, count: 0, @@ -104,7 +104,7 @@ private final class TestChatTransport: @unchecked Sendable, MoltbotChatTransport true } - func emit(_ evt: MoltbotChatTransportEvent) { + func emit(_ evt: OpenClawChatTransportEvent) { self.continuation.yield(evt) } @@ -139,12 +139,12 @@ extension TestChatTransportState { @Suite struct ChatViewModelTests { @Test func streamsAssistantAndClearsOnFinal() async throws { let sessionId = "sess-main" - let history1 = MoltbotChatHistoryPayload( + let history1 = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: sessionId, messages: [], thinkingLevel: "off") - let history2 = MoltbotChatHistoryPayload( + let history2 = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: sessionId, messages: [ @@ -157,7 +157,7 @@ extension TestChatTransportState { thinkingLevel: "off") let transport = TestChatTransport(historyResponses: [history1, history2]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "main", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "main", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } } @@ -170,7 +170,7 @@ extension TestChatTransportState { transport.emit( .agent( - MoltbotAgentEventPayload( + OpenClawAgentEventPayload( runId: sessionId, seq: 1, stream: "assistant", @@ -183,7 +183,7 @@ extension TestChatTransportState { transport.emit( .agent( - MoltbotAgentEventPayload( + OpenClawAgentEventPayload( runId: sessionId, seq: 2, stream: "tool", @@ -200,7 +200,7 @@ extension TestChatTransportState { let runId = try #require(await transport.lastSentRunId()) transport.emit( .chat( - MoltbotChatEventPayload( + OpenClawChatEventPayload( runId: runId, sessionKey: "main", state: "final", @@ -217,20 +217,20 @@ extension TestChatTransportState { @Test func clearsStreamingOnExternalFinalEvent() async throws { let sessionId = "sess-main" - let history = MoltbotChatHistoryPayload( + let history = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: sessionId, messages: [], thinkingLevel: "off") let transport = TestChatTransport(historyResponses: [history, history]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "main", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "main", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } } transport.emit( .agent( - MoltbotAgentEventPayload( + OpenClawAgentEventPayload( runId: sessionId, seq: 1, stream: "assistant", @@ -239,7 +239,7 @@ extension TestChatTransportState { transport.emit( .agent( - MoltbotAgentEventPayload( + OpenClawAgentEventPayload( runId: sessionId, seq: 2, stream: "tool", @@ -258,7 +258,7 @@ extension TestChatTransportState { transport.emit( .chat( - MoltbotChatEventPayload( + OpenClawChatEventPayload( runId: "other-run", sessionKey: "main", state: "final", @@ -274,18 +274,18 @@ extension TestChatTransportState { let recent = now - (2 * 60 * 60 * 1000) let recentOlder = now - (5 * 60 * 60 * 1000) let stale = now - (26 * 60 * 60 * 1000) - let history = MoltbotChatHistoryPayload( + let history = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: "sess-main", messages: [], thinkingLevel: "off") - let sessions = MoltbotChatSessionsListResponse( + let sessions = OpenClawChatSessionsListResponse( ts: now, path: nil, count: 4, defaults: nil, sessions: [ - MoltbotChatSessionEntry( + OpenClawChatSessionEntry( key: "recent-1", kind: nil, displayName: nil, @@ -304,7 +304,7 @@ extension TestChatTransportState { totalTokens: nil, model: nil, contextTokens: nil), - MoltbotChatSessionEntry( + OpenClawChatSessionEntry( key: "main", kind: nil, displayName: nil, @@ -323,7 +323,7 @@ extension TestChatTransportState { totalTokens: nil, model: nil, contextTokens: nil), - MoltbotChatSessionEntry( + OpenClawChatSessionEntry( key: "recent-2", kind: nil, displayName: nil, @@ -342,7 +342,7 @@ extension TestChatTransportState { totalTokens: nil, model: nil, contextTokens: nil), - MoltbotChatSessionEntry( + OpenClawChatSessionEntry( key: "old-1", kind: nil, displayName: nil, @@ -366,7 +366,7 @@ extension TestChatTransportState { let transport = TestChatTransport( historyResponses: [history], sessionsResponses: [sessions]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "main", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "main", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("sessions loaded") { await MainActor.run { !vm.sessions.isEmpty } } @@ -377,18 +377,18 @@ extension TestChatTransportState { @Test func sessionChoicesIncludeCurrentWhenMissing() async throws { let now = Date().timeIntervalSince1970 * 1000 let recent = now - (30 * 60 * 1000) - let history = MoltbotChatHistoryPayload( + let history = OpenClawChatHistoryPayload( sessionKey: "custom", sessionId: "sess-custom", messages: [], thinkingLevel: "off") - let sessions = MoltbotChatSessionsListResponse( + let sessions = OpenClawChatSessionsListResponse( ts: now, path: nil, count: 1, defaults: nil, sessions: [ - MoltbotChatSessionEntry( + OpenClawChatSessionEntry( key: "main", kind: nil, displayName: nil, @@ -412,7 +412,7 @@ extension TestChatTransportState { let transport = TestChatTransport( historyResponses: [history], sessionsResponses: [sessions]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "custom", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "custom", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("sessions loaded") { await MainActor.run { !vm.sessions.isEmpty } } @@ -422,20 +422,20 @@ extension TestChatTransportState { @Test func clearsStreamingOnExternalErrorEvent() async throws { let sessionId = "sess-main" - let history = MoltbotChatHistoryPayload( + let history = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: sessionId, messages: [], thinkingLevel: "off") let transport = TestChatTransport(historyResponses: [history, history]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "main", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "main", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } } transport.emit( .agent( - MoltbotAgentEventPayload( + OpenClawAgentEventPayload( runId: sessionId, seq: 1, stream: "assistant", @@ -448,7 +448,7 @@ extension TestChatTransportState { transport.emit( .chat( - MoltbotChatEventPayload( + OpenClawChatEventPayload( runId: "other-run", sessionKey: "main", state: "error", @@ -460,13 +460,13 @@ extension TestChatTransportState { @Test func abortRequestsDoNotClearPendingUntilAbortedEvent() async throws { let sessionId = "sess-main" - let history = MoltbotChatHistoryPayload( + let history = OpenClawChatHistoryPayload( sessionKey: "main", sessionId: sessionId, messages: [], thinkingLevel: "off") let transport = TestChatTransport(historyResponses: [history, history]) - let vm = await MainActor.run { MoltbotChatViewModel(sessionKey: "main", transport: transport) } + let vm = await MainActor.run { OpenClawChatViewModel(sessionKey: "main", transport: transport) } await MainActor.run { vm.load() } try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } } @@ -490,7 +490,7 @@ extension TestChatTransportState { transport.emit( .chat( - MoltbotChatEventPayload( + OpenClawChatEventPayload( runId: runId, sessionKey: "main", state: "aborted", diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ElevenLabsTTSValidationTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ElevenLabsTTSValidationTests.swift similarity index 96% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/ElevenLabsTTSValidationTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/ElevenLabsTTSValidationTests.swift index 0803d6b220..1d672db353 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ElevenLabsTTSValidationTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ElevenLabsTTSValidationTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import MoltbotKit +@testable import OpenClawKit final class ElevenLabsTTSValidationTests: XCTestCase { func testValidatedOutputFormatAllowsOnlyMp3Presets() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/GatewayNodeSessionTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/GatewayNodeSessionTests.swift similarity index 97% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/GatewayNodeSessionTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/GatewayNodeSessionTests.swift index 8a3a120cf0..91e3096159 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/GatewayNodeSessionTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/GatewayNodeSessionTests.swift @@ -1,7 +1,7 @@ import Foundation import Testing -@testable import MoltbotKit -import MoltbotProtocol +@testable import OpenClawKit +import OpenClawProtocol struct GatewayNodeSessionTests { @Test diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/JPEGTranscoderTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/JPEGTranscoderTests.swift similarity index 99% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/JPEGTranscoderTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/JPEGTranscoderTests.swift index b49bdbf416..5070a8b14e 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/JPEGTranscoderTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/JPEGTranscoderTests.swift @@ -1,4 +1,4 @@ -import MoltbotKit +import OpenClawKit import CoreGraphics import ImageIO import Testing diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkDirectiveTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkDirectiveTests.swift similarity index 98% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkDirectiveTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkDirectiveTests.swift index 2b7e637c92..11565ac744 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkDirectiveTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkDirectiveTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import MoltbotKit +@testable import OpenClawKit final class TalkDirectiveTests: XCTestCase { func testParsesDirectiveAndStripsLine() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkHistoryTimestampTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkHistoryTimestampTests.swift similarity index 95% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkHistoryTimestampTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkHistoryTimestampTests.swift index eeb3731435..e66c4e1e9c 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkHistoryTimestampTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkHistoryTimestampTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import MoltbotKit +@testable import OpenClawKit final class TalkHistoryTimestampTests: XCTestCase { func testSecondsTimestampsAreAcceptedWithSmallTolerance() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkPromptBuilderTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkPromptBuilderTests.swift similarity index 95% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkPromptBuilderTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkPromptBuilderTests.swift index 193ad49fac..1ca18fdf32 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/TalkPromptBuilderTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/TalkPromptBuilderTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import MoltbotKit +@testable import OpenClawKit final class TalkPromptBuilderTests: XCTestCase { func testBuildIncludesTranscript() { diff --git a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ToolDisplayRegistryTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ToolDisplayRegistryTests.swift similarity index 75% rename from apps/shared/MoltbotKit/Tests/MoltbotKitTests/ToolDisplayRegistryTests.swift rename to apps/shared/OpenClawKit/Tests/OpenClawKitTests/ToolDisplayRegistryTests.swift index 61c5294376..dbf38138a4 100644 --- a/apps/shared/MoltbotKit/Tests/MoltbotKitTests/ToolDisplayRegistryTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ToolDisplayRegistryTests.swift @@ -1,10 +1,10 @@ -import MoltbotKit +import OpenClawKit import Foundation import Testing @Suite struct ToolDisplayRegistryTests { @Test func loadsToolDisplayConfigFromBundle() { - let url = MoltbotKitResources.bundle.url(forResource: "tool-display", withExtension: "json") + let url = OpenClawKitResources.bundle.url(forResource: "tool-display", withExtension: "json") #expect(url != nil) } diff --git a/apps/shared/MoltbotKit/Tools/CanvasA2UI/bootstrap.js b/apps/shared/OpenClawKit/Tools/CanvasA2UI/bootstrap.js similarity index 91% rename from apps/shared/MoltbotKit/Tools/CanvasA2UI/bootstrap.js rename to apps/shared/OpenClawKit/Tools/CanvasA2UI/bootstrap.js index 7548ace807..59d1cc150d 100644 --- a/apps/shared/MoltbotKit/Tools/CanvasA2UI/bootstrap.js +++ b/apps/shared/OpenClawKit/Tools/CanvasA2UI/bootstrap.js @@ -4,7 +4,7 @@ import { ContextProvider } from "@lit/context"; import { v0_8 } from "@a2ui/lit"; import "@a2ui/lit/ui"; -import { themeContext } from "@moltbot/a2ui-theme-context"; +import { themeContext } from "@openclaw/a2ui-theme-context"; const modalStyles = css` dialog { @@ -42,7 +42,7 @@ const buttonShadow = isAndroid ? "0 2px 10px rgba(6, 182, 212, 0.14)" : "0 10px const statusShadow = isAndroid ? "0 2px 10px rgba(0, 0, 0, 0.18)" : "0 10px 24px rgba(0, 0, 0, 0.25)"; const statusBlur = isAndroid ? "10px" : "14px"; -const moltbotTheme = { +const openclawTheme = { components: { AudioPlayer: emptyClasses(), Button: emptyClasses(), @@ -152,7 +152,7 @@ const moltbotTheme = { }, }; -class MoltbotA2UIHost extends LitElement { +class OpenClawA2UIHost extends LitElement { static properties = { surfaces: { state: true }, pendingAction: { state: true }, @@ -162,7 +162,7 @@ class MoltbotA2UIHost extends LitElement { #processor = v0_8.Data.createSignalA2uiMessageProcessor(); #themeProvider = new ContextProvider(this, { context: themeContext, - initialValue: moltbotTheme, + initialValue: openclawTheme, }); surfaces = []; @@ -177,10 +177,10 @@ class MoltbotA2UIHost extends LitElement { position: relative; box-sizing: border-box; padding: - var(--moltbot-a2ui-inset-top, 0px) - var(--moltbot-a2ui-inset-right, 0px) - var(--moltbot-a2ui-inset-bottom, 0px) - var(--moltbot-a2ui-inset-left, 0px); + var(--openclaw-a2ui-inset-top, 0px) + var(--openclaw-a2ui-inset-right, 0px) + var(--openclaw-a2ui-inset-bottom, 0px) + var(--openclaw-a2ui-inset-left, 0px); } #surfaces { @@ -189,14 +189,14 @@ class MoltbotA2UIHost extends LitElement { gap: 12px; height: 100%; overflow: auto; - padding-bottom: var(--moltbot-a2ui-scroll-pad-bottom, 0px); + padding-bottom: var(--openclaw-a2ui-scroll-pad-bottom, 0px); } .status { position: absolute; left: 50%; transform: translateX(-50%); - top: var(--moltbot-a2ui-status-top, 12px); + top: var(--openclaw-a2ui-status-top, 12px); display: inline-flex; align-items: center; gap: 8px; @@ -217,7 +217,7 @@ class MoltbotA2UIHost extends LitElement { position: absolute; left: 50%; transform: translateX(-50%); - bottom: var(--moltbot-a2ui-toast-bottom, 12px); + bottom: var(--openclaw-a2ui-toast-bottom, 12px); display: inline-flex; align-items: center; gap: 8px; @@ -243,7 +243,7 @@ class MoltbotA2UIHost extends LitElement { position: absolute; left: 50%; transform: translateX(-50%); - top: var(--moltbot-a2ui-empty-top, var(--moltbot-a2ui-status-top, 12px)); + top: var(--openclaw-a2ui-empty-top, var(--openclaw-a2ui-status-top, 12px)); text-align: center; opacity: 0.8; padding: 10px 12px; @@ -281,18 +281,21 @@ class MoltbotA2UIHost extends LitElement { reset: () => this.reset(), getSurfaces: () => Array.from(this.#processor.getSurfaces().keys()), }; - globalThis.moltbotA2UI = api; - globalThis.clawdbotA2UI = api; + globalThis.openclawA2UI = api; this.addEventListener("a2uiaction", (evt) => this.#handleA2UIAction(evt)); this.#statusListener = (evt) => this.#handleActionStatus(evt); - globalThis.addEventListener("moltbot:a2ui-action-status", this.#statusListener); + for (const eventName of ["openclaw:a2ui-action-status"]) { + globalThis.addEventListener(eventName, this.#statusListener); + } this.#syncSurfaces(); } disconnectedCallback() { super.disconnectedCallback(); if (this.#statusListener) { - globalThis.removeEventListener("moltbot:a2ui-action-status", this.#statusListener); + for (const eventName of ["openclaw:a2ui-action-status"]) { + globalThis.removeEventListener(eventName, this.#statusListener); + } this.#statusListener = null; } } @@ -395,20 +398,15 @@ class MoltbotA2UIHost extends LitElement { ...(Object.keys(context).length ? { context } : {}), }; - globalThis.__moltbotLastA2UIAction = userAction; + globalThis.__openclawLastA2UIAction = userAction; const handler = - globalThis.webkit?.messageHandlers?.moltbotCanvasA2UIAction ?? - globalThis.webkit?.messageHandlers?.clawdbotCanvasA2UIAction ?? - globalThis.moltbotCanvasA2UIAction ?? - globalThis.clawdbotCanvasA2UIAction; + globalThis.webkit?.messageHandlers?.openclawCanvasA2UIAction ?? + globalThis.openclawCanvasA2UIAction; if (handler?.postMessage) { try { // WebKit message handlers support structured objects; Android's JS interface expects strings. - if ( - handler === globalThis.moltbotCanvasA2UIAction || - handler === globalThis.clawdbotCanvasA2UIAction - ) { + if (handler === globalThis.openclawCanvasA2UIAction) { handler.postMessage(JSON.stringify({ userAction })); } else { handler.postMessage({ userAction }); @@ -488,4 +486,6 @@ class MoltbotA2UIHost extends LitElement { } } -customElements.define("moltbot-a2ui-host", MoltbotA2UIHost); +if (!customElements.get("openclaw-a2ui-host")) { + customElements.define("openclaw-a2ui-host", OpenClawA2UIHost); +} diff --git a/apps/shared/MoltbotKit/Tools/CanvasA2UI/rolldown.config.mjs b/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs similarity index 96% rename from apps/shared/MoltbotKit/Tools/CanvasA2UI/rolldown.config.mjs rename to apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs index 1b7a9c04e8..dbd4b86fff 100644 --- a/apps/shared/MoltbotKit/Tools/CanvasA2UI/rolldown.config.mjs +++ b/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs @@ -27,7 +27,7 @@ export default defineConfig({ alias: { "@a2ui/lit": path.resolve(a2uiLitDist, "index.js"), "@a2ui/lit/ui": path.resolve(a2uiLitDist, "0.8/ui/ui.js"), - "@moltbot/a2ui-theme-context": a2uiThemeContext, + "@openclaw/a2ui-theme-context": a2uiThemeContext, "@lit/context": path.resolve(repoRoot, "node_modules/@lit/context/index.js"), "@lit/context/": path.resolve(repoRoot, "node_modules/@lit/context/"), "@lit-labs/signals": path.resolve(repoRoot, "node_modules/@lit-labs/signals/index.js"), diff --git a/assets/chrome-extension/README.md b/assets/chrome-extension/README.md index 6700893217..2a2a11a3be 100644 --- a/assets/chrome-extension/README.md +++ b/assets/chrome-extension/README.md @@ -1,16 +1,16 @@ -# Clawdbot Chrome Extension (Browser Relay) +# OpenClaw Chrome Extension (Browser Relay) -Purpose: attach Clawdbot to an existing Chrome tab so the Gateway can automate it (via the local CDP relay server). +Purpose: attach OpenClaw to an existing Chrome tab so the Gateway can automate it (via the local CDP relay server). ## Dev / load unpacked -1. Build/run Clawdbot Gateway with browser control enabled. +1. Build/run OpenClaw Gateway with browser control enabled. 2. Ensure the relay server is reachable at `http://127.0.0.1:18792/` (default). 3. Install the extension to a stable path: ```bash - clawdbot browser extension install - clawdbot browser extension path + openclaw browser extension install + openclaw browser extension path ``` 4. Chrome → `chrome://extensions` → enable “Developer mode”. diff --git a/assets/chrome-extension/background.js b/assets/chrome-extension/background.js index ab1a891e77..31ba401bdd 100644 --- a/assets/chrome-extension/background.js +++ b/assets/chrome-extension/background.js @@ -114,7 +114,7 @@ function onRelayClosed(reason) { setBadge(tabId, 'connecting') void chrome.action.setTitle({ tabId, - title: 'Moltbot Browser Relay: disconnected (click to re-attach)', + title: 'OpenClaw Browser Relay: disconnected (click to re-attach)', }) } tabs.clear() @@ -225,7 +225,7 @@ async function attachTab(tabId, opts = {}) { tabBySession.set(sessionId, tabId) void chrome.action.setTitle({ tabId, - title: 'Moltbot Browser Relay: attached (click to detach)', + title: 'OpenClaw Browser Relay: attached (click to detach)', }) if (!opts.skipAttachedEvent) { @@ -278,7 +278,7 @@ async function detachTab(tabId, reason) { setBadge(tabId, 'off') void chrome.action.setTitle({ tabId, - title: 'Moltbot Browser Relay (click to attach/detach)', + title: 'OpenClaw Browser Relay (click to attach/detach)', }) } @@ -297,7 +297,7 @@ async function connectOrToggleForActiveTab() { setBadge(tabId, 'connecting') void chrome.action.setTitle({ tabId, - title: 'Moltbot Browser Relay: connecting to local relay…', + title: 'OpenClaw Browser Relay: connecting to local relay…', }) try { @@ -308,7 +308,7 @@ async function connectOrToggleForActiveTab() { setBadge(tabId, 'error') void chrome.action.setTitle({ tabId, - title: 'Moltbot Browser Relay: relay not running (open options for setup)', + title: 'OpenClaw Browser Relay: relay not running (open options for setup)', }) void maybeOpenHelpOnce() // Extra breadcrumbs in chrome://extensions service worker logs. diff --git a/assets/chrome-extension/manifest.json b/assets/chrome-extension/manifest.json index 09926ccc57..d6b593990d 100644 --- a/assets/chrome-extension/manifest.json +++ b/assets/chrome-extension/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 3, - "name": "Moltbot Browser Relay", + "name": "OpenClaw Browser Relay", "version": "0.1.0", - "description": "Attach Moltbot to your existing Chrome tab via a local CDP relay server.", + "description": "Attach OpenClaw to your existing Chrome tab via a local CDP relay server.", "icons": { "16": "icons/icon16.png", "32": "icons/icon32.png", @@ -13,7 +13,7 @@ "host_permissions": ["http://127.0.0.1/*", "http://localhost/*"], "background": { "service_worker": "background.js", "type": "module" }, "action": { - "default_title": "Moltbot Browser Relay (click to attach/detach)", + "default_title": "OpenClaw Browser Relay (click to attach/detach)", "default_icon": { "16": "icons/icon16.png", "32": "icons/icon32.png", diff --git a/assets/chrome-extension/options.html b/assets/chrome-extension/options.html index fc4aa368d9..14704d65cf 100644 --- a/assets/chrome-extension/options.html +++ b/assets/chrome-extension/options.html @@ -3,7 +3,7 @@ - Moltbot Browser Relay + OpenClaw Browser Relay - -
    + +
    -
    Ready
    -
    Waiting for agent
    +
    Ready
    +
    Waiting for agent
    - + `; // Check if already injected - if (html.includes("__CLAWDBOT_ASSISTANT_NAME__")) return html; + if (html.includes("__OPENCLAW_ASSISTANT_NAME__")) return html; const headClose = html.indexOf(""); if (headClose !== -1) { return `${html.slice(0, headClose)}${script}${html.slice(headClose)}`; @@ -195,7 +195,7 @@ function injectControlUiConfig(html: string, opts: ControlUiInjectionOpts): stri interface ServeIndexHtmlOpts { basePath: string; - config?: MoltbotConfig; + config?: OpenClawConfig; agentId?: string; } diff --git a/src/gateway/gateway-cli-backend.live.test.ts b/src/gateway/gateway-cli-backend.live.test.ts index c39b34b912..7d547c0af9 100644 --- a/src/gateway/gateway-cli-backend.live.test.ts +++ b/src/gateway/gateway-cli-backend.live.test.ts @@ -12,10 +12,10 @@ import { GatewayClient } from "./client.js"; import { renderCatNoncePngBase64 } from "./live-image-probe.js"; import { startGatewayServer } from "./server.js"; -const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.CLAWDBOT_LIVE_TEST); -const CLI_LIVE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND); -const CLI_IMAGE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_PROBE); -const CLI_RESUME = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND_RESUME_PROBE); +const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST); +const CLI_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND); +const CLI_IMAGE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE); +const CLI_RESUME = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE); const describeLive = LIVE && CLI_LIVE ? describe : describe.skip; const DEFAULT_MODEL = "claude-cli/claude-sonnet-4-5"; @@ -94,7 +94,7 @@ function parseImageMode(raw?: string): "list" | "repeat" | undefined { const trimmed = raw?.trim(); if (!trimmed) return undefined; if (trimmed === "list" || trimmed === "repeat") return trimmed; - throw new Error("CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE must be 'list' or 'repeat'."); + throw new Error("OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE must be 'list' or 'repeat'."); } function withMcpConfigOverrides(args: string[], mcpConfigPath: string): string[] { @@ -181,31 +181,31 @@ async function connectClient(params: { url: string; token: string }) { describeLive("gateway live (cli backend)", () => { it("runs the agent pipeline against the local CLI backend", async () => { const previous = { - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, anthropicApiKey: process.env.ANTHROPIC_API_KEY, anthropicApiKeyOld: process.env.ANTHROPIC_API_KEY_OLD, }; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; delete process.env.ANTHROPIC_API_KEY; delete process.env.ANTHROPIC_API_KEY_OLD; const token = `test-${randomUUID()}`; - process.env.CLAWDBOT_GATEWAY_TOKEN = token; + process.env.OPENCLAW_GATEWAY_TOKEN = token; - const rawModel = process.env.CLAWDBOT_LIVE_CLI_BACKEND_MODEL ?? DEFAULT_MODEL; + const rawModel = process.env.OPENCLAW_LIVE_CLI_BACKEND_MODEL ?? DEFAULT_MODEL; const parsed = parseModelRef(rawModel, "claude-cli"); if (!parsed) { throw new Error( - `CLAWDBOT_LIVE_CLI_BACKEND_MODEL must resolve to a CLI backend model. Got: ${rawModel}`, + `OPENCLAW_LIVE_CLI_BACKEND_MODEL must resolve to a CLI backend model. Got: ${rawModel}`, ); } const providerId = parsed.provider; @@ -218,36 +218,36 @@ describeLive("gateway live (cli backend)", () => { ? { command: "codex", args: DEFAULT_CODEX_ARGS } : null; - const cliCommand = process.env.CLAWDBOT_LIVE_CLI_BACKEND_COMMAND ?? providerDefaults?.command; + const cliCommand = process.env.OPENCLAW_LIVE_CLI_BACKEND_COMMAND ?? providerDefaults?.command; if (!cliCommand) { throw new Error( - `CLAWDBOT_LIVE_CLI_BACKEND_COMMAND is required for provider "${providerId}".`, + `OPENCLAW_LIVE_CLI_BACKEND_COMMAND is required for provider "${providerId}".`, ); } const baseCliArgs = parseJsonStringArray( - "CLAWDBOT_LIVE_CLI_BACKEND_ARGS", - process.env.CLAWDBOT_LIVE_CLI_BACKEND_ARGS, + "OPENCLAW_LIVE_CLI_BACKEND_ARGS", + process.env.OPENCLAW_LIVE_CLI_BACKEND_ARGS, ) ?? providerDefaults?.args; if (!baseCliArgs || baseCliArgs.length === 0) { - throw new Error(`CLAWDBOT_LIVE_CLI_BACKEND_ARGS is required for provider "${providerId}".`); + throw new Error(`OPENCLAW_LIVE_CLI_BACKEND_ARGS is required for provider "${providerId}".`); } const cliClearEnv = parseJsonStringArray( - "CLAWDBOT_LIVE_CLI_BACKEND_CLEAR_ENV", - process.env.CLAWDBOT_LIVE_CLI_BACKEND_CLEAR_ENV, + "OPENCLAW_LIVE_CLI_BACKEND_CLEAR_ENV", + process.env.OPENCLAW_LIVE_CLI_BACKEND_CLEAR_ENV, ) ?? (providerId === "claude-cli" ? DEFAULT_CLEAR_ENV : []); - const cliImageArg = process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_ARG?.trim() || undefined; - const cliImageMode = parseImageMode(process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE); + const cliImageArg = process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG?.trim() || undefined; + const cliImageMode = parseImageMode(process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE); if (cliImageMode && !cliImageArg) { throw new Error( - "CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE requires CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_ARG.", + "OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE requires OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG.", ); } - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-cli-")); - const disableMcpConfig = process.env.CLAWDBOT_LIVE_CLI_BACKEND_DISABLE_MCP_CONFIG !== "0"; + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-cli-")); + const disableMcpConfig = process.env.OPENCLAW_LIVE_CLI_BACKEND_DISABLE_MCP_CONFIG !== "0"; let cliArgs = baseCliArgs; if (providerId === "claude-cli" && disableMcpConfig) { const mcpConfigPath = path.join(tempDir, "claude-mcp.json"); @@ -281,9 +281,9 @@ describeLive("gateway live (cli backend)", () => { }, }, }; - const tempConfigPath = path.join(tempDir, "moltbot.json"); + const tempConfigPath = path.join(tempDir, "openclaw.json"); await fs.writeFile(tempConfigPath, `${JSON.stringify(nextCfg, null, 2)}\n`); - process.env.CLAWDBOT_CONFIG_PATH = tempConfigPath; + process.env.OPENCLAW_CONFIG_PATH = tempConfigPath; const port = await getFreeGatewayPort(); const server = await startGatewayServer(port, { @@ -399,18 +399,18 @@ describeLive("gateway live (cli backend)", () => { client.stop(); await server.close(); await fs.rm(tempDir, { recursive: true, force: true }); - if (previous.configPath === undefined) delete process.env.CLAWDBOT_CONFIG_PATH; - else process.env.CLAWDBOT_CONFIG_PATH = previous.configPath; - if (previous.token === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token; - if (previous.skipChannels === undefined) delete process.env.CLAWDBOT_SKIP_CHANNELS; - else process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels; - if (previous.skipGmail === undefined) delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; - else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail; - if (previous.skipCron === undefined) delete process.env.CLAWDBOT_SKIP_CRON; - else process.env.CLAWDBOT_SKIP_CRON = previous.skipCron; - if (previous.skipCanvas === undefined) delete process.env.CLAWDBOT_SKIP_CANVAS_HOST; - else process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas; + if (previous.configPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH; + else process.env.OPENCLAW_CONFIG_PATH = previous.configPath; + if (previous.token === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = previous.token; + if (previous.skipChannels === undefined) delete process.env.OPENCLAW_SKIP_CHANNELS; + else process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels; + if (previous.skipGmail === undefined) delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; + else process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail; + if (previous.skipCron === undefined) delete process.env.OPENCLAW_SKIP_CRON; + else process.env.OPENCLAW_SKIP_CRON = previous.skipCron; + if (previous.skipCanvas === undefined) delete process.env.OPENCLAW_SKIP_CANVAS_HOST; + else process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas; if (previous.anthropicApiKey === undefined) delete process.env.ANTHROPIC_API_KEY; else process.env.ANTHROPIC_API_KEY = previous.anthropicApiKey; if (previous.anthropicApiKeyOld === undefined) delete process.env.ANTHROPIC_API_KEY_OLD; diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index d3cede10b4..c3b4c3448b 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -7,7 +7,7 @@ import path from "node:path"; import type { Api, Model } from "@mariozechner/pi-ai"; import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent"; import { describe, it } from "vitest"; -import { resolveMoltbotAgentDir } from "../agents/agent-paths.js"; +import { resolveOpenClawAgentDir } from "../agents/agent-paths.js"; import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js"; import { type AuthProfileStore, @@ -21,9 +21,9 @@ import { } from "../agents/live-auth-keys.js"; import { isModernModelRef } from "../agents/live-model-filter.js"; import { getApiKeyForModel } from "../agents/model-auth.js"; -import { ensureMoltbotModelsJson } from "../agents/models-config.js"; +import { ensureOpenClawModelsJson } from "../agents/models-config.js"; import { loadConfig } from "../config/config.js"; -import type { MoltbotConfig, ModelProviderConfig } from "../config/types.js"; +import type { OpenClawConfig, ModelProviderConfig } from "../config/types.js"; import { isTruthyEnvValue } from "../infra/env.js"; import { DEFAULT_AGENT_ID } from "../routing/session-key.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; @@ -31,10 +31,10 @@ import { GatewayClient } from "./client.js"; import { renderCatNoncePngBase64 } from "./live-image-probe.js"; import { startGatewayServer } from "./server.js"; -const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.CLAWDBOT_LIVE_TEST); -const GATEWAY_LIVE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_GATEWAY); -const ZAI_FALLBACK = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_GATEWAY_ZAI_FALLBACK); -const PROVIDERS = parseFilter(process.env.CLAWDBOT_LIVE_GATEWAY_PROVIDERS); +const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST); +const GATEWAY_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY); +const ZAI_FALLBACK = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY_ZAI_FALLBACK); +const PROVIDERS = parseFilter(process.env.OPENCLAW_LIVE_GATEWAY_PROVIDERS); const THINKING_LEVEL = "high"; const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking)\s*>/i; const FINAL_TAG_RE = /<\s*\/?\s*final\s*>/i; @@ -331,7 +331,7 @@ async function connectClient(params: { url: string; token: string }) { type GatewayModelSuiteParams = { label: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; candidates: Array>; extraToolProbes: boolean; extraImageProbes: boolean; @@ -340,10 +340,10 @@ type GatewayModelSuiteParams = { }; function buildLiveGatewayConfig(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; candidates: Array>; providerOverrides?: Record; -}): MoltbotConfig { +}): OpenClawConfig { const providerOverrides = params.providerOverrides ?? {}; const lmstudioProvider = params.cfg.models?.providers?.lmstudio; const baseProviders = params.cfg.models?.providers ?? {}; @@ -382,16 +382,16 @@ function buildLiveGatewayConfig(params: { } function sanitizeAuthConfig(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir: string; -}): MoltbotConfig["auth"] | undefined { +}): OpenClawConfig["auth"] | undefined { const auth = params.cfg.auth; if (!auth) return auth; const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false, }); - let profiles: NonNullable["profiles"] | undefined; + let profiles: NonNullable["profiles"] | undefined; if (auth.profiles) { profiles = {}; for (const [profileId, profile] of Object.entries(auth.profiles)) { @@ -421,7 +421,7 @@ function sanitizeAuthConfig(params: { } function buildMinimaxProviderOverride(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; api: "openai-completions" | "anthropic-messages"; baseUrl: string; }): ModelProviderConfig | null { @@ -436,29 +436,29 @@ function buildMinimaxProviderOverride(params: { async function runGatewayModelSuite(params: GatewayModelSuiteParams) { const previous = { - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, - agentDir: process.env.CLAWDBOT_AGENT_DIR, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, + agentDir: process.env.OPENCLAW_AGENT_DIR, piAgentDir: process.env.PI_CODING_AGENT_DIR, - stateDir: process.env.CLAWDBOT_STATE_DIR, + stateDir: process.env.OPENCLAW_STATE_DIR, }; let tempAgentDir: string | undefined; let tempStateDir: string | undefined; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; const token = `test-${randomUUID()}`; - process.env.CLAWDBOT_GATEWAY_TOKEN = token; + process.env.OPENCLAW_GATEWAY_TOKEN = token; const agentId = "dev"; - const hostAgentDir = resolveMoltbotAgentDir(); + const hostAgentDir = resolveOpenClawAgentDir(); const hostStore = ensureAuthProfileStore(hostAgentDir, { allowKeychainPrompt: false, }); @@ -471,26 +471,26 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { lastGood: hostStore.lastGood ? { ...hostStore.lastGood } : undefined, usageStats: hostStore.usageStats ? { ...hostStore.usageStats } : undefined, }; - tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-state-")); - process.env.CLAWDBOT_STATE_DIR = tempStateDir; + tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-state-")); + process.env.OPENCLAW_STATE_DIR = tempStateDir; tempAgentDir = path.join(tempStateDir, "agents", DEFAULT_AGENT_ID, "agent"); saveAuthProfileStore(sanitizedStore, tempAgentDir); const tempSessionAgentDir = path.join(tempStateDir, "agents", agentId, "agent"); if (tempSessionAgentDir !== tempAgentDir) { saveAuthProfileStore(sanitizedStore, tempSessionAgentDir); } - process.env.CLAWDBOT_AGENT_DIR = tempAgentDir; + process.env.OPENCLAW_AGENT_DIR = tempAgentDir; process.env.PI_CODING_AGENT_DIR = tempAgentDir; const workspaceDir = resolveAgentWorkspaceDir(params.cfg, agentId); await fs.mkdir(workspaceDir, { recursive: true }); const nonceA = randomUUID(); const nonceB = randomUUID(); - const toolProbePath = path.join(workspaceDir, `.clawdbot-live-tool-probe.${nonceA}.txt`); + const toolProbePath = path.join(workspaceDir, `.openclaw-live-tool-probe.${nonceA}.txt`); await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`); - const agentDir = resolveMoltbotAgentDir(); - const sanitizedCfg: MoltbotConfig = { + const agentDir = resolveOpenClawAgentDir(); + const sanitizedCfg: OpenClawConfig = { ...params.cfg, auth: sanitizeAuthConfig({ cfg: params.cfg, agentDir }), }; @@ -499,12 +499,12 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { candidates: params.candidates, providerOverrides: params.providerOverrides, }); - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-")); - const tempConfigPath = path.join(tempDir, "moltbot.json"); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-")); + const tempConfigPath = path.join(tempDir, "openclaw.json"); await fs.writeFile(tempConfigPath, `${JSON.stringify(nextCfg, null, 2)}\n`); - process.env.CLAWDBOT_CONFIG_PATH = tempConfigPath; + process.env.OPENCLAW_CONFIG_PATH = tempConfigPath; - await ensureMoltbotModelsJson(nextCfg); + await ensureOpenClawModelsJson(nextCfg); const port = await getFreeGatewayPort(); const server = await startGatewayServer(port, { @@ -636,7 +636,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { sessionKey, idempotencyKey: `idem-${runIdTool}-tool`, message: - "Moltbot live tool probe (local, safe): " + + "OpenClaw live tool probe (local, safe): " + `use the tool named \`read\` (or \`Read\`) with JSON arguments {"path":"${toolProbePath}"}. ` + "Then reply with the two nonce values you read (include both).", thinking: params.thinkingLevel, @@ -676,7 +676,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { sessionKey, idempotencyKey: `idem-${runIdTool}-exec-read`, message: - "Moltbot live tool probe (local, safe): " + + "OpenClaw live tool probe (local, safe): " + "use the tool named `exec` (or `Exec`) to run this command: " + `mkdir -p "${tempDir}" && printf '%s' '${nonceC}' > "${toolWritePath}". ` + `Then use the tool named \`read\` (or \`Read\`) with JSON arguments {"path":"${toolWritePath}"}. ` + @@ -940,15 +940,15 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { await fs.rm(tempStateDir, { recursive: true, force: true }); } - process.env.CLAWDBOT_CONFIG_PATH = previous.configPath; - process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token; - process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail; - process.env.CLAWDBOT_SKIP_CRON = previous.skipCron; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas; - process.env.CLAWDBOT_AGENT_DIR = previous.agentDir; + process.env.OPENCLAW_CONFIG_PATH = previous.configPath; + process.env.OPENCLAW_GATEWAY_TOKEN = previous.token; + process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail; + process.env.OPENCLAW_SKIP_CRON = previous.skipCron; + process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas; + process.env.OPENCLAW_AGENT_DIR = previous.agentDir; process.env.PI_CODING_AGENT_DIR = previous.piAgentDir; - process.env.CLAWDBOT_STATE_DIR = previous.stateDir; + process.env.OPENCLAW_STATE_DIR = previous.stateDir; } } @@ -957,9 +957,9 @@ describeLive("gateway live (dev agent, profile keys)", () => { "runs meaningful prompts across models with available keys", async () => { const cfg = loadConfig(); - await ensureMoltbotModelsJson(cfg); + await ensureOpenClawModelsJson(cfg); - const agentDir = resolveMoltbotAgentDir(); + const agentDir = resolveOpenClawAgentDir(); const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false, }); @@ -967,7 +967,7 @@ describeLive("gateway live (dev agent, profile keys)", () => { const modelRegistry = discoverModels(authStorage, agentDir); const all = modelRegistry.getAll() as Array>; - const rawModels = process.env.CLAWDBOT_LIVE_GATEWAY_MODELS?.trim(); + const rawModels = process.env.OPENCLAW_LIVE_GATEWAY_MODELS?.trim(); const useModern = !rawModels || rawModels === "modern" || rawModels === "all"; const useExplicit = Boolean(rawModels) && !useModern; const filter = useExplicit ? parseFilter(rawModels) : null; @@ -1044,26 +1044,26 @@ describeLive("gateway live (dev agent, profile keys)", () => { it("z.ai fallback handles anthropic tool history", async () => { if (!ZAI_FALLBACK) return; const previous = { - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, }; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; const token = `test-${randomUUID()}`; - process.env.CLAWDBOT_GATEWAY_TOKEN = token; + process.env.OPENCLAW_GATEWAY_TOKEN = token; const cfg = loadConfig(); - await ensureMoltbotModelsJson(cfg); + await ensureOpenClawModelsJson(cfg); - const agentDir = resolveMoltbotAgentDir(); + const agentDir = resolveOpenClawAgentDir(); const authStorage = discoverAuthStorage(agentDir); const modelRegistry = discoverModels(authStorage, agentDir); const anthropic = modelRegistry.find("anthropic", "claude-opus-4-5") as Model | null; @@ -1082,7 +1082,7 @@ describeLive("gateway live (dev agent, profile keys)", () => { await fs.mkdir(workspaceDir, { recursive: true }); const nonceA = randomUUID(); const nonceB = randomUUID(); - const toolProbePath = path.join(workspaceDir, `.clawdbot-live-zai-fallback.${nonceA}.txt`); + const toolProbePath = path.join(workspaceDir, `.openclaw-live-zai-fallback.${nonceA}.txt`); await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`); const port = await getFreeGatewayPort(); @@ -1173,12 +1173,12 @@ describeLive("gateway live (dev agent, profile keys)", () => { await server.close({ reason: "live test complete" }); await fs.rm(toolProbePath, { force: true }); - process.env.CLAWDBOT_CONFIG_PATH = previous.configPath; - process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token; - process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail; - process.env.CLAWDBOT_SKIP_CRON = previous.skipCron; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas; + process.env.OPENCLAW_CONFIG_PATH = previous.configPath; + process.env.OPENCLAW_GATEWAY_TOKEN = previous.token; + process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail; + process.env.OPENCLAW_SKIP_CRON = previous.skipCron; + process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas; } }, 180_000); }); diff --git a/src/gateway/gateway.e2e.test.ts b/src/gateway/gateway.e2e.test.ts index 372432983c..eb643a9b8f 100644 --- a/src/gateway/gateway.e2e.test.ts +++ b/src/gateway/gateway.e2e.test.ts @@ -29,39 +29,39 @@ describe("gateway e2e", () => { async () => { const prev = { home: process.env.HOME, - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, - skipBrowser: process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, + skipBrowser: process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER, }; const { baseUrl: openaiBaseUrl, restore } = installOpenAiResponsesMock(); - const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-mock-home-")); + const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-mock-home-")); process.env.HOME = tempHome; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; - process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1"; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1"; const token = `test-${randomUUID()}`; - process.env.CLAWDBOT_GATEWAY_TOKEN = token; + process.env.OPENCLAW_GATEWAY_TOKEN = token; - const workspaceDir = path.join(tempHome, "clawd"); + const workspaceDir = path.join(tempHome, "openclaw"); await fs.mkdir(workspaceDir, { recursive: true }); const nonceA = randomUUID(); const nonceB = randomUUID(); - const toolProbePath = path.join(workspaceDir, `.clawdbot-tool-probe.${nonceA}.txt`); + const toolProbePath = path.join(workspaceDir, `.openclaw-tool-probe.${nonceA}.txt`); await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`); - const configDir = path.join(tempHome, ".clawdbot"); + const configDir = path.join(tempHome, ".openclaw"); await fs.mkdir(configDir, { recursive: true }); - const configPath = path.join(configDir, "moltbot.json"); + const configPath = path.join(configDir, "openclaw.json"); const cfg = { agents: { defaults: { workspace: workspaceDir } }, @@ -91,7 +91,7 @@ describe("gateway e2e", () => { }; await fs.writeFile(configPath, `${JSON.stringify(cfg, null, 2)}\n`); - process.env.CLAWDBOT_CONFIG_PATH = configPath; + process.env.OPENCLAW_CONFIG_PATH = configPath; const port = await getFreeGatewayPort(); const server = await startGatewayServer(port, { @@ -141,13 +141,13 @@ describe("gateway e2e", () => { await fs.rm(tempHome, { recursive: true, force: true }); restore(); process.env.HOME = prev.home; - process.env.CLAWDBOT_CONFIG_PATH = prev.configPath; - process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token; - process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail; - process.env.CLAWDBOT_SKIP_CRON = prev.skipCron; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas; - process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser; + process.env.OPENCLAW_CONFIG_PATH = prev.configPath; + process.env.OPENCLAW_GATEWAY_TOKEN = prev.token; + process.env.OPENCLAW_SKIP_CHANNELS = prev.skipChannels; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prev.skipGmail; + process.env.OPENCLAW_SKIP_CRON = prev.skipCron; + process.env.OPENCLAW_SKIP_CANVAS_HOST = prev.skipCanvas; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser; } }, ); @@ -155,27 +155,27 @@ describe("gateway e2e", () => { it("runs wizard over ws and writes auth token config", { timeout: 90_000 }, async () => { const prev = { home: process.env.HOME, - stateDir: process.env.CLAWDBOT_STATE_DIR, - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, - skipBrowser: process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER, + stateDir: process.env.OPENCLAW_STATE_DIR, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, + skipBrowser: process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER, }; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; - process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1"; - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1"; + delete process.env.OPENCLAW_GATEWAY_TOKEN; - const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wizard-home-")); + const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wizard-home-")); process.env.HOME = tempHome; - delete process.env.CLAWDBOT_STATE_DIR; - delete process.env.CLAWDBOT_CONFIG_PATH; + delete process.env.OPENCLAW_STATE_DIR; + delete process.env.OPENCLAW_CONFIG_PATH; const wizardToken = `wiz-${randomUUID()}`; const port = await getFreeGatewayPort(); @@ -263,14 +263,14 @@ describe("gateway e2e", () => { await server2.close({ reason: "wizard auth verify" }); await fs.rm(tempHome, { recursive: true, force: true }); process.env.HOME = prev.home; - process.env.CLAWDBOT_STATE_DIR = prev.stateDir; - process.env.CLAWDBOT_CONFIG_PATH = prev.configPath; - process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token; - process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail; - process.env.CLAWDBOT_SKIP_CRON = prev.skipCron; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas; - process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser; + process.env.OPENCLAW_STATE_DIR = prev.stateDir; + process.env.OPENCLAW_CONFIG_PATH = prev.configPath; + process.env.OPENCLAW_GATEWAY_TOKEN = prev.token; + process.env.OPENCLAW_SKIP_CHANNELS = prev.skipChannels; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prev.skipGmail; + process.env.OPENCLAW_SKIP_CRON = prev.skipCron; + process.env.OPENCLAW_SKIP_CANVAS_HOST = prev.skipCanvas; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser; } }); }); diff --git a/src/gateway/hooks-mapping.test.ts b/src/gateway/hooks-mapping.test.ts index 8900ffd072..e07e2eeaf6 100644 --- a/src/gateway/hooks-mapping.test.ts +++ b/src/gateway/hooks-mapping.test.ts @@ -63,7 +63,7 @@ describe("hooks mapping", () => { }); it("runs transform module", async () => { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-hooks-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-hooks-")); const modPath = path.join(dir, "transform.mjs"); const placeholder = "${" + "payload.name}"; fs.writeFileSync( @@ -99,7 +99,7 @@ describe("hooks mapping", () => { }); it("treats null transform as a handled skip", async () => { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-hooks-skip-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-hooks-skip-")); const modPath = path.join(dir, "transform.mjs"); fs.writeFileSync(modPath, "export default () => null;"); diff --git a/src/gateway/hooks.test.ts b/src/gateway/hooks.test.ts index a943f00ab3..970acde4d2 100644 --- a/src/gateway/hooks.test.ts +++ b/src/gateway/hooks.test.ts @@ -1,6 +1,6 @@ import type { IncomingMessage } from "node:http"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; import { setActivePluginRegistry } from "../plugins/runtime.js"; import { createIMessageTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js"; @@ -26,7 +26,7 @@ describe("gateway hooks helpers", () => { token: "secret", path: "hooks///", }, - } as MoltbotConfig; + } as OpenClawConfig; const resolved = resolveHooksConfig(base); expect(resolved?.basePath).toBe("/hooks"); expect(resolved?.token).toBe("secret"); @@ -35,7 +35,7 @@ describe("gateway hooks helpers", () => { test("resolveHooksConfig rejects root path", () => { const cfg = { hooks: { enabled: true, token: "x", path: "/" }, - } as MoltbotConfig; + } as OpenClawConfig; expect(() => resolveHooksConfig(cfg)).toThrow("hooks.path may not be '/'"); }); @@ -43,7 +43,7 @@ describe("gateway hooks helpers", () => { const req = { headers: { authorization: "Bearer top", - "x-moltbot-token": "header", + "x-openclaw-token": "header", }, } as unknown as IncomingMessage; const url = new URL("http://localhost/hooks/wake?token=query"); @@ -52,7 +52,7 @@ describe("gateway hooks helpers", () => { expect(result1.fromQuery).toBe(false); const req2 = { - headers: { "x-moltbot-token": "header" }, + headers: { "x-openclaw-token": "header" }, } as unknown as IncomingMessage; const result2 = extractHookToken(req2, url); expect(result2.token).toBe("header"); diff --git a/src/gateway/hooks.ts b/src/gateway/hooks.ts index 1fc6d52f4a..cddbb97303 100644 --- a/src/gateway/hooks.ts +++ b/src/gateway/hooks.ts @@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto"; import type { IncomingMessage } from "node:http"; import { listChannelPlugins } from "../channels/plugins/index.js"; import type { ChannelId } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { normalizeMessageChannel } from "../utils/message-channel.js"; import { type HookMappingResolved, resolveHookMappings } from "./hooks-mapping.js"; @@ -16,7 +16,7 @@ export type HooksConfigResolved = { mappings: HookMappingResolved[]; }; -export function resolveHooksConfig(cfg: MoltbotConfig): HooksConfigResolved | null { +export function resolveHooksConfig(cfg: OpenClawConfig): HooksConfigResolved | null { if (cfg.hooks?.enabled !== true) return null; const token = cfg.hooks?.token?.trim(); if (!token) { @@ -54,7 +54,9 @@ export function extractHookToken(req: IncomingMessage, url: URL): HookTokenResul if (token) return { token, fromQuery: false }; } const headerToken = - typeof req.headers["x-moltbot-token"] === "string" ? req.headers["x-moltbot-token"].trim() : ""; + typeof req.headers["x-openclaw-token"] === "string" + ? req.headers["x-openclaw-token"].trim() + : ""; if (headerToken) return { token: headerToken, fromQuery: false }; const queryToken = url.searchParams.get("token"); if (queryToken) return { token: queryToken.trim(), fromQuery: true }; diff --git a/src/gateway/http-utils.ts b/src/gateway/http-utils.ts index b6c9de38d1..f6a6e725a5 100644 --- a/src/gateway/http-utils.ts +++ b/src/gateway/http-utils.ts @@ -19,7 +19,9 @@ export function getBearerToken(req: IncomingMessage): string | undefined { export function resolveAgentIdFromHeader(req: IncomingMessage): string | undefined { const raw = - getHeader(req, "x-moltbot-agent-id")?.trim() || getHeader(req, "x-moltbot-agent")?.trim() || ""; + getHeader(req, "x-openclaw-agent-id")?.trim() || + getHeader(req, "x-openclaw-agent")?.trim() || + ""; if (!raw) return undefined; return normalizeAgentId(raw); } @@ -29,7 +31,7 @@ export function resolveAgentIdFromModel(model: string | undefined): string | und if (!raw) return undefined; const m = - raw.match(/^moltbot[:/](?[a-z0-9][a-z0-9_-]{0,63})$/i) ?? + raw.match(/^openclaw[:/](?[a-z0-9][a-z0-9_-]{0,63})$/i) ?? raw.match(/^agent:(?[a-z0-9][a-z0-9_-]{0,63})$/i); const agentId = m?.groups?.agentId; if (!agentId) return undefined; @@ -53,7 +55,7 @@ export function resolveSessionKey(params: { user?: string | undefined; prefix: string; }): string { - const explicit = getHeader(params.req, "x-moltbot-session-key")?.trim(); + const explicit = getHeader(params.req, "x-openclaw-session-key")?.trim(); if (explicit) return explicit; const user = params.user?.trim(); diff --git a/src/gateway/node-command-policy.ts b/src/gateway/node-command-policy.ts index 0edb5db2a8..2e34a6a130 100644 --- a/src/gateway/node-command-policy.ts +++ b/src/gateway/node-command-policy.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { NodeSession } from "./node-registry.js"; const CANVAS_COMMANDS = [ @@ -75,7 +75,7 @@ function normalizePlatformId(platform?: string, deviceFamily?: string): string { } export function resolveNodeCommandAllowlist( - cfg: MoltbotConfig, + cfg: OpenClawConfig, node?: Pick, ): Set { const platformId = normalizePlatformId(node?.platform, node?.deviceFamily); diff --git a/src/gateway/openai-http.e2e.test.ts b/src/gateway/openai-http.e2e.test.ts index 7068f66235..99698ca729 100644 --- a/src/gateway/openai-http.e2e.test.ts +++ b/src/gateway/openai-http.e2e.test.ts @@ -67,7 +67,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { const server = await startServerWithDefaultConfig(port); try { const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(404); @@ -83,7 +83,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { }); try { const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(404); @@ -124,8 +124,8 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions( port, - { model: "moltbot", messages: [{ role: "user", content: "hi" }] }, - { "x-moltbot-agent-id": "beta" }, + { model: "openclaw", messages: [{ role: "user", content: "hi" }] }, + { "x-openclaw-agent-id": "beta" }, ); expect(res.status).toBe(200); @@ -140,7 +140,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { - model: "moltbot:beta", + model: "openclaw:beta", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(200); @@ -158,10 +158,10 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { const res = await postChatCompletions( port, { - model: "moltbot:beta", + model: "openclaw:beta", messages: [{ role: "user", content: "hi" }], }, - { "x-moltbot-agent-id": "alpha" }, + { "x-openclaw-agent-id": "alpha" }, ); expect(res.status).toBe(200); @@ -177,10 +177,10 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions( port, - { model: "moltbot", messages: [{ role: "user", content: "hi" }] }, + { model: "openclaw", messages: [{ role: "user", content: "hi" }] }, { - "x-moltbot-agent-id": "beta", - "x-moltbot-session-key": "agent:beta:openai:custom", + "x-openclaw-agent-id": "beta", + "x-openclaw-session-key": "agent:beta:openai:custom", }, ); expect(res.status).toBe(200); @@ -196,7 +196,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { user: "alice", - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(200); @@ -211,7 +211,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [ { role: "user", @@ -232,7 +232,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "I am Claude" }]); const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "Hello, who are you?" }, @@ -255,7 +255,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "Hello" }, @@ -274,7 +274,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [ { role: "developer", content: "You are a helpful assistant." }, { role: "user", content: "Hello" }, @@ -292,7 +292,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { mockAgentOnce([{ text: "ok" }]); const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "What's the weather?" }, @@ -316,7 +316,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const res = await postChatCompletions(port, { stream: false, - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(200); @@ -331,7 +331,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { { const res = await postChatCompletions(port, { - model: "moltbot", + model: "openclaw", messages: [{ role: "system", content: "yo" }], }); expect(res.status).toBe(400); @@ -359,7 +359,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { const res = await postChatCompletions(port, { stream: true, - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(res.status).toBe(200); @@ -392,7 +392,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { const repeatedRes = await postChatCompletions(port, { stream: true, - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(repeatedRes.status).toBe(200); @@ -417,7 +417,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => { const fallbackRes = await postChatCompletions(port, { stream: true, - model: "moltbot", + model: "openclaw", messages: [{ role: "user", content: "hi" }], }); expect(fallbackRes.status).toBe(200); diff --git a/src/gateway/openai-http.ts b/src/gateway/openai-http.ts index 5a05f08d5d..2cbcb7c1ff 100644 --- a/src/gateway/openai-http.ts +++ b/src/gateway/openai-http.ts @@ -181,7 +181,7 @@ export async function handleOpenAiHttpRequest( const payload = coerceRequest(body); const stream = Boolean(payload.stream); - const model = typeof payload.model === "string" ? payload.model : "moltbot"; + const model = typeof payload.model === "string" ? payload.model : "openclaw"; const user = typeof payload.user === "string" ? payload.user : undefined; const agentId = resolveAgentIdForRequest({ req, model }); @@ -223,7 +223,7 @@ export async function handleOpenAiHttpRequest( .map((p) => (typeof p.text === "string" ? p.text : "")) .filter(Boolean) .join("\n\n") - : "No response from Moltbot."; + : "No response from OpenClaw."; sendJson(res, 200, { id: runId, @@ -344,7 +344,7 @@ export async function handleOpenAiHttpRequest( .map((p) => (typeof p.text === "string" ? p.text : "")) .filter(Boolean) .join("\n\n") - : "No response from Moltbot."; + : "No response from OpenClaw."; sawAssistantDelta = true; writeSse(res, { diff --git a/src/gateway/openresponses-http.e2e.test.ts b/src/gateway/openresponses-http.e2e.test.ts index ce7df2a1d2..9ae6c2f025 100644 --- a/src/gateway/openresponses-http.e2e.test.ts +++ b/src/gateway/openresponses-http.e2e.test.ts @@ -87,7 +87,7 @@ describe("OpenResponses HTTP API (e2e)", () => { const _server = await startServerWithDefaultConfig(port); try { const res = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", }); expect(res.status).toBe(404); @@ -102,7 +102,7 @@ describe("OpenResponses HTTP API (e2e)", () => { }); try { const res = await postResponses(disabledPort, { - model: "moltbot", + model: "openclaw", input: "hi", }); expect(res.status).toBe(404); @@ -130,7 +130,7 @@ describe("OpenResponses HTTP API (e2e)", () => { const resMissingAuth = await fetch(`http://127.0.0.1:${port}/v1/responses`, { method: "POST", headers: { "content-type": "application/json" }, - body: JSON.stringify({ model: "moltbot", input: "hi" }), + body: JSON.stringify({ model: "openclaw", input: "hi" }), }); expect(resMissingAuth.status).toBe(401); await ensureResponseConsumed(resMissingAuth); @@ -146,8 +146,8 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resHeader = await postResponses( port, - { model: "moltbot", input: "hi" }, - { "x-moltbot-agent-id": "beta" }, + { model: "openclaw", input: "hi" }, + { "x-openclaw-agent-id": "beta" }, ); expect(resHeader.status).toBe(200); const [optsHeader] = agentCommand.mock.calls[0] ?? []; @@ -157,7 +157,7 @@ describe("OpenResponses HTTP API (e2e)", () => { await ensureResponseConsumed(resHeader); mockAgentOnce([{ text: "hello" }]); - const resModel = await postResponses(port, { model: "moltbot:beta", input: "hi" }); + const resModel = await postResponses(port, { model: "openclaw:beta", input: "hi" }); expect(resModel.status).toBe(200); const [optsModel] = agentCommand.mock.calls[0] ?? []; expect((optsModel as { sessionKey?: string } | undefined)?.sessionKey ?? "").toMatch( @@ -168,7 +168,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resUser = await postResponses(port, { user: "alice", - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resUser.status).toBe(200); @@ -180,7 +180,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resString = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hello world", }); expect(resString.status).toBe(200); @@ -190,7 +190,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resArray = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [{ type: "message", role: "user", content: "hello there" }], }); expect(resArray.status).toBe(200); @@ -200,7 +200,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resSystemDeveloper = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [ { type: "message", role: "system", content: "You are a helpful assistant." }, { type: "message", role: "developer", content: "Be concise." }, @@ -218,7 +218,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resInstructions = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", instructions: "Always respond in French.", }); @@ -231,7 +231,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "I am Claude" }]); const resHistory = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [ { type: "message", role: "system", content: "You are a helpful assistant." }, { type: "message", role: "user", content: "Hello, who are you?" }, @@ -251,7 +251,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "ok" }]); const resFunctionOutput = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [ { type: "message", role: "user", content: "What's the weather?" }, { type: "function_call_output", call_id: "call_1", output: "Sunny, 70F." }, @@ -266,7 +266,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "ok" }]); const resInputFile = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [ { type: "message", @@ -297,7 +297,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "ok" }]); const resToolNone = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", tools: [ { @@ -316,7 +316,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "ok" }]); const resToolChoice = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", tools: [ { @@ -340,7 +340,7 @@ describe("OpenResponses HTTP API (e2e)", () => { await ensureResponseConsumed(resToolChoice); const resUnknownTool = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", tools: [ { @@ -355,7 +355,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "ok" }]); const resMaxTokens = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: "hi", max_output_tokens: 123, }); @@ -374,7 +374,7 @@ describe("OpenResponses HTTP API (e2e)", () => { }); const resUsage = await postResponses(port, { stream: false, - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resUsage.status).toBe(200); @@ -385,7 +385,7 @@ describe("OpenResponses HTTP API (e2e)", () => { mockAgentOnce([{ text: "hello" }]); const resShape = await postResponses(port, { stream: false, - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resShape.status).toBe(200); @@ -407,7 +407,7 @@ describe("OpenResponses HTTP API (e2e)", () => { await ensureResponseConsumed(resShape); const resNoUser = await postResponses(port, { - model: "moltbot", + model: "openclaw", input: [{ type: "message", role: "system", content: "yo" }], }); expect(resNoUser.status).toBe(400); @@ -434,7 +434,7 @@ describe("OpenResponses HTTP API (e2e)", () => { const resDelta = await postResponses(port, { stream: true, - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resDelta.status).toBe(200); @@ -470,7 +470,7 @@ describe("OpenResponses HTTP API (e2e)", () => { const resFallback = await postResponses(port, { stream: true, - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resFallback.status).toBe(200); @@ -485,7 +485,7 @@ describe("OpenResponses HTTP API (e2e)", () => { const resTypeMatch = await postResponses(port, { stream: true, - model: "moltbot", + model: "openclaw", input: "hi", }); expect(resTypeMatch.status).toBe(200); diff --git a/src/gateway/openresponses-http.ts b/src/gateway/openresponses-http.ts index 147ca5fb9c..82fef800e6 100644 --- a/src/gateway/openresponses-http.ts +++ b/src/gateway/openresponses-http.ts @@ -1,7 +1,7 @@ /** * OpenResponses HTTP Handler * - * Implements the OpenResponses `/v1/responses` endpoint for Moltbot Gateway. + * Implements the OpenResponses `/v1/responses` endpoint for OpenClaw Gateway. * * @see https://www.open-responses.com/ */ @@ -552,7 +552,7 @@ export async function handleOpenResponsesHttpRequest( .map((p) => (typeof p.text === "string" ? p.text : "")) .filter(Boolean) .join("\n\n") - : "No response from Moltbot."; + : "No response from OpenClaw."; const response = createResponseResource({ id: responseId, @@ -706,7 +706,7 @@ export async function handleOpenResponsesHttpRequest( if (evt.stream === "lifecycle") { const phase = evt.data?.phase; if (phase === "end" || phase === "error") { - const finalText = accumulatedText || "No response from Moltbot."; + const finalText = accumulatedText || "No response from OpenClaw."; const finalStatus = phase === "error" ? "failed" : "completed"; requestFinalize(finalStatus, finalText); } @@ -831,7 +831,7 @@ export async function handleOpenResponsesHttpRequest( .map((p) => (typeof p.text === "string" ? p.text : "")) .filter(Boolean) .join("\n\n") - : "No response from Moltbot."; + : "No response from OpenClaw."; accumulatedText = content; sawAssistantDelta = true; diff --git a/src/gateway/protocol/client-info.ts b/src/gateway/protocol/client-info.ts index bab32ea9c3..9fc39ff119 100644 --- a/src/gateway/protocol/client-info.ts +++ b/src/gateway/protocol/client-info.ts @@ -1,16 +1,16 @@ export const GATEWAY_CLIENT_IDS = { WEBCHAT_UI: "webchat-ui", - CONTROL_UI: "moltbot-control-ui", + CONTROL_UI: "openclaw-control-ui", WEBCHAT: "webchat", CLI: "cli", GATEWAY_CLIENT: "gateway-client", - MACOS_APP: "moltbot-macos", - IOS_APP: "moltbot-ios", - ANDROID_APP: "moltbot-android", + MACOS_APP: "openclaw-macos", + IOS_APP: "openclaw-ios", + ANDROID_APP: "openclaw-android", NODE_HOST: "node-host", TEST: "test", FINGERPRINT: "fingerprint", - PROBE: "moltbot-probe", + PROBE: "openclaw-probe", } as const; export type GatewayClientId = (typeof GATEWAY_CLIENT_IDS)[keyof typeof GATEWAY_CLIENT_IDS]; diff --git a/src/gateway/server-browser.ts b/src/gateway/server-browser.ts index f525348bb8..bbc5060342 100644 --- a/src/gateway/server-browser.ts +++ b/src/gateway/server-browser.ts @@ -5,10 +5,10 @@ export type BrowserControlServer = { }; export async function startBrowserControlServerIfEnabled(): Promise { - if (isTruthyEnvValue(process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER)) return null; + if (isTruthyEnvValue(process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER)) return null; // Lazy import: keeps startup fast, but still bundles for the embedded // gateway (bun --compile) via the static specifier path. - const override = process.env.CLAWDBOT_BROWSER_CONTROL_MODULE?.trim(); + const override = process.env.OPENCLAW_BROWSER_CONTROL_MODULE?.trim(); const mod = override ? await import(override) : await import("../browser/control-service.js"); const start = typeof (mod as { startBrowserControlServiceFromConfig?: unknown }) diff --git a/src/gateway/server-channels.ts b/src/gateway/server-channels.ts index 6f83484301..43c21f0828 100644 --- a/src/gateway/server-channels.ts +++ b/src/gateway/server-channels.ts @@ -1,7 +1,7 @@ import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js"; import { type ChannelId, getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js"; import type { ChannelAccountSnapshot } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { formatErrorMessage } from "../infra/errors.js"; import { resetDirectoryCache } from "../infra/outbound/target-resolver.js"; import type { createSubsystemLogger } from "../logging/subsystem.js"; @@ -45,7 +45,7 @@ function cloneDefaultRuntime(channelId: ChannelId, accountId: string): ChannelAc } type ChannelManagerOptions = { - loadConfig: () => MoltbotConfig; + loadConfig: () => OpenClawConfig; channelLogs: Record; channelRuntimeEnvs: Record; }; diff --git a/src/gateway/server-constants.ts b/src/gateway/server-constants.ts index 0151644759..103b55accf 100644 --- a/src/gateway/server-constants.ts +++ b/src/gateway/server-constants.ts @@ -18,8 +18,8 @@ export const __setMaxChatHistoryMessagesBytesForTest = (value?: number) => { }; export const DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000; export const getHandshakeTimeoutMs = () => { - if (process.env.VITEST && process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS) { - const parsed = Number(process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS); + if (process.env.VITEST && process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS) { + const parsed = Number(process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS); if (Number.isFinite(parsed) && parsed > 0) return parsed; } return DEFAULT_HANDSHAKE_TIMEOUT_MS; diff --git a/src/gateway/server-cron.ts b/src/gateway/server-cron.ts index 9a0c0ca987..46d335c390 100644 --- a/src/gateway/server-cron.ts +++ b/src/gateway/server-cron.ts @@ -26,7 +26,7 @@ export function buildGatewayCronService(params: { }): GatewayCronState { const cronLogger = getChildLogger({ module: "cron" }); const storePath = resolveCronStorePath(params.cfg.cron?.store); - const cronEnabled = process.env.CLAWDBOT_SKIP_CRON !== "1" && params.cfg.cron?.enabled !== false; + const cronEnabled = process.env.OPENCLAW_SKIP_CRON !== "1" && params.cfg.cron?.enabled !== false; const resolveCronAgent = (requested?: string | null) => { const runtimeConfig = loadConfig(); diff --git a/src/gateway/server-discovery-runtime.ts b/src/gateway/server-discovery-runtime.ts index 2dec5883e5..eaf7c964f4 100644 --- a/src/gateway/server-discovery-runtime.ts +++ b/src/gateway/server-discovery-runtime.ts @@ -1,6 +1,6 @@ import { startGatewayBonjourAdvertiser } from "../infra/bonjour.js"; import { pickPrimaryTailnetIPv4, pickPrimaryTailnetIPv6 } from "../infra/tailnet.js"; -import { WIDE_AREA_DISCOVERY_DOMAIN, writeWideAreaGatewayZone } from "../infra/widearea-dns.js"; +import { resolveWideAreaDiscoveryDomain, writeWideAreaGatewayZone } from "../infra/widearea-dns.js"; import { formatBonjourInstanceName, resolveBonjourCliPath, @@ -13,6 +13,7 @@ export async function startGatewayDiscovery(params: { gatewayTls?: { enabled: boolean; fingerprintSha256?: string }; canvasPort?: number; wideAreaDiscoveryEnabled: boolean; + wideAreaDiscoveryDomain?: string | null; tailscaleMode: "off" | "serve" | "funnel"; /** mDNS/Bonjour discovery mode (default: minimal). */ mdnsMode?: "off" | "minimal" | "full"; @@ -23,7 +24,7 @@ export async function startGatewayDiscovery(params: { // mDNS can be disabled via config (mdnsMode: off) or env var. const bonjourEnabled = mdnsMode !== "off" && - process.env.CLAWDBOT_DISABLE_BONJOUR !== "1" && + process.env.OPENCLAW_DISABLE_BONJOUR !== "1" && process.env.NODE_ENV !== "test" && !process.env.VITEST; const mdnsMinimal = mdnsMode !== "full"; @@ -32,7 +33,7 @@ export async function startGatewayDiscovery(params: { const tailnetDns = needsTailnetDns ? await resolveTailnetDnsHint({ enabled: tailscaleEnabled }) : undefined; - const sshPortEnv = mdnsMinimal ? undefined : process.env.CLAWDBOT_SSH_PORT?.trim(); + const sshPortEnv = mdnsMinimal ? undefined : process.env.OPENCLAW_SSH_PORT?.trim(); const sshPortParsed = sshPortEnv ? Number.parseInt(sshPortEnv, 10) : NaN; const sshPort = Number.isFinite(sshPortParsed) && sshPortParsed > 0 ? sshPortParsed : undefined; const cliPath = mdnsMinimal ? undefined : resolveBonjourCliPath(); @@ -57,6 +58,15 @@ export async function startGatewayDiscovery(params: { } if (params.wideAreaDiscoveryEnabled) { + const wideAreaDomain = resolveWideAreaDiscoveryDomain({ + configDomain: params.wideAreaDiscoveryDomain ?? undefined, + }); + if (!wideAreaDomain) { + params.logDiscovery.warn( + "discovery.wideArea.enabled is true, but no domain was configured; set discovery.wideArea.domain to enable unicast DNS-SD", + ); + return { bonjourStop }; + } const tailnetIPv4 = pickPrimaryTailnetIPv4(); if (!tailnetIPv4) { params.logDiscovery.warn( @@ -66,6 +76,7 @@ export async function startGatewayDiscovery(params: { try { const tailnetIPv6 = pickPrimaryTailnetIPv6(); const result = await writeWideAreaGatewayZone({ + domain: wideAreaDomain, gatewayPort: params.port, displayName: formatBonjourInstanceName(params.machineDisplayName), tailnetIPv4, @@ -77,7 +88,7 @@ export async function startGatewayDiscovery(params: { cliPath: resolveBonjourCliPath(), }); params.logDiscovery.info( - `wide-area DNS-SD ${result.changed ? "updated" : "unchanged"} (${WIDE_AREA_DISCOVERY_DOMAIN} → ${result.zonePath})`, + `wide-area DNS-SD ${result.changed ? "updated" : "unchanged"} (${wideAreaDomain} → ${result.zonePath})`, ); } catch (err) { params.logDiscovery.warn(`wide-area discovery update failed: ${String(err)}`); diff --git a/src/gateway/server-discovery.test.ts b/src/gateway/server-discovery.test.ts index 3b7a62b90c..7f0ce113e8 100644 --- a/src/gateway/server-discovery.test.ts +++ b/src/gateway/server-discovery.test.ts @@ -10,21 +10,21 @@ describe("resolveTailnetDnsHint", () => { const prevTailnetDns = { value: undefined as string | undefined }; beforeEach(() => { - prevTailnetDns.value = process.env.CLAWDBOT_TAILNET_DNS; - delete process.env.CLAWDBOT_TAILNET_DNS; + prevTailnetDns.value = process.env.OPENCLAW_TAILNET_DNS; + delete process.env.OPENCLAW_TAILNET_DNS; getTailnetHostname.mockReset(); }); afterEach(() => { if (prevTailnetDns.value === undefined) { - delete process.env.CLAWDBOT_TAILNET_DNS; + delete process.env.OPENCLAW_TAILNET_DNS; } else { - process.env.CLAWDBOT_TAILNET_DNS = prevTailnetDns.value; + process.env.OPENCLAW_TAILNET_DNS = prevTailnetDns.value; } }); test("returns env hint when disabled", async () => { - process.env.CLAWDBOT_TAILNET_DNS = "studio.tailnet.ts.net."; + process.env.OPENCLAW_TAILNET_DNS = "studio.tailnet.ts.net."; const value = await resolveTailnetDnsHint({ enabled: false }); expect(value).toBe("studio.tailnet.ts.net"); expect(getTailnetHostname).not.toHaveBeenCalled(); diff --git a/src/gateway/server-discovery.ts b/src/gateway/server-discovery.ts index 94fd3f2d32..519ab3ba0a 100644 --- a/src/gateway/server-discovery.ts +++ b/src/gateway/server-discovery.ts @@ -13,14 +13,14 @@ export type ResolveBonjourCliPathOptions = { export function formatBonjourInstanceName(displayName: string) { const trimmed = displayName.trim(); - if (!trimmed) return "Moltbot"; - if (/moltbot/i.test(trimmed)) return trimmed; - return `${trimmed} (Moltbot)`; + if (!trimmed) return "OpenClaw"; + if (/openclaw/i.test(trimmed)) return trimmed; + return `${trimmed} (OpenClaw)`; } export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}): string | undefined { const env = opts.env ?? process.env; - const envPath = env.CLAWDBOT_CLI_PATH?.trim(); + const envPath = env.OPENCLAW_CLI_PATH?.trim(); if (envPath) return envPath; const statSync = opts.statSync ?? fs.statSync; @@ -34,7 +34,7 @@ export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}): const execPath = opts.execPath ?? process.execPath; const execDir = path.dirname(execPath); - const siblingCli = path.join(execDir, "moltbot"); + const siblingCli = path.join(execDir, "openclaw"); if (isFile(siblingCli)) return siblingCli; const argv = opts.argv ?? process.argv; @@ -46,7 +46,7 @@ export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}): const cwd = opts.cwd ?? process.cwd(); const distCli = path.join(cwd, "dist", "index.js"); if (isFile(distCli)) return distCli; - const binCli = path.join(cwd, "bin", "moltbot.js"); + const binCli = path.join(cwd, "bin", "openclaw"); if (isFile(binCli)) return binCli; return undefined; @@ -58,7 +58,7 @@ export async function resolveTailnetDnsHint(opts?: { enabled?: boolean; }): Promise { const env = opts?.env ?? process.env; - const envRaw = env.CLAWDBOT_TAILNET_DNS?.trim(); + const envRaw = env.OPENCLAW_TAILNET_DNS?.trim(); const envValue = envRaw && envRaw.length > 0 ? envRaw.replace(/\.$/, "") : ""; if (envValue) return envValue; if (opts?.enabled === false) return undefined; diff --git a/src/gateway/server-http.ts b/src/gateway/server-http.ts index f08dc811ca..e84c0ed431 100644 --- a/src/gateway/server-http.ts +++ b/src/gateway/server-http.ts @@ -87,7 +87,7 @@ export function createHooksRequestHandler( logHooks.warn( "Hook token provided via query parameter is deprecated for security reasons. " + "Tokens in URLs appear in logs, browser history, and referrer headers. " + - "Use Authorization: Bearer or X-Moltbot-Token header instead.", + "Use Authorization: Bearer or X-OpenClaw-Token header instead.", ); } diff --git a/src/gateway/server-methods/channels.ts b/src/gateway/server-methods/channels.ts index 75b1d97771..f0b71761e7 100644 --- a/src/gateway/server-methods/channels.ts +++ b/src/gateway/server-methods/channels.ts @@ -8,7 +8,7 @@ import { import { buildChannelUiCatalog } from "../../channels/plugins/catalog.js"; import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js"; import type { ChannelAccountSnapshot, ChannelPlugin } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { loadConfig, readConfigFileSnapshot } from "../../config/config.js"; import { getChannelActivity } from "../../infra/channel-activity.js"; import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js"; @@ -33,7 +33,7 @@ type ChannelLogoutPayload = { export async function logoutChannelAccount(params: { channelId: ChannelId; accountId?: string | null; - cfg: MoltbotConfig; + cfg: OpenClawConfig; context: GatewayRequestContext; plugin: ChannelPlugin; }): Promise { diff --git a/src/gateway/server-methods/config.ts b/src/gateway/server-methods/config.ts index 4f50562951..833ce7c489 100644 --- a/src/gateway/server-methods/config.ts +++ b/src/gateway/server-methods/config.ts @@ -18,7 +18,7 @@ import { writeRestartSentinel, } from "../../infra/restart-sentinel.js"; import { listChannelPlugins } from "../../channels/plugins/index.js"; -import { loadMoltbotPlugins } from "../../plugins/loader.js"; +import { loadOpenClawPlugins } from "../../plugins/loader.js"; import { ErrorCodes, errorShape, @@ -112,7 +112,7 @@ export const configHandlers: GatewayRequestHandlers = { } const cfg = loadConfig(); const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)); - const pluginRegistry = loadMoltbotPlugins({ + const pluginRegistry = loadOpenClawPlugins({ config: cfg, workspaceDir, logger: { diff --git a/src/gateway/server-methods/logs.test.ts b/src/gateway/server-methods/logs.test.ts index 6a28a23d47..67d6f473da 100644 --- a/src/gateway/server-methods/logs.test.ts +++ b/src/gateway/server-methods/logs.test.ts @@ -16,16 +16,16 @@ describe("logs.tail", () => { }); it("falls back to latest rolling log file when today is missing", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-logs-")); - const older = path.join(tempDir, "moltbot-2026-01-20.log"); - const newer = path.join(tempDir, "moltbot-2026-01-21.log"); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-logs-")); + const older = path.join(tempDir, "openclaw-2026-01-20.log"); + const newer = path.join(tempDir, "openclaw-2026-01-21.log"); await fs.writeFile(older, '{"msg":"old"}\n'); await fs.writeFile(newer, '{"msg":"new"}\n'); await fs.utimes(older, new Date(0), new Date(0)); await fs.utimes(newer, new Date(), new Date()); - setLoggerOverride({ file: path.join(tempDir, "moltbot-2026-01-22.log") }); + setLoggerOverride({ file: path.join(tempDir, "openclaw-2026-01-22.log") }); const respond = vi.fn(); await logsHandlers["logs.tail"]({ diff --git a/src/gateway/server-methods/logs.ts b/src/gateway/server-methods/logs.ts index cda5eed38d..ea4d27cb25 100644 --- a/src/gateway/server-methods/logs.ts +++ b/src/gateway/server-methods/logs.ts @@ -13,7 +13,7 @@ const DEFAULT_LIMIT = 500; const DEFAULT_MAX_BYTES = 250_000; const MAX_LIMIT = 5000; const MAX_BYTES = 1_000_000; -const ROLLING_LOG_RE = /^moltbot-\d{4}-\d{2}-\d{2}\.log$/; +const ROLLING_LOG_RE = /^openclaw-\d{4}-\d{2}-\d{2}\.log$/; function clamp(value: number, min: number, max: number) { return Math.max(min, Math.min(max, value)); diff --git a/src/gateway/server-methods/skills.ts b/src/gateway/server-methods/skills.ts index ceb1020926..829df66c72 100644 --- a/src/gateway/server-methods/skills.ts +++ b/src/gateway/server-methods/skills.ts @@ -2,7 +2,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/ag import { installSkill } from "../../agents/skills-install.js"; import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js"; import { loadWorkspaceSkillEntries, type SkillEntry } from "../../agents/skills.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { loadConfig, writeConfigFile } from "../../config/config.js"; import { getRemoteSkillEligibility } from "../../infra/skills-remote.js"; import { @@ -16,7 +16,7 @@ import { } from "../protocol/index.js"; import type { GatewayRequestHandlers } from "./types.js"; -function listWorkspaceDirs(cfg: MoltbotConfig): string[] { +function listWorkspaceDirs(cfg: OpenClawConfig): string[] { const dirs = new Set(); const list = cfg.agents?.list; if (Array.isArray(list)) { @@ -172,7 +172,7 @@ export const skillsHandlers: GatewayRequestHandlers = { } entries[p.skillKey] = current; skills.entries = entries; - const nextConfig: MoltbotConfig = { + const nextConfig: OpenClawConfig = { ...cfg, skills, }; diff --git a/src/gateway/server-methods/update.ts b/src/gateway/server-methods/update.ts index db8cf2c533..672f54a5f7 100644 --- a/src/gateway/server-methods/update.ts +++ b/src/gateway/server-methods/update.ts @@ -1,4 +1,4 @@ -import { resolveMoltbotPackageRoot } from "../../infra/moltbot-root.js"; +import { resolveOpenClawPackageRoot } from "../../infra/openclaw-root.js"; import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js"; import { formatDoctorNonInteractiveHint, @@ -49,7 +49,7 @@ export const updateHandlers: GatewayRequestHandlers = { let result: Awaited>; try { const root = - (await resolveMoltbotPackageRoot({ + (await resolveOpenClawPackageRoot({ moduleUrl: import.meta.url, argv1: process.argv[1], cwd: process.cwd(), diff --git a/src/gateway/server-plugins.test.ts b/src/gateway/server-plugins.test.ts index 58f47c7de8..0901a5116d 100644 --- a/src/gateway/server-plugins.test.ts +++ b/src/gateway/server-plugins.test.ts @@ -3,10 +3,10 @@ import type { PluginRegistry } from "../plugins/registry.js"; import type { PluginDiagnostic } from "../plugins/types.js"; import { loadGatewayPlugins } from "./server-plugins.js"; -const loadMoltbotPlugins = vi.hoisted(() => vi.fn()); +const loadOpenClawPlugins = vi.hoisted(() => vi.fn()); vi.mock("../plugins/loader.js", () => ({ - loadMoltbotPlugins, + loadOpenClawPlugins, })); const createRegistry = (diagnostics: PluginDiagnostic[]): PluginRegistry => ({ @@ -34,7 +34,7 @@ describe("loadGatewayPlugins", () => { message: "failed to load plugin: boom", }, ]; - loadMoltbotPlugins.mockReturnValue(createRegistry(diagnostics)); + loadOpenClawPlugins.mockReturnValue(createRegistry(diagnostics)); const log = { info: vi.fn(), diff --git a/src/gateway/server-plugins.ts b/src/gateway/server-plugins.ts index fca9142494..e879310c30 100644 --- a/src/gateway/server-plugins.ts +++ b/src/gateway/server-plugins.ts @@ -1,5 +1,5 @@ import type { loadConfig } from "../config/config.js"; -import { loadMoltbotPlugins } from "../plugins/loader.js"; +import { loadOpenClawPlugins } from "../plugins/loader.js"; import type { GatewayRequestHandler } from "./server-methods/types.js"; export function loadGatewayPlugins(params: { @@ -14,7 +14,7 @@ export function loadGatewayPlugins(params: { coreGatewayHandlers: Record; baseMethods: string[]; }) { - const pluginRegistry = loadMoltbotPlugins({ + const pluginRegistry = loadOpenClawPlugins({ config: params.cfg, workspaceDir: params.workspaceDir, logger: { diff --git a/src/gateway/server-reload-handlers.ts b/src/gateway/server-reload-handlers.ts index 6cea5ac020..4d11492699 100644 --- a/src/gateway/server-reload-handlers.ts +++ b/src/gateway/server-reload-handlers.ts @@ -87,7 +87,7 @@ export function createGatewayReloadHandlers(params: { if (plan.restartGmailWatcher) { await stopGmailWatcher().catch(() => {}); - if (!isTruthyEnvValue(process.env.CLAWDBOT_SKIP_GMAIL_WATCHER)) { + if (!isTruthyEnvValue(process.env.OPENCLAW_SKIP_GMAIL_WATCHER)) { try { const gmailResult = await startGmailWatcher(nextConfig); if (gmailResult.started) { @@ -103,17 +103,17 @@ export function createGatewayReloadHandlers(params: { params.logHooks.error(`gmail watcher failed to start: ${String(err)}`); } } else { - params.logHooks.info("skipping gmail watcher restart (CLAWDBOT_SKIP_GMAIL_WATCHER=1)"); + params.logHooks.info("skipping gmail watcher restart (OPENCLAW_SKIP_GMAIL_WATCHER=1)"); } } if (plan.restartChannels.size > 0) { if ( - isTruthyEnvValue(process.env.CLAWDBOT_SKIP_CHANNELS) || - isTruthyEnvValue(process.env.CLAWDBOT_SKIP_PROVIDERS) + isTruthyEnvValue(process.env.OPENCLAW_SKIP_CHANNELS) || + isTruthyEnvValue(process.env.OPENCLAW_SKIP_PROVIDERS) ) { params.logChannels.info( - "skipping channel reload (CLAWDBOT_SKIP_CHANNELS=1 or CLAWDBOT_SKIP_PROVIDERS=1)", + "skipping channel reload (OPENCLAW_SKIP_CHANNELS=1 or OPENCLAW_SKIP_PROVIDERS=1)", ); } else { const restartChannel = async (name: ChannelKind) => { diff --git a/src/gateway/server-runtime-config.ts b/src/gateway/server-runtime-config.ts index 2d699988ab..b8ae4ee1b6 100644 --- a/src/gateway/server-runtime-config.ts +++ b/src/gateway/server-runtime-config.ts @@ -77,12 +77,12 @@ export async function resolveGatewayRuntimeConfig(params: { (authMode === "token" && hasToken) || (authMode === "password" && hasPassword); const hooksConfig = resolveHooksConfig(params.cfg); const canvasHostEnabled = - process.env.CLAWDBOT_SKIP_CANVAS_HOST !== "1" && params.cfg.canvasHost?.enabled !== false; + process.env.OPENCLAW_SKIP_CANVAS_HOST !== "1" && params.cfg.canvasHost?.enabled !== false; assertGatewayAuthConfigured(resolvedAuth); if (tailscaleMode === "funnel" && authMode !== "password") { throw new Error( - "tailscale funnel requires gateway auth mode=password (set gateway.auth.password or CLAWDBOT_GATEWAY_PASSWORD)", + "tailscale funnel requires gateway auth mode=password (set gateway.auth.password or OPENCLAW_GATEWAY_PASSWORD)", ); } if (tailscaleMode !== "off" && !isLoopbackHost(bindHost)) { @@ -90,7 +90,7 @@ export async function resolveGatewayRuntimeConfig(params: { } if (!isLoopbackHost(bindHost) && !hasSharedSecret) { throw new Error( - `refusing to bind gateway to ${bindHost}:${params.port} without auth (set gateway.auth.token/password, or set CLAWDBOT_GATEWAY_TOKEN/CLAWDBOT_GATEWAY_PASSWORD)`, + `refusing to bind gateway to ${bindHost}:${params.port} without auth (set gateway.auth.token/password, or set OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD)`, ); } diff --git a/src/gateway/server-runtime-state.ts b/src/gateway/server-runtime-state.ts index 02b060a3b7..203383a0b1 100644 --- a/src/gateway/server-runtime-state.ts +++ b/src/gateway/server-runtime-state.ts @@ -22,7 +22,7 @@ import type { PluginRegistry } from "../plugins/registry.js"; import type { GatewayTlsRuntime } from "./server/tls.js"; export async function createGatewayRuntimeState(params: { - cfg: import("../config/config.js").MoltbotConfig; + cfg: import("../config/config.js").OpenClawConfig; bindHost: string; port: number; controlUiEnabled: boolean; diff --git a/src/gateway/server-startup.ts b/src/gateway/server-startup.ts index e6bdbb0dcc..8cd30e338c 100644 --- a/src/gateway/server-startup.ts +++ b/src/gateway/server-startup.ts @@ -15,7 +15,7 @@ import { triggerInternalHook, } from "../hooks/internal-hooks.js"; import { loadInternalHooks } from "../hooks/loader.js"; -import type { loadMoltbotPlugins } from "../plugins/loader.js"; +import type { loadOpenClawPlugins } from "../plugins/loader.js"; import { type PluginServicesHandle, startPluginServices } from "../plugins/services.js"; import { startBrowserControlServerIfEnabled } from "./server-browser.js"; import { @@ -25,7 +25,7 @@ import { export async function startGatewaySidecars(params: { cfg: ReturnType; - pluginRegistry: ReturnType; + pluginRegistry: ReturnType; defaultWorkspaceDir: string; deps: CliDeps; startChannels: () => Promise; @@ -38,7 +38,7 @@ export async function startGatewaySidecars(params: { logChannels: { info: (msg: string) => void; error: (msg: string) => void }; logBrowser: { error: (msg: string) => void }; }) { - // Start clawd browser control server (unless disabled via config). + // Start OpenClaw browser control server (unless disabled via config). let browserControl: Awaited> = null; try { browserControl = await startBrowserControlServerIfEnabled(); @@ -47,7 +47,7 @@ export async function startGatewaySidecars(params: { } // Start Gmail watcher if configured (hooks.gmail.account). - if (!isTruthyEnvValue(process.env.CLAWDBOT_SKIP_GMAIL_WATCHER)) { + if (!isTruthyEnvValue(process.env.OPENCLAW_SKIP_GMAIL_WATCHER)) { try { const gmailResult = await startGmailWatcher(params.cfg); if (gmailResult.started) { @@ -112,10 +112,10 @@ export async function startGatewaySidecars(params: { } // Launch configured channels so gateway replies via the surface the message came from. - // Tests can opt out via CLAWDBOT_SKIP_CHANNELS (or legacy CLAWDBOT_SKIP_PROVIDERS). + // Tests can opt out via OPENCLAW_SKIP_CHANNELS (or legacy OPENCLAW_SKIP_PROVIDERS). const skipChannels = - isTruthyEnvValue(process.env.CLAWDBOT_SKIP_CHANNELS) || - isTruthyEnvValue(process.env.CLAWDBOT_SKIP_PROVIDERS); + isTruthyEnvValue(process.env.OPENCLAW_SKIP_CHANNELS) || + isTruthyEnvValue(process.env.OPENCLAW_SKIP_PROVIDERS); if (!skipChannels) { try { await params.startChannels(); @@ -124,7 +124,7 @@ export async function startGatewaySidecars(params: { } } else { params.logChannels.info( - "skipping channel start (CLAWDBOT_SKIP_CHANNELS=1 or CLAWDBOT_SKIP_PROVIDERS=1)", + "skipping channel start (OPENCLAW_SKIP_CHANNELS=1 or OPENCLAW_SKIP_PROVIDERS=1)", ); } diff --git a/src/gateway/server.agent.gateway-server-agent-a.e2e.test.ts b/src/gateway/server.agent.gateway-server-agent-a.e2e.test.ts index ff8f34e67f..5c5be95716 100644 --- a/src/gateway/server.agent.gateway-server-agent-a.e2e.test.ts +++ b/src/gateway/server.agent.gateway-server-agent-a.e2e.test.ts @@ -167,7 +167,7 @@ describe("gateway server agent", () => { test("agent marks implicit delivery when lastTo is stale", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+436769770569"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -199,7 +199,7 @@ describe("gateway server agent", () => { test("agent forwards sessionKey to agentCommand", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -227,7 +227,7 @@ describe("gateway server agent", () => { test("agent derives sessionKey from agentId", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); testState.agentsConfig = { list: [{ id: "ops" }] }; await writeSessionStore({ @@ -285,7 +285,7 @@ describe("gateway server agent", () => { test("agent forwards accountId to agentCommand", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -320,7 +320,7 @@ describe("gateway server agent", () => { test("agent avoids lastAccountId when explicit to is provided", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -353,7 +353,7 @@ describe("gateway server agent", () => { test("agent keeps explicit accountId when explicit to is provided", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -387,7 +387,7 @@ describe("gateway server agent", () => { test("agent falls back to lastAccountId for implicit delivery", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -418,7 +418,7 @@ describe("gateway server agent", () => { test("agent forwards image attachments as images[]", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -459,7 +459,7 @@ describe("gateway server agent", () => { test("agent falls back to whatsapp when delivery requested and no last channel exists", async () => { setRegistry(defaultRegistry); testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -488,7 +488,7 @@ describe("gateway server agent", () => { test("agent routes main last-channel whatsapp", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -521,7 +521,7 @@ describe("gateway server agent", () => { test("agent routes main last-channel telegram", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -553,7 +553,7 @@ describe("gateway server agent", () => { test("agent routes main last-channel discord", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -585,7 +585,7 @@ describe("gateway server agent", () => { test("agent routes main last-channel slack", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -617,7 +617,7 @@ describe("gateway server agent", () => { test("agent routes main last-channel signal", async () => { setRegistry(defaultRegistry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { diff --git a/src/gateway/server.agent.gateway-server-agent-b.e2e.test.ts b/src/gateway/server.agent.gateway-server-agent-b.e2e.test.ts index 7c62b7d836..742117a08c 100644 --- a/src/gateway/server.agent.gateway-server-agent-b.e2e.test.ts +++ b/src/gateway/server.agent.gateway-server-agent-b.e2e.test.ts @@ -137,7 +137,7 @@ describe("gateway server agent", () => { ]); registryState.registry = registry; setActivePluginRegistry(registry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -177,7 +177,7 @@ describe("gateway server agent", () => { ]); registryState.registry = registry; setActivePluginRegistry(registry); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -231,7 +231,7 @@ describe("gateway server agent", () => { test("agent ignores webchat last-channel for routing", async () => { testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -262,7 +262,7 @@ describe("gateway server agent", () => { }); test("agent uses webchat for internal runs when last provider is webchat", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { @@ -395,7 +395,7 @@ describe("gateway server agent", () => { }); test("agent events stream to webchat clients when run context is registered", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { diff --git a/src/gateway/server.auth.e2e.test.ts b/src/gateway/server.auth.e2e.test.ts index ee700ead66..3e2cdd4ce3 100644 --- a/src/gateway/server.auth.e2e.test.ts +++ b/src/gateway/server.auth.e2e.test.ts @@ -49,8 +49,8 @@ describe("gateway server auth/connect", () => { test("closes silent handshakes after timeout", { timeout: 60_000 }, async () => { vi.useRealTimers(); - const prevHandshakeTimeout = process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS; - process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS = "50"; + const prevHandshakeTimeout = process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS; + process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS = "50"; try { const ws = await openWs(port); const handshakeTimeoutMs = getHandshakeTimeoutMs(); @@ -58,9 +58,9 @@ describe("gateway server auth/connect", () => { expect(closed).toBe(true); } finally { if (prevHandshakeTimeout === undefined) { - delete process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS; + delete process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS; } else { - process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS = prevHandshakeTimeout; + process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS = prevHandshakeTimeout; } } }); @@ -220,8 +220,8 @@ describe("gateway server auth/connect", () => { let prevToken: string | undefined; beforeAll(async () => { - prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - process.env.CLAWDBOT_GATEWAY_TOKEN = "secret"; + prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; + process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; port = await getFreePort(); server = await startGatewayServer(port); }); @@ -229,9 +229,9 @@ describe("gateway server auth/connect", () => { afterAll(async () => { await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); @@ -294,9 +294,9 @@ describe("gateway server auth/connect", () => { ws.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); @@ -309,8 +309,8 @@ describe("gateway server auth/connect", () => { trustedProxies: ["127.0.0.1"], }, } as any); - const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - process.env.CLAWDBOT_GATEWAY_TOKEN = "secret"; + const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; + process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; const port = await getFreePort(); const server = await startGatewayServer(port); const ws = new WebSocket(`ws://127.0.0.1:${port}`, { @@ -359,17 +359,17 @@ describe("gateway server auth/connect", () => { ws.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); test("allows control ui with stale device identity when device auth is disabled", async () => { testState.gatewayControlUi = { dangerouslyDisableDeviceAuth: true }; testState.gatewayAuth = { mode: "token", token: "secret" }; - const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - process.env.CLAWDBOT_GATEWAY_TOKEN = "secret"; + const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; + process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; const port = await getFreePort(); const server = await startGatewayServer(port); const ws = await openWs(port); @@ -407,9 +407,9 @@ describe("gateway server auth/connect", () => { ws.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); @@ -443,9 +443,9 @@ describe("gateway server auth/connect", () => { ws2.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); @@ -461,7 +461,7 @@ describe("gateway server auth/connect", () => { const { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } = await import("../utils/message-channel.js"); const { server, ws, port, prevToken } = await startServerWithClient("secret"); - const identityDir = await mkdtemp(join(tmpdir(), "moltbot-device-scope-")); + const identityDir = await mkdtemp(join(tmpdir(), "openclaw-device-scope-")); const identity = loadOrCreateDeviceIdentity(join(identityDir, "device.json")); const client = { id: GATEWAY_CLIENT_NAMES.TEST, @@ -522,9 +522,9 @@ describe("gateway server auth/connect", () => { ws2.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); @@ -560,9 +560,9 @@ describe("gateway server auth/connect", () => { ws2.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); diff --git a/src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts b/src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts index 52e7b714e7..88099ead96 100644 --- a/src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts +++ b/src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts @@ -56,7 +56,7 @@ describe("gateway server chat", () => { const historyMaxBytes = 192 * 1024; __setMaxChatHistoryMessagesBytesForTest(historyMaxBytes); await connectOk(ws); - const sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); tempDirs.push(sessionDir); testState.sessionStorePath = path.join(sessionDir, "sessions.json"); const writeStore = async ( diff --git a/src/gateway/server.chat.gateway-server-chat.e2e.test.ts b/src/gateway/server.chat.gateway-server-chat.e2e.test.ts index f550dc588a..0cc9cee938 100644 --- a/src/gateway/server.chat.gateway-server-chat.e2e.test.ts +++ b/src/gateway/server.chat.gateway-server-chat.e2e.test.ts @@ -100,7 +100,7 @@ describe("gateway server chat", () => { const sessionCall = spy.mock.calls.at(-1)?.[0] as { SessionKey?: string } | undefined; expect(sessionCall?.SessionKey).toBe("agent:main:subagent:abc"); - const sendPolicyDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const sendPolicyDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); tempDirs.push(sendPolicyDir); testState.sessionStorePath = path.join(sendPolicyDir, "sessions.json"); testState.sessionConfig = { @@ -139,7 +139,7 @@ describe("gateway server chat", () => { testState.sessionStorePath = undefined; testState.sessionConfig = undefined; - const agentBlockedDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const agentBlockedDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); tempDirs.push(agentBlockedDir); testState.sessionStorePath = path.join(agentBlockedDir, "sessions.json"); testState.sessionConfig = { @@ -241,7 +241,7 @@ describe("gateway server chat", () => { | undefined; expect(imgOnlyOpts?.images).toEqual([{ type: "image", data: pngB64, mimeType: "image/png" }]); - const historyDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const historyDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); tempDirs.push(historyDir); testState.sessionStorePath = path.join(historyDir, "sessions.json"); await writeSessionStore({ @@ -293,7 +293,7 @@ describe("gateway server chat", () => { }); test("routes chat.send slash commands without agent runs", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); try { testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ @@ -332,7 +332,7 @@ describe("gateway server chat", () => { }); test("agent events include sessionKey and agent.wait covers lifecycle flows", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await writeSessionStore({ entries: { diff --git a/src/gateway/server.config-apply.e2e.test.ts b/src/gateway/server.config-apply.e2e.test.ts index 9547c36645..aa7bfa0b72 100644 --- a/src/gateway/server.config-apply.e2e.test.ts +++ b/src/gateway/server.config-apply.e2e.test.ts @@ -19,16 +19,16 @@ let port = 0; let previousToken: string | undefined; beforeAll(async () => { - previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + previousToken = process.env.OPENCLAW_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; port = await getFreePort(); server = await startGatewayServer(port); }); afterAll(async () => { await server.close(); - if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken; + if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken; }); const openClient = async () => { @@ -49,7 +49,7 @@ describe("gateway config.apply", () => { id, method: "config.apply", params: { - raw: '{ "agents": { "list": [{ "id": "main", "workspace": "~/clawd" }] } }', + raw: '{ "agents": { "list": [{ "id": "main", "workspace": "~/openclaw" }] } }', sessionKey: "agent:main:whatsapp:dm:+15555550123", restartDelayMs: 0, }, @@ -62,7 +62,7 @@ describe("gateway config.apply", () => { expect(res.ok).toBe(true); // Verify sentinel file was created (restart was scheduled) - const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json"); + const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json"); // Wait for file to be written await new Promise((resolve) => setTimeout(resolve, 100)); diff --git a/src/gateway/server.config-patch.e2e.test.ts b/src/gateway/server.config-patch.e2e.test.ts index 193bb4f068..65a5401a1a 100644 --- a/src/gateway/server.config-patch.e2e.test.ts +++ b/src/gateway/server.config-patch.e2e.test.ts @@ -190,7 +190,7 @@ describe("gateway config.patch", () => { ); expect(patchRes.ok).toBe(true); - const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json"); + const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json"); await new Promise((resolve) => setTimeout(resolve, 100)); try { @@ -288,7 +288,7 @@ describe("gateway config.patch", () => { describe("gateway server sessions", () => { it("filters sessions by agentId", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-agents-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-agents-")); testState.sessionConfig = { store: path.join(dir, "{agentId}", "sessions.json"), }; @@ -349,7 +349,7 @@ describe("gateway server sessions", () => { }); it("resolves and patches main alias to default agent main key", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-")); const storePath = path.join(dir, "sessions.json"); testState.sessionStorePath = storePath; testState.agentsConfig = { list: [{ id: "ops", default: true }] }; diff --git a/src/gateway/server.cron.e2e.test.ts b/src/gateway/server.cron.e2e.test.ts index f63efdd943..927ce141e0 100644 --- a/src/gateway/server.cron.e2e.test.ts +++ b/src/gateway/server.cron.e2e.test.ts @@ -50,9 +50,9 @@ async function waitForNonEmptyFile(pathname: string, timeoutMs = 2000) { describe("gateway server cron", () => { test("handles cron CRUD, normalization, and patch semantics", { timeout: 120_000 }, async () => { - const prevSkipCron = process.env.CLAWDBOT_SKIP_CRON; - process.env.CLAWDBOT_SKIP_CRON = "0"; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-cron-")); + const prevSkipCron = process.env.OPENCLAW_SKIP_CRON; + process.env.OPENCLAW_SKIP_CRON = "0"; + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-cron-")); testState.cronStorePath = path.join(dir, "cron", "jobs.json"); testState.sessionConfig = { mainKey: "primary" }; testState.cronEnabled = false; @@ -256,17 +256,17 @@ describe("gateway server cron", () => { testState.sessionConfig = undefined; testState.cronEnabled = undefined; if (prevSkipCron === undefined) { - delete process.env.CLAWDBOT_SKIP_CRON; + delete process.env.OPENCLAW_SKIP_CRON; } else { - process.env.CLAWDBOT_SKIP_CRON = prevSkipCron; + process.env.OPENCLAW_SKIP_CRON = prevSkipCron; } } }); test("writes cron run history and auto-runs due jobs", async () => { - const prevSkipCron = process.env.CLAWDBOT_SKIP_CRON; - process.env.CLAWDBOT_SKIP_CRON = "0"; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-cron-log-")); + const prevSkipCron = process.env.OPENCLAW_SKIP_CRON; + process.env.OPENCLAW_SKIP_CRON = "0"; + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-cron-log-")); testState.cronStorePath = path.join(dir, "cron", "jobs.json"); testState.cronEnabled = undefined; await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true }); @@ -353,9 +353,9 @@ describe("gateway server cron", () => { testState.cronStorePath = undefined; testState.cronEnabled = undefined; if (prevSkipCron === undefined) { - delete process.env.CLAWDBOT_SKIP_CRON; + delete process.env.OPENCLAW_SKIP_CRON; } else { - process.env.CLAWDBOT_SKIP_CRON = prevSkipCron; + process.env.OPENCLAW_SKIP_CRON = prevSkipCron; } } }, 45_000); diff --git a/src/gateway/server.health.e2e.test.ts b/src/gateway/server.health.e2e.test.ts index 29511372ea..17b3abe56c 100644 --- a/src/gateway/server.health.e2e.test.ts +++ b/src/gateway/server.health.e2e.test.ts @@ -28,16 +28,16 @@ let port = 0; let previousToken: string | undefined; beforeAll(async () => { - previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + previousToken = process.env.OPENCLAW_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; port = await getFreePort(); server = await startGatewayServer(port); }); afterAll(async () => { await server.close(); - if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken; + if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken; }); const openClient = async (opts?: Parameters[1]) => { @@ -214,7 +214,7 @@ describe("gateway server health/presence", () => { }); test("presence includes client fingerprint", async () => { - const identityPath = path.join(os.tmpdir(), `moltbot-device-${randomUUID()}.json`); + const identityPath = path.join(os.tmpdir(), `openclaw-device-${randomUUID()}.json`); const identity = loadOrCreateDeviceIdentity(identityPath); const role = "operator"; const scopes: string[] = []; diff --git a/src/gateway/server.hooks.e2e.test.ts b/src/gateway/server.hooks.e2e.test.ts index 0eebeac80f..97e4e37ef4 100644 --- a/src/gateway/server.hooks.e2e.test.ts +++ b/src/gateway/server.hooks.e2e.test.ts @@ -108,7 +108,7 @@ describe("gateway server hooks", () => { method: "POST", headers: { "Content-Type": "application/json", - "x-moltbot-token": "hook-secret", + "x-openclaw-token": "hook-secret", }, body: JSON.stringify({ text: "Header auth" }), }); diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index f641c40769..efa91be768 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -20,7 +20,7 @@ import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js"; import { onHeartbeatEvent } from "../infra/heartbeat-events.js"; import { startHeartbeatRunner } from "../infra/heartbeat-runner.js"; import { getMachineDisplayName } from "../infra/machine-name.js"; -import { ensureMoltbotCliOnPath } from "../infra/path-env.js"; +import { ensureOpenClawCliOnPath } from "../infra/path-env.js"; import { primeRemoteSkillsCache, refreshRemoteBinsForConnectedNodes, @@ -73,7 +73,7 @@ import { attachGatewayWsHandlers } from "./server-ws-runtime.js"; export { __resetModelCatalogCacheForTest } from "./server-model-catalog.js"; -ensureMoltbotCliOnPath(); +ensureOpenClawCliOnPath(); const log = createSubsystemLogger("gateway"); const logCanvas = log.child("canvas"); @@ -149,13 +149,13 @@ export async function startGatewayServer( opts: GatewayServerOptions = {}, ): Promise { // Ensure all default port derivations (browser/canvas) see the actual runtime port. - process.env.CLAWDBOT_GATEWAY_PORT = String(port); + process.env.OPENCLAW_GATEWAY_PORT = String(port); logAcceptedEnvOption({ - key: "CLAWDBOT_RAW_STREAM", + key: "OPENCLAW_RAW_STREAM", description: "raw stream logging enabled", }); logAcceptedEnvOption({ - key: "CLAWDBOT_RAW_STREAM_PATH", + key: "OPENCLAW_RAW_STREAM_PATH", description: "raw stream log path override", }); @@ -169,7 +169,7 @@ export async function startGatewayServer( const { config: migrated, changes } = migrateLegacyConfig(configSnapshot.parsed); if (!migrated) { throw new Error( - `Legacy config entries detected but auto-migration failed. Run "${formatCliCommand("moltbot doctor")}" to migrate.`, + `Legacy config entries detected but auto-migration failed. Run "${formatCliCommand("openclaw doctor")}" to migrate.`, ); } await writeConfigFile(migrated); @@ -191,7 +191,7 @@ export async function startGatewayServer( .join("\n") : "Unknown validation issue."; throw new Error( - `Invalid config at ${configSnapshot.path}.\n${issues}\nRun "${formatCliCommand("moltbot doctor")}" to repair, then retry.`, + `Invalid config at ${configSnapshot.path}.\n${issues}\nRun "${formatCliCommand("openclaw doctor")}" to repair, then retry.`, ); } @@ -351,6 +351,7 @@ export async function startGatewayServer( ? { enabled: true, fingerprintSha256: gatewayTls.fingerprintSha256 } : undefined, wideAreaDiscoveryEnabled: cfgAtStart.discovery?.wideArea?.enabled === true, + wideAreaDiscoveryDomain: cfgAtStart.discovery?.wideArea?.domain, tailscaleMode, mdnsMode: cfgAtStart.discovery?.mdns?.mode, logDiscovery, diff --git a/src/gateway/server.ios-client-id.e2e.test.ts b/src/gateway/server.ios-client-id.e2e.test.ts index 086d14d27e..3c00d23fb1 100644 --- a/src/gateway/server.ios-client-id.e2e.test.ts +++ b/src/gateway/server.ios-client-id.e2e.test.ts @@ -54,11 +54,11 @@ function connectReq( ); } -test("accepts moltbot-ios as a valid gateway client id", async () => { +test("accepts openclaw-ios as a valid gateway client id", async () => { const ws = new WebSocket(`ws://127.0.0.1:${port}`); await new Promise((resolve) => ws.once("open", resolve)); - const res = await connectReq(ws, { clientId: "moltbot-ios", platform: "ios" }); + const res = await connectReq(ws, { clientId: "openclaw-ios", platform: "ios" }); // We don't care if auth fails here; we only care that schema validation accepts the client id. // A schema rejection would close the socket before sending a response. if (!res.ok) { @@ -73,11 +73,11 @@ test("accepts moltbot-ios as a valid gateway client id", async () => { ws.close(); }); -test("accepts moltbot-android as a valid gateway client id", async () => { +test("accepts openclaw-android as a valid gateway client id", async () => { const ws = new WebSocket(`ws://127.0.0.1:${port}`); await new Promise((resolve) => ws.once("open", resolve)); - const res = await connectReq(ws, { clientId: "moltbot-android", platform: "android" }); + const res = await connectReq(ws, { clientId: "openclaw-android", platform: "android" }); // We don't care if auth fails here; we only care that schema validation accepts the client id. // A schema rejection would close the socket before sending a response. if (!res.ok) { diff --git a/src/gateway/server.models-voicewake-misc.e2e.test.ts b/src/gateway/server.models-voicewake-misc.e2e.test.ts index 775013e041..6c1ed968ce 100644 --- a/src/gateway/server.models-voicewake-misc.e2e.test.ts +++ b/src/gateway/server.models-voicewake-misc.e2e.test.ts @@ -93,12 +93,12 @@ const emptyRegistry = createRegistry([]); describe("gateway server models + voicewake", () => { const setTempHome = (homeDir: string) => { const prevHome = process.env.HOME; - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; const prevUserProfile = process.env.USERPROFILE; const prevHomeDrive = process.env.HOMEDRIVE; const prevHomePath = process.env.HOMEPATH; process.env.HOME = homeDir; - process.env.CLAWDBOT_STATE_DIR = path.join(homeDir, ".clawdbot"); + process.env.OPENCLAW_STATE_DIR = path.join(homeDir, ".openclaw"); process.env.USERPROFILE = homeDir; if (process.platform === "win32") { const parsed = path.parse(homeDir); @@ -112,9 +112,9 @@ describe("gateway server models + voicewake", () => { process.env.HOME = prevHome; } if (prevStateDir === undefined) { - delete process.env.CLAWDBOT_STATE_DIR; + delete process.env.OPENCLAW_STATE_DIR; } else { - process.env.CLAWDBOT_STATE_DIR = prevStateDir; + process.env.OPENCLAW_STATE_DIR = prevStateDir; } if (prevUserProfile === undefined) { delete process.env.USERPROFILE; @@ -140,12 +140,12 @@ describe("gateway server models + voicewake", () => { "voicewake.get returns defaults and voicewake.set broadcasts", { timeout: 60_000 }, async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-")); const restoreHome = setTempHome(homeDir); const initial = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get"); expect(initial.ok).toBe(true); - expect(initial.payload?.triggers).toEqual(["clawd", "claude", "computer"]); + expect(initial.payload?.triggers).toEqual(["openclaw", "claude", "computer"]); const changedP = onceMessage<{ type: "event"; @@ -171,7 +171,7 @@ describe("gateway server models + voicewake", () => { expect(after.payload?.triggers).toEqual(["hi", "there"]); const onDisk = JSON.parse( - await fs.readFile(path.join(homeDir, ".clawdbot", "settings", "voicewake.json"), "utf8"), + await fs.readFile(path.join(homeDir, ".openclaw", "settings", "voicewake.json"), "utf8"), ) as { triggers?: unknown; updatedAtMs?: unknown }; expect(onDisk.triggers).toEqual(["hi", "there"]); expect(typeof onDisk.updatedAtMs).toBe("number"); @@ -181,7 +181,7 @@ describe("gateway server models + voicewake", () => { ); test("pushes voicewake.changed to nodes on connect and on updates", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-")); const restoreHome = setTempHome(homeDir); const nodeWs = new WebSocket(`ws://127.0.0.1:${port}`); @@ -203,7 +203,7 @@ describe("gateway server models + voicewake", () => { const first = await firstEventP; expect(first.event).toBe("voicewake.changed"); expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([ - "clawd", + "openclaw", "claude", "computer", ]); @@ -213,14 +213,14 @@ describe("gateway server models + voicewake", () => { (o) => o.type === "event" && o.event === "voicewake.changed", ); const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", { - triggers: ["clawd", "computer"], + triggers: ["openclaw", "computer"], }); expect(setRes.ok).toBe(true); const broadcast = await broadcastP; expect(broadcast.event).toBe("voicewake.changed"); expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([ - "clawd", + "openclaw", "computer", ]); @@ -315,14 +315,14 @@ describe("gateway server models + voicewake", () => { describe("gateway server misc", () => { test("hello-ok advertises the gateway port for canvas host", async () => { - const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - const prevCanvasPort = process.env.CLAWDBOT_CANVAS_HOST_PORT; - process.env.CLAWDBOT_GATEWAY_TOKEN = "secret"; + const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; + const prevCanvasPort = process.env.OPENCLAW_CANVAS_HOST_PORT; + process.env.OPENCLAW_GATEWAY_TOKEN = "secret"; testTailnetIPv4.value = "100.64.0.1"; testState.gatewayBind = "lan"; const canvasPort = await getFreePort(); testState.canvasHostPort = canvasPort; - process.env.CLAWDBOT_CANVAS_HOST_PORT = String(canvasPort); + process.env.OPENCLAW_CANVAS_HOST_PORT = String(canvasPort); const testPort = await getFreePort(); const canvasHostUrl = resolveCanvasHostUrl({ @@ -332,14 +332,14 @@ describe("gateway server misc", () => { }); expect(canvasHostUrl).toBe(`http://100.64.0.1:${canvasPort}`); if (prevToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } if (prevCanvasPort === undefined) { - delete process.env.CLAWDBOT_CANVAS_HOST_PORT; + delete process.env.OPENCLAW_CANVAS_HOST_PORT; } else { - process.env.CLAWDBOT_CANVAS_HOST_PORT = prevCanvasPort; + process.env.OPENCLAW_CANVAS_HOST_PORT = prevCanvasPort; } }); @@ -375,8 +375,8 @@ describe("gateway server misc", () => { }); test("auto-enables configured channel plugins on startup", async () => { - const configPath = process.env.CLAWDBOT_CONFIG_PATH; - if (!configPath) throw new Error("Missing CLAWDBOT_CONFIG_PATH"); + const configPath = process.env.OPENCLAW_CONFIG_PATH; + if (!configPath) throw new Error("Missing OPENCLAW_CONFIG_PATH"); await fs.mkdir(path.dirname(configPath), { recursive: true }); await fs.writeFile( configPath, diff --git a/src/gateway/server.reload.e2e.test.ts b/src/gateway/server.reload.e2e.test.ts index b9fc76d984..f629f0fcf6 100644 --- a/src/gateway/server.reload.e2e.test.ts +++ b/src/gateway/server.reload.e2e.test.ts @@ -172,22 +172,22 @@ describe("gateway hot reload", () => { let prevSkipGmail: string | undefined; beforeEach(() => { - prevSkipChannels = process.env.CLAWDBOT_SKIP_CHANNELS; - prevSkipGmail = process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; - process.env.CLAWDBOT_SKIP_CHANNELS = "0"; - delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; + prevSkipChannels = process.env.OPENCLAW_SKIP_CHANNELS; + prevSkipGmail = process.env.OPENCLAW_SKIP_GMAIL_WATCHER; + process.env.OPENCLAW_SKIP_CHANNELS = "0"; + delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; }); afterEach(() => { if (prevSkipChannels === undefined) { - delete process.env.CLAWDBOT_SKIP_CHANNELS; + delete process.env.OPENCLAW_SKIP_CHANNELS; } else { - process.env.CLAWDBOT_SKIP_CHANNELS = prevSkipChannels; + process.env.OPENCLAW_SKIP_CHANNELS = prevSkipChannels; } if (prevSkipGmail === undefined) { - delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; + delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; } else { - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prevSkipGmail; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prevSkipGmail; } }); diff --git a/src/gateway/server.roles-allowlist-update.e2e.test.ts b/src/gateway/server.roles-allowlist-update.e2e.test.ts index 275970c445..e236cc7dd2 100644 --- a/src/gateway/server.roles-allowlist-update.e2e.test.ts +++ b/src/gateway/server.roles-allowlist-update.e2e.test.ts @@ -176,7 +176,7 @@ describe("gateway update.run", () => { await waitForSignal(() => sigusr1.mock.calls.length > 0); expect(sigusr1).toHaveBeenCalled(); - const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json"); + const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json"); const raw = await fs.readFile(sentinelPath, "utf-8"); const parsed = JSON.parse(raw) as { payload?: { kind?: string; stats?: { mode?: string } }; diff --git a/src/gateway/server.sessions-send.e2e.test.ts b/src/gateway/server.sessions-send.e2e.test.ts index 2829c531e6..c04709abde 100644 --- a/src/gateway/server.sessions-send.e2e.test.ts +++ b/src/gateway/server.sessions-send.e2e.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; -import { createMoltbotTools } from "../agents/moltbot-tools.js"; +import { createOpenClawTools } from "../agents/openclaw-tools.js"; import { resolveSessionTranscriptPath } from "../config/sessions.js"; import { emitAgentEvent } from "../infra/agent-events.js"; import { @@ -19,25 +19,25 @@ let prevGatewayPort: string | undefined; let prevGatewayToken: string | undefined; beforeAll(async () => { - prevGatewayPort = process.env.CLAWDBOT_GATEWAY_PORT; - prevGatewayToken = process.env.CLAWDBOT_GATEWAY_TOKEN; + prevGatewayPort = process.env.OPENCLAW_GATEWAY_PORT; + prevGatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN; gatewayPort = await getFreePort(); - process.env.CLAWDBOT_GATEWAY_PORT = String(gatewayPort); - process.env.CLAWDBOT_GATEWAY_TOKEN = "test-token"; + process.env.OPENCLAW_GATEWAY_PORT = String(gatewayPort); + process.env.OPENCLAW_GATEWAY_TOKEN = "test-token"; server = await startGatewayServer(gatewayPort); }); afterAll(async () => { await server.close(); if (prevGatewayPort === undefined) { - delete process.env.CLAWDBOT_GATEWAY_PORT; + delete process.env.OPENCLAW_GATEWAY_PORT; } else { - process.env.CLAWDBOT_GATEWAY_PORT = prevGatewayPort; + process.env.OPENCLAW_GATEWAY_PORT = prevGatewayPort; } if (prevGatewayToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = prevGatewayToken; + process.env.OPENCLAW_GATEWAY_TOKEN = prevGatewayToken; } }); @@ -86,7 +86,7 @@ describe("sessions_send gateway loopback", () => { }); }); - const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send"); + const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send"); if (!tool) throw new Error("missing sessions_send tool"); const result = await tool.execute("call-loopback", { @@ -151,7 +151,7 @@ describe("sessions_send label lookup", () => { timeoutMs: 5000, }); - const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send"); + const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send"); if (!tool) throw new Error("missing sessions_send tool"); // Send using label instead of sessionKey @@ -171,7 +171,7 @@ describe("sessions_send label lookup", () => { }); it("returns error when label not found", { timeout: 60_000 }, async () => { - const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send"); + const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send"); if (!tool) throw new Error("missing sessions_send tool"); const result = await tool.execute("call-missing-label", { @@ -185,7 +185,7 @@ describe("sessions_send label lookup", () => { }); it("returns error when neither sessionKey nor label provided", { timeout: 60_000 }, async () => { - const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send"); + const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send"); if (!tool) throw new Error("missing sessions_send tool"); const result = await tool.execute("call-no-key", { diff --git a/src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts b/src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts index 5099081c11..5a717a0ec5 100644 --- a/src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts +++ b/src/gateway/server.sessions.gateway-server-sessions-a.e2e.test.ts @@ -48,16 +48,16 @@ let port = 0; let previousToken: string | undefined; beforeAll(async () => { - previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + previousToken = process.env.OPENCLAW_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; port = await getFreePort(); server = await startGatewayServer(port); }); afterAll(async () => { await server.close(); - if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken; + if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken; }); const openClient = async (opts?: Parameters[1]) => { @@ -74,7 +74,7 @@ describe("gateway server sessions", () => { }); test("lists and patches session store via sessions.* RPC", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-")); const storePath = path.join(dir, "sessions.json"); const now = Date.now(); const recent = now - 30_000; @@ -370,7 +370,7 @@ describe("gateway server sessions", () => { }); test("sessions.preview returns transcript previews", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-preview-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-preview-")); const storePath = path.join(dir, "sessions.json"); testState.sessionStorePath = storePath; const sessionId = "sess-preview"; @@ -415,7 +415,7 @@ describe("gateway server sessions", () => { }); test("sessions.delete rejects main and aborts active runs", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-")); const storePath = path.join(dir, "sessions.json"); testState.sessionStorePath = storePath; diff --git a/src/gateway/server/ws-connection/message-handler.ts b/src/gateway/server/ws-connection/message-handler.ts index d1f6ae5118..948d6cefbd 100644 --- a/src/gateway/server/ws-connection/message-handler.ts +++ b/src/gateway/server/ws-connection/message-handler.ts @@ -789,7 +789,7 @@ export function attachGatewayWsMessageHandler(params: { type: "hello-ok", protocol: PROTOCOL_VERSION, server: { - version: process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "dev", + version: process.env.OPENCLAW_VERSION ?? process.env.npm_package_version ?? "dev", commit: process.env.GIT_COMMIT, host: os.hostname(), connId, diff --git a/src/gateway/session-utils.fs.test.ts b/src/gateway/session-utils.fs.test.ts index 3cbbd43439..56a5a059b6 100644 --- a/src/gateway/session-utils.fs.test.ts +++ b/src/gateway/session-utils.fs.test.ts @@ -13,7 +13,7 @@ describe("readFirstUserMessageFromTranscript", () => { let storePath: string; beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-fs-test-")); + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-fs-test-")); storePath = path.join(tmpDir, "sessions.json"); }); @@ -159,7 +159,7 @@ describe("readLastMessagePreviewFromTranscript", () => { let storePath: string; beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-fs-test-")); + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-fs-test-")); storePath = path.join(tmpDir, "sessions.json"); }); @@ -348,7 +348,7 @@ describe("readSessionPreviewItemsFromTranscript", () => { let storePath: string; beforeEach(() => { - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-preview-test-")); + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-preview-test-")); storePath = path.join(tmpDir, "sessions.json"); }); diff --git a/src/gateway/session-utils.fs.ts b/src/gateway/session-utils.fs.ts index d6453ace69..8ab79ce48d 100644 --- a/src/gateway/session-utils.fs.ts +++ b/src/gateway/session-utils.fs.ts @@ -47,7 +47,8 @@ export function resolveSessionTranscriptCandidates( if (agentId) { candidates.push(resolveSessionTranscriptPath(sessionId, agentId)); } - candidates.push(path.join(os.homedir(), ".clawdbot", "sessions", `${sessionId}.jsonl`)); + const home = os.homedir(); + candidates.push(path.join(home, ".openclaw", "sessions", `${sessionId}.jsonl`)); return candidates; } diff --git a/src/gateway/session-utils.test.ts b/src/gateway/session-utils.test.ts index 317a7c91a8..76798db437 100644 --- a/src/gateway/session-utils.test.ts +++ b/src/gateway/session-utils.test.ts @@ -1,7 +1,7 @@ import os from "node:os"; import path from "node:path"; import { describe, expect, test } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { capArrayByJsonBytes, @@ -46,7 +46,7 @@ describe("gateway session utils", () => { const cfg = { session: { mainKey: "work" }, agents: { list: [{ id: "ops", default: true }] }, - } as MoltbotConfig; + } as OpenClawConfig; expect(resolveSessionStoreKey({ cfg, sessionKey: "main" })).toBe("agent:ops:work"); expect(resolveSessionStoreKey({ cfg, sessionKey: "work" })).toBe("agent:ops:work"); expect(resolveSessionStoreKey({ cfg, sessionKey: "agent:ops:main" })).toBe("agent:ops:work"); @@ -56,7 +56,7 @@ describe("gateway session utils", () => { const cfg = { session: { mainKey: "main" }, agents: { list: [{ id: "ops", default: true }] }, - } as MoltbotConfig; + } as OpenClawConfig; expect(resolveSessionStoreKey({ cfg, sessionKey: "discord:group:123" })).toBe( "agent:ops:discord:group:123", ); @@ -69,7 +69,7 @@ describe("gateway session utils", () => { const cfg = { session: { scope: "global", mainKey: "work" }, agents: { list: [{ id: "ops", default: true }] }, - } as MoltbotConfig; + } as OpenClawConfig; expect(resolveSessionStoreKey({ cfg, sessionKey: "main" })).toBe("global"); const target = resolveGatewaySessionStoreTarget({ cfg, key: "main" }); expect(target.canonicalKey).toBe("global"); @@ -79,14 +79,14 @@ describe("gateway session utils", () => { test("resolveGatewaySessionStoreTarget uses canonical key for main alias", () => { const storeTemplate = path.join( os.tmpdir(), - "moltbot-session-utils", + "openclaw-session-utils", "{agentId}", "sessions.json", ); const cfg = { session: { mainKey: "main", store: storeTemplate }, agents: { list: [{ id: "ops", default: true }] }, - } as MoltbotConfig; + } as OpenClawConfig; const target = resolveGatewaySessionStoreTarget({ cfg, key: "main" }); expect(target.canonicalKey).toBe("agent:ops:main"); expect(target.storeKeys).toEqual(expect.arrayContaining(["agent:ops:main", "main"])); @@ -193,7 +193,7 @@ describe("listSessionsFromStore search", () => { const baseCfg = { session: { mainKey: "main" }, agents: { list: [{ id: "main", default: true }] }, - } as MoltbotConfig; + } as OpenClawConfig; const makeStore = (): Record => ({ "agent:main:work-project": { diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index 164be999e9..0cff924c7a 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -5,7 +5,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent import { lookupContextTokens } from "../agents/context.js"; import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js"; import { resolveConfiguredModelRef } from "../agents/model-selection.js"; -import { type MoltbotConfig, loadConfig } from "../config/config.js"; +import { type OpenClawConfig, loadConfig } from "../config/config.js"; import { resolveStateDir } from "../config/paths.js"; import { buildGroupDisplayName, @@ -85,7 +85,7 @@ function isWorkspaceRelativePath(value: string): boolean { } function resolveIdentityAvatarUrl( - cfg: MoltbotConfig, + cfg: OpenClawConfig, agentId: string, avatar: string | undefined, ): string | undefined { @@ -211,7 +211,7 @@ function listExistingAgentIdsFromDisk(): string[] { } } -function listConfiguredAgentIds(cfg: MoltbotConfig): string[] { +function listConfiguredAgentIds(cfg: OpenClawConfig): string[] { const agents = cfg.agents?.list ?? []; if (agents.length > 0) { const ids = new Set(); @@ -239,7 +239,7 @@ function listConfiguredAgentIds(cfg: MoltbotConfig): string[] { return sorted; } -export function listAgentsForGateway(cfg: MoltbotConfig): { +export function listAgentsForGateway(cfg: OpenClawConfig): { defaultId: string; mainKey: string; scope: SessionScope; @@ -301,11 +301,14 @@ function canonicalizeSessionKeyForAgent(agentId: string, key: string): string { return `agent:${normalizeAgentId(agentId)}:${key}`; } -function resolveDefaultStoreAgentId(cfg: MoltbotConfig): string { +function resolveDefaultStoreAgentId(cfg: OpenClawConfig): string { return normalizeAgentId(resolveDefaultAgentId(cfg)); } -export function resolveSessionStoreKey(params: { cfg: MoltbotConfig; sessionKey: string }): string { +export function resolveSessionStoreKey(params: { + cfg: OpenClawConfig; + sessionKey: string; +}): string { const raw = params.sessionKey.trim(); if (!raw) return raw; if (raw === "global" || raw === "unknown") return raw; @@ -330,7 +333,7 @@ export function resolveSessionStoreKey(params: { cfg: MoltbotConfig; sessionKey: return canonicalizeSessionKeyForAgent(agentId, raw); } -function resolveSessionStoreAgentId(cfg: MoltbotConfig, canonicalKey: string): string { +function resolveSessionStoreAgentId(cfg: OpenClawConfig, canonicalKey: string): string { if (canonicalKey === "global" || canonicalKey === "unknown") { return resolveDefaultStoreAgentId(cfg); } @@ -347,7 +350,7 @@ function canonicalizeSpawnedByForAgent(agentId: string, spawnedBy?: string): str return `agent:${normalizeAgentId(agentId)}:${raw}`; } -export function resolveGatewaySessionStoreTarget(params: { cfg: MoltbotConfig; key: string }): { +export function resolveGatewaySessionStoreTarget(params: { cfg: OpenClawConfig; key: string }): { agentId: string; storePath: string; canonicalKey: string; @@ -403,7 +406,7 @@ function mergeSessionEntryIntoCombined(params: { } } -export function loadCombinedSessionStoreForGateway(cfg: MoltbotConfig): { +export function loadCombinedSessionStoreForGateway(cfg: OpenClawConfig): { storePath: string; store: Record; } { @@ -446,7 +449,7 @@ export function loadCombinedSessionStoreForGateway(cfg: MoltbotConfig): { return { storePath, store: combined }; } -export function getSessionDefaults(cfg: MoltbotConfig): GatewaySessionsDefaults { +export function getSessionDefaults(cfg: OpenClawConfig): GatewaySessionsDefaults { const resolved = resolveConfiguredModelRef({ cfg, defaultProvider: DEFAULT_PROVIDER, @@ -464,7 +467,7 @@ export function getSessionDefaults(cfg: MoltbotConfig): GatewaySessionsDefaults } export function resolveSessionModelRef( - cfg: MoltbotConfig, + cfg: OpenClawConfig, entry?: SessionEntry, ): { provider: string; model: string } { const resolved = resolveConfiguredModelRef({ @@ -483,7 +486,7 @@ export function resolveSessionModelRef( } export function listSessionsFromStore(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; storePath: string; store: Record; opts: import("./protocol/index.js").SessionsListParams; diff --git a/src/gateway/sessions-patch.test.ts b/src/gateway/sessions-patch.test.ts index 53e5d93431..ec4a1b7066 100644 --- a/src/gateway/sessions-patch.test.ts +++ b/src/gateway/sessions-patch.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { applySessionsPatchToStore } from "./sessions-patch.js"; @@ -7,7 +7,7 @@ describe("gateway sessions patch", () => { test("persists elevatedLevel=off (does not clear)", async () => { const store: Record = {}; const res = await applySessionsPatchToStore({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, store, storeKey: "agent:main:main", patch: { elevatedLevel: "off" }, @@ -20,7 +20,7 @@ describe("gateway sessions patch", () => { test("persists elevatedLevel=on", async () => { const store: Record = {}; const res = await applySessionsPatchToStore({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, store, storeKey: "agent:main:main", patch: { elevatedLevel: "on" }, @@ -35,7 +35,7 @@ describe("gateway sessions patch", () => { "agent:main:main": { elevatedLevel: "off" } as SessionEntry, }; const res = await applySessionsPatchToStore({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, store, storeKey: "agent:main:main", patch: { elevatedLevel: null }, @@ -48,7 +48,7 @@ describe("gateway sessions patch", () => { test("rejects invalid elevatedLevel values", async () => { const store: Record = {}; const res = await applySessionsPatchToStore({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, store, storeKey: "agent:main:main", patch: { elevatedLevel: "maybe" }, @@ -71,7 +71,7 @@ describe("gateway sessions patch", () => { } as SessionEntry, }; const res = await applySessionsPatchToStore({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, store, storeKey: "agent:main:main", patch: { model: "openai/gpt-5.2" }, diff --git a/src/gateway/sessions-patch.ts b/src/gateway/sessions-patch.ts index 46b5e7c401..3789cbae63 100644 --- a/src/gateway/sessions-patch.ts +++ b/src/gateway/sessions-patch.ts @@ -13,7 +13,7 @@ import { normalizeUsageDisplay, supportsXHighThinking, } from "../auto-reply/thinking.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { isSubagentSessionKey } from "../routing/session-key.js"; import { applyVerboseOverride, parseVerboseOverride } from "../sessions/level-overrides.js"; @@ -56,7 +56,7 @@ function normalizeExecAsk(raw: string): "off" | "on-miss" | "always" | undefined } export async function applySessionsPatchToStore(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; store: Record; storeKey: string; patch: SessionsPatchParams; diff --git a/src/gateway/sessions-resolve.ts b/src/gateway/sessions-resolve.ts index 2d64fa89fc..1bf8edfd23 100644 --- a/src/gateway/sessions-resolve.ts +++ b/src/gateway/sessions-resolve.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadSessionStore } from "../config/sessions.js"; import { parseSessionLabel } from "../sessions/session-label.js"; import { @@ -16,7 +16,7 @@ import { export type SessionsResolveResult = { ok: true; key: string } | { ok: false; error: ErrorShape }; export function resolveSessionKeyFromResolveParams(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; p: SessionsResolveParams; }): SessionsResolveResult { const { cfg, p } = params; diff --git a/src/gateway/test-helpers.mocks.ts b/src/gateway/test-helpers.mocks.ts index 298e52618e..15127ef310 100644 --- a/src/gateway/test-helpers.mocks.ts +++ b/src/gateway/test-helpers.mocks.ts @@ -188,12 +188,12 @@ export const resetTestPluginRegistry = () => { }; const testConfigRoot = { - value: path.join(os.tmpdir(), `moltbot-gateway-test-${process.pid}-${crypto.randomUUID()}`), + value: path.join(os.tmpdir(), `openclaw-gateway-test-${process.pid}-${crypto.randomUUID()}`), }; export const setTestConfigRoot = (root: string) => { testConfigRoot.value = root; - process.env.CLAWDBOT_CONFIG_PATH = path.join(root, "moltbot.json"); + process.env.OPENCLAW_CONFIG_PATH = path.join(root, "openclaw.json"); }; export const testTailnetIPv4 = hoisted.testTailnetIPv4; @@ -271,7 +271,7 @@ vi.mock("../config/sessions.js", async () => { vi.mock("../config/config.js", async () => { const actual = await vi.importActual("../config/config.js"); - const resolveConfigPath = () => path.join(testConfigRoot.value, "moltbot.json"); + const resolveConfigPath = () => path.join(testConfigRoot.value, "openclaw.json"); const hashConfigRaw = (raw: string | null) => crypto .createHash("sha256") @@ -389,7 +389,7 @@ vi.mock("../config/config.js", async () => { : {}; const defaults = { model: { primary: "anthropic/claude-opus-4-5" }, - workspace: path.join(os.tmpdir(), "clawd-gateway-test"), + workspace: path.join(os.tmpdir(), "openclaw-gateway-test"), ...fileDefaults, ...testState.agentConfig, }; @@ -560,5 +560,7 @@ vi.mock("../cli/deps.js", async () => { }; }); -process.env.CLAWDBOT_SKIP_CHANNELS = "1"; -process.env.CLAWDBOT_SKIP_CRON = "1"; +process.env.OPENCLAW_SKIP_CHANNELS = "1"; +process.env.OPENCLAW_SKIP_CRON = "1"; +process.env.OPENCLAW_SKIP_CHANNELS = "1"; +process.env.OPENCLAW_SKIP_CRON = "1"; diff --git a/src/gateway/test-helpers.server.ts b/src/gateway/test-helpers.server.ts index 1541168131..6b8f194718 100644 --- a/src/gateway/test-helpers.server.ts +++ b/src/gateway/test-helpers.server.ts @@ -78,22 +78,22 @@ export async function writeSessionStore(params: { async function setupGatewayTestHome() { previousHome = process.env.HOME; previousUserProfile = process.env.USERPROFILE; - previousStateDir = process.env.CLAWDBOT_STATE_DIR; - previousConfigPath = process.env.CLAWDBOT_CONFIG_PATH; - previousSkipBrowserControl = process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER; - previousSkipGmailWatcher = process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; - previousSkipCanvasHost = process.env.CLAWDBOT_SKIP_CANVAS_HOST; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gateway-home-")); + previousStateDir = process.env.OPENCLAW_STATE_DIR; + previousConfigPath = process.env.OPENCLAW_CONFIG_PATH; + previousSkipBrowserControl = process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER; + previousSkipGmailWatcher = process.env.OPENCLAW_SKIP_GMAIL_WATCHER; + previousSkipCanvasHost = process.env.OPENCLAW_SKIP_CANVAS_HOST; + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-home-")); process.env.HOME = tempHome; process.env.USERPROFILE = tempHome; - process.env.CLAWDBOT_STATE_DIR = path.join(tempHome, ".clawdbot"); - delete process.env.CLAWDBOT_CONFIG_PATH; + process.env.OPENCLAW_STATE_DIR = path.join(tempHome, ".openclaw"); + delete process.env.OPENCLAW_CONFIG_PATH; } function applyGatewaySkipEnv() { - process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; } async function resetGatewayTestState(options: { uniqueConfigRoot: boolean }) { @@ -105,8 +105,8 @@ async function resetGatewayTestState(options: { uniqueConfigRoot: boolean }) { } applyGatewaySkipEnv(); tempConfigRoot = options.uniqueConfigRoot - ? await fs.mkdtemp(path.join(tempHome, "moltbot-test-")) - : path.join(tempHome, ".clawdbot-test"); + ? await fs.mkdtemp(path.join(tempHome, "openclaw-test-")) + : path.join(tempHome, ".openclaw-test"); setTestConfigRoot(tempConfigRoot); sessionStoreSaveDelayMs.value = 0; testTailnetIPv4.value = undefined; @@ -152,17 +152,17 @@ async function cleanupGatewayTestHome(options: { restoreEnv: boolean }) { else process.env.HOME = previousHome; if (previousUserProfile === undefined) delete process.env.USERPROFILE; else process.env.USERPROFILE = previousUserProfile; - if (previousStateDir === undefined) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = previousStateDir; - if (previousConfigPath === undefined) delete process.env.CLAWDBOT_CONFIG_PATH; - else process.env.CLAWDBOT_CONFIG_PATH = previousConfigPath; + if (previousStateDir === undefined) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = previousStateDir; + if (previousConfigPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH; + else process.env.OPENCLAW_CONFIG_PATH = previousConfigPath; if (previousSkipBrowserControl === undefined) - delete process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER; - else process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = previousSkipBrowserControl; - if (previousSkipGmailWatcher === undefined) delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; - else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previousSkipGmailWatcher; - if (previousSkipCanvasHost === undefined) delete process.env.CLAWDBOT_SKIP_CANVAS_HOST; - else process.env.CLAWDBOT_SKIP_CANVAS_HOST = previousSkipCanvasHost; + delete process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER; + else process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = previousSkipBrowserControl; + if (previousSkipGmailWatcher === undefined) delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; + else process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previousSkipGmailWatcher; + if (previousSkipCanvasHost === undefined) delete process.env.OPENCLAW_SKIP_CANVAS_HOST; + else process.env.OPENCLAW_SKIP_CANVAS_HOST = previousSkipCanvasHost; } if (options.restoreEnv && tempHome) { await fs.rm(tempHome, { @@ -259,7 +259,7 @@ export async function startGatewayServer(port: number, opts?: GatewayServerOptio export async function startServerWithClient(token?: string, opts?: GatewayServerOptions) { let port = await getFreePort(); - const prev = process.env.CLAWDBOT_GATEWAY_TOKEN; + const prev = process.env.OPENCLAW_GATEWAY_TOKEN; if (typeof token === "string") { testState.gatewayAuth = { mode: "token", token }; } @@ -269,9 +269,9 @@ export async function startServerWithClient(token?: string, opts?: GatewayServer ? (testState.gatewayAuth as { token?: string }).token : undefined); if (fallbackToken === undefined) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = fallbackToken; + process.env.OPENCLAW_GATEWAY_TOKEN = fallbackToken; } let server: Awaited> | null = null; @@ -348,13 +348,13 @@ export async function connectReq( ? undefined : typeof (testState.gatewayAuth as { token?: unknown } | undefined)?.token === "string" ? ((testState.gatewayAuth as { token?: string }).token ?? undefined) - : process.env.CLAWDBOT_GATEWAY_TOKEN; + : process.env.OPENCLAW_GATEWAY_TOKEN; const defaultPassword = opts?.skipDefaultAuth === true ? undefined : typeof (testState.gatewayAuth as { password?: unknown } | undefined)?.password === "string" ? ((testState.gatewayAuth as { password?: string }).password ?? undefined) - : process.env.CLAWDBOT_GATEWAY_PASSWORD; + : process.env.OPENCLAW_GATEWAY_PASSWORD; const token = opts?.token ?? defaultToken; const password = opts?.password ?? defaultPassword; const requestedScopes = Array.isArray(opts?.scopes) ? opts?.scopes : []; diff --git a/src/gateway/tools-invoke-http.test.ts b/src/gateway/tools-invoke-http.test.ts index 93a295fc81..ef937826c0 100644 --- a/src/gateway/tools-invoke-http.test.ts +++ b/src/gateway/tools-invoke-http.test.ts @@ -13,8 +13,8 @@ installGatewayTestHooks({ scope: "suite" }); beforeEach(() => { // Ensure these tests are not affected by host env vars. - delete process.env.CLAWDBOT_GATEWAY_TOKEN; - delete process.env.CLAWDBOT_GATEWAY_PASSWORD; + delete process.env.OPENCLAW_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_PASSWORD; }); const resolveGatewayToken = (): string => { diff --git a/src/gateway/tools-invoke-http.ts b/src/gateway/tools-invoke-http.ts index bf05e2822a..6637ffd12b 100644 --- a/src/gateway/tools-invoke-http.ts +++ b/src/gateway/tools-invoke-http.ts @@ -1,6 +1,6 @@ import type { IncomingMessage, ServerResponse } from "node:http"; -import { createMoltbotTools } from "../agents/moltbot-tools.js"; +import { createOpenClawTools } from "../agents/openclaw-tools.js"; import { filterToolsByPolicy, resolveEffectiveToolPolicy, @@ -156,8 +156,10 @@ export async function handleToolsInvokeHttpRequest( !rawSessionKey || rawSessionKey === "main" ? resolveMainSessionKey(cfg) : rawSessionKey; // Resolve message channel/account hints (optional headers) for policy inheritance. - const messageChannel = normalizeMessageChannel(getHeader(req, "x-moltbot-message-channel") ?? ""); - const accountId = getHeader(req, "x-moltbot-account-id")?.trim() || undefined; + const messageChannel = normalizeMessageChannel( + getHeader(req, "x-openclaw-message-channel") ?? "", + ); + const accountId = getHeader(req, "x-openclaw-account-id")?.trim() || undefined; const { agentId, @@ -194,7 +196,7 @@ export async function handleToolsInvokeHttpRequest( : undefined; // Build tool list (core + plugin tools). - const allTools = createMoltbotTools({ + const allTools = createOpenClawTools({ agentSessionKey: sessionKey, agentChannel: messageChannel ?? undefined, agentAccountId: accountId, diff --git a/src/git-hooks.test.ts b/src/git-hooks.test.ts index ddb52a4f49..424bec8472 100644 --- a/src/git-hooks.test.ts +++ b/src/git-hooks.test.ts @@ -12,7 +12,7 @@ import { import { setupGitHooks } from "../scripts/setup-git-hooks.js"; function makeTempDir() { - return fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-hooks-")); + return fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-hooks-")); } describe("format-staged helpers", () => { diff --git a/src/hooks/bundled-dir.ts b/src/hooks/bundled-dir.ts index 6ced545e30..1c3e70ca0e 100644 --- a/src/hooks/bundled-dir.ts +++ b/src/hooks/bundled-dir.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; export function resolveBundledHooksDir(): string | undefined { - const override = process.env.CLAWDBOT_BUNDLED_HOOKS_DIR?.trim(); + const override = process.env.OPENCLAW_BUNDLED_HOOKS_DIR?.trim(); if (override) return override; // bun --compile: ship a sibling `hooks/bundled/` next to the executable. @@ -16,7 +16,7 @@ export function resolveBundledHooksDir(): string | undefined { } // npm: resolve `/dist/hooks/bundled` relative to this module (compiled hooks). - // This path works when installed via npm: node_modules/moltbot/dist/hooks/bundled-dir.js + // This path works when installed via npm: node_modules/openclaw/dist/hooks/bundled-dir.js try { const moduleDir = path.dirname(fileURLToPath(import.meta.url)); const distBundled = path.join(moduleDir, "bundled"); diff --git a/src/hooks/bundled/README.md b/src/hooks/bundled/README.md index 77df25ee41..b842d7909f 100644 --- a/src/hooks/bundled/README.md +++ b/src/hooks/bundled/README.md @@ -1,6 +1,6 @@ # Bundled Hooks -This directory contains hooks that ship with Clawdbot. These hooks are automatically discovered and can be enabled/disabled via CLI or configuration. +This directory contains hooks that ship with OpenClaw. These hooks are automatically discovered and can be enabled/disabled via CLI or configuration. ## Available Hooks @@ -10,12 +10,12 @@ Automatically saves session context to memory when you issue `/new`. **Events**: `command:new` **What it does**: Creates a dated memory file with LLM-generated slug based on conversation content. -**Output**: `/memory/YYYY-MM-DD-slug.md` (defaults to `~/clawd`) +**Output**: `/memory/YYYY-MM-DD-slug.md` (defaults to `~/.openclaw/workspace`) **Enable**: ```bash -clawdbot hooks enable session-memory +openclaw hooks enable session-memory ``` ### 📝 command-logger @@ -24,12 +24,12 @@ Logs all command events to a centralized audit file. **Events**: `command` (all commands) **What it does**: Appends JSONL entries to command log file. -**Output**: `~/.clawdbot/logs/commands.log` +**Output**: `~/.openclaw/logs/commands.log` **Enable**: ```bash -clawdbot hooks enable command-logger +openclaw hooks enable command-logger ``` ### 😈 soul-evil @@ -39,12 +39,12 @@ Swaps injected `SOUL.md` content with `SOUL_EVIL.md` during a purge window or by **Events**: `agent:bootstrap` **What it does**: Overrides the injected SOUL content before the system prompt is built. **Output**: No files written; swaps happen in-memory only. -**Docs**: https://docs.molt.bot/hooks/soul-evil +**Docs**: https://docs.openclaw.ai/hooks/soul-evil **Enable**: ```bash -clawdbot hooks enable soul-evil +openclaw hooks enable soul-evil ``` ### 🚀 boot-md @@ -58,7 +58,7 @@ Runs `BOOT.md` whenever the gateway starts (after channels start). **Enable**: ```bash -clawdbot hooks enable boot-md +openclaw hooks enable boot-md ``` ## Hook Structure @@ -82,9 +82,9 @@ session-memory/ --- name: my-hook description: "Short description" -homepage: https://docs.molt.bot/hooks#my-hook +homepage: https://docs.openclaw.ai/hooks#my-hook metadata: - { "clawdbot": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } } + { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } } --- # Hook Title @@ -108,7 +108,7 @@ Documentation goes here... To create your own hooks, place them in: - **Workspace hooks**: `/hooks/` (highest precedence) -- **Managed hooks**: `~/.clawdbot/hooks/` (shared across workspaces) +- **Managed hooks**: `~/.openclaw/hooks/` (shared across workspaces) Custom hooks follow the same structure as bundled hooks. @@ -117,31 +117,31 @@ Custom hooks follow the same structure as bundled hooks. List all hooks: ```bash -clawdbot hooks list +openclaw hooks list ``` Show hook details: ```bash -clawdbot hooks info session-memory +openclaw hooks info session-memory ``` Check hook status: ```bash -clawdbot hooks check +openclaw hooks check ``` Enable/disable: ```bash -clawdbot hooks enable session-memory -clawdbot hooks disable command-logger +openclaw hooks enable session-memory +openclaw hooks disable command-logger ``` ## Configuration -Hooks can be configured in `~/.clawdbot/clawdbot.json`: +Hooks can be configured in `~/.openclaw/openclaw.json`: ```json { @@ -214,11 +214,11 @@ export default myHandler; Test your hooks by: 1. Place hook in workspace hooks directory -2. Restart gateway: `pkill -9 -f 'clawdbot.*gateway' && pnpm clawdbot gateway` -3. Enable the hook: `clawdbot hooks enable my-hook` +2. Restart gateway: `pkill -9 -f 'openclaw.*gateway' && pnpm openclaw gateway` +3. Enable the hook: `openclaw hooks enable my-hook` 4. Trigger the event (e.g., send `/new` command) 5. Check gateway logs for hook execution ## Documentation -Full documentation: https://docs.molt.bot/hooks +Full documentation: https://docs.openclaw.ai/hooks diff --git a/src/hooks/bundled/boot-md/HOOK.md b/src/hooks/bundled/boot-md/HOOK.md index 545a604fef..59755318cc 100644 --- a/src/hooks/bundled/boot-md/HOOK.md +++ b/src/hooks/bundled/boot-md/HOOK.md @@ -1,15 +1,15 @@ --- name: boot-md description: "Run BOOT.md on gateway startup" -homepage: https://docs.molt.bot/hooks#boot-md +homepage: https://docs.openclaw.ai/hooks#boot-md metadata: { - "moltbot": + "openclaw": { "emoji": "🚀", "events": ["gateway:startup"], "requires": { "config": ["workspace.dir"] }, - "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }], + "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }], }, } --- diff --git a/src/hooks/bundled/boot-md/handler.ts b/src/hooks/bundled/boot-md/handler.ts index 0133435870..6d41a144b4 100644 --- a/src/hooks/bundled/boot-md/handler.ts +++ b/src/hooks/bundled/boot-md/handler.ts @@ -1,11 +1,11 @@ import type { CliDeps } from "../../../cli/deps.js"; import { createDefaultDeps } from "../../../cli/deps.js"; -import type { MoltbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import { runBootOnce } from "../../../gateway/boot.js"; import type { HookHandler } from "../../hooks.js"; type BootHookContext = { - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; workspaceDir?: string; deps?: CliDeps; }; diff --git a/src/hooks/bundled/command-logger/HOOK.md b/src/hooks/bundled/command-logger/HOOK.md index 897c3e0fbf..dd7636c7d9 100644 --- a/src/hooks/bundled/command-logger/HOOK.md +++ b/src/hooks/bundled/command-logger/HOOK.md @@ -1,14 +1,14 @@ --- name: command-logger description: "Log all command events to a centralized audit file" -homepage: https://docs.molt.bot/hooks#command-logger +homepage: https://docs.openclaw.ai/hooks#command-logger metadata: { - "moltbot": + "openclaw": { "emoji": "📝", "events": ["command"], - "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }], + "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }], }, } --- @@ -22,7 +22,7 @@ Logs all command events (`/new`, `/reset`, `/stop`, etc.) to a centralized audit Every time you issue a command to the agent: 1. **Captures event details** - Command action, timestamp, session key, sender ID, source -2. **Appends to log file** - Writes a JSON line to `~/.clawdbot/logs/commands.log` +2. **Appends to log file** - Writes a JSON line to `~/.openclaw/logs/commands.log` 3. **Silent operation** - Runs in the background without user notifications ## Output Format @@ -43,7 +43,7 @@ Log entries are written in JSONL (JSON Lines) format: ## Log File Location -`~/.clawdbot/logs/commands.log` +`~/.openclaw/logs/commands.log` ## Requirements @@ -62,7 +62,7 @@ No configuration needed. The hook automatically: To disable this hook: ```bash -moltbot hooks disable command-logger +openclaw hooks disable command-logger ``` Or via config: @@ -86,13 +86,13 @@ The hook does not automatically rotate logs. To manage log size, you can: 1. **Manual rotation**: ```bash - mv ~/.clawdbot/logs/commands.log ~/.clawdbot/logs/commands.log.old + mv ~/.openclaw/logs/commands.log ~/.openclaw/logs/commands.log.old ``` 2. **Use logrotate** (Linux): - Create `/etc/logrotate.d/moltbot`: + Create `/etc/logrotate.d/openclaw`: ``` - /home/username/.clawdbot/logs/commands.log { + /home/username/.openclaw/logs/commands.log { weekly rotate 4 compress @@ -106,17 +106,17 @@ The hook does not automatically rotate logs. To manage log size, you can: View recent commands: ```bash -tail -n 20 ~/.clawdbot/logs/commands.log +tail -n 20 ~/.openclaw/logs/commands.log ``` Pretty-print with jq: ```bash -cat ~/.clawdbot/logs/commands.log | jq . +cat ~/.openclaw/logs/commands.log | jq . ``` Filter by action: ```bash -grep '"action":"new"' ~/.clawdbot/logs/commands.log | jq . +grep '"action":"new"' ~/.openclaw/logs/commands.log | jq . ``` diff --git a/src/hooks/bundled/command-logger/handler.ts b/src/hooks/bundled/command-logger/handler.ts index c89bfc0d1f..c292c68f79 100644 --- a/src/hooks/bundled/command-logger/handler.ts +++ b/src/hooks/bundled/command-logger/handler.ts @@ -39,7 +39,8 @@ const logCommand: HookHandler = async (event) => { try { // Create log directory - const logDir = path.join(os.homedir(), ".clawdbot", "logs"); + const stateDir = process.env.OPENCLAW_STATE_DIR?.trim() || path.join(os.homedir(), ".openclaw"); + const logDir = path.join(stateDir, "logs"); await fs.mkdir(logDir, { recursive: true }); // Append to command log file diff --git a/src/hooks/bundled/session-memory/HOOK.md b/src/hooks/bundled/session-memory/HOOK.md index 41223eb058..20b5985761 100644 --- a/src/hooks/bundled/session-memory/HOOK.md +++ b/src/hooks/bundled/session-memory/HOOK.md @@ -1,15 +1,15 @@ --- name: session-memory description: "Save session context to memory when /new command is issued" -homepage: https://docs.molt.bot/hooks#session-memory +homepage: https://docs.openclaw.ai/hooks#session-memory metadata: { - "moltbot": + "openclaw": { "emoji": "💾", "events": ["command:new"], "requires": { "config": ["workspace.dir"] }, - "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }], + "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }], }, } --- @@ -82,7 +82,7 @@ Example configuration: The hook automatically: -- Uses your workspace directory (`~/clawd` by default) +- Uses your workspace directory (`~/.openclaw/workspace` by default) - Uses your configured LLM for slug generation - Falls back to timestamp slugs if LLM is unavailable @@ -91,7 +91,7 @@ The hook automatically: To disable this hook: ```bash -moltbot hooks disable session-memory +openclaw hooks disable session-memory ``` Or remove it from your config: diff --git a/src/hooks/bundled/session-memory/handler.test.ts b/src/hooks/bundled/session-memory/handler.test.ts index 525e210599..c6bf1ae719 100644 --- a/src/hooks/bundled/session-memory/handler.test.ts +++ b/src/hooks/bundled/session-memory/handler.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import handler from "./handler.js"; import { createHookEvent } from "../../hooks.js"; -import type { ClawdbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import { makeTempWorkspace, writeWorkspaceFile } from "../../../test-helpers/workspace.js"; /** @@ -33,7 +33,7 @@ function createMockSessionContent( describe("session-memory hook", () => { it("skips non-command events", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const event = createHookEvent("agent", "bootstrap", "agent:main:main", { workspaceDir: tempDir, @@ -47,7 +47,7 @@ describe("session-memory hook", () => { }); it("skips commands other than new", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const event = createHookEvent("command", "help", "agent:main:main", { workspaceDir: tempDir, @@ -61,7 +61,7 @@ describe("session-memory hook", () => { }); it("creates memory file with session content on /new command", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -78,7 +78,7 @@ describe("session-memory hook", () => { content: sessionContent, }); - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, }; @@ -106,7 +106,7 @@ describe("session-memory hook", () => { }); it("filters out non-message entries (tool calls, system)", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -124,7 +124,7 @@ describe("session-memory hook", () => { content: sessionContent, }); - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, }; @@ -153,7 +153,7 @@ describe("session-memory hook", () => { }); it("filters out command messages starting with /", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -169,7 +169,7 @@ describe("session-memory hook", () => { content: sessionContent, }); - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, }; @@ -196,7 +196,7 @@ describe("session-memory hook", () => { }); it("respects custom messages config (limits to N messages)", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -213,7 +213,7 @@ describe("session-memory hook", () => { }); // Configure to only include last 3 messages - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, hooks: { internal: { @@ -247,7 +247,7 @@ describe("session-memory hook", () => { }); it("filters messages before slicing (fix for #2681)", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -274,7 +274,7 @@ describe("session-memory hook", () => { // Request 3 messages - if we sliced first, we'd only get 1-2 messages // because the last 3 lines include tool entries - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, hooks: { internal: { @@ -307,7 +307,7 @@ describe("session-memory hook", () => { }); it("handles empty session files gracefully", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -317,7 +317,7 @@ describe("session-memory hook", () => { content: "", }); - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, }; @@ -339,7 +339,7 @@ describe("session-memory hook", () => { }); it("handles session files with fewer messages than requested", async () => { - const tempDir = await makeTempWorkspace("clawdbot-session-memory-"); + const tempDir = await makeTempWorkspace("openclaw-session-memory-"); const sessionsDir = path.join(tempDir, "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); @@ -354,7 +354,7 @@ describe("session-memory hook", () => { content: sessionContent, }); - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tempDir } }, }; diff --git a/src/hooks/bundled/session-memory/handler.ts b/src/hooks/bundled/session-memory/handler.ts index 5b5a69c9c1..af3b82c771 100644 --- a/src/hooks/bundled/session-memory/handler.ts +++ b/src/hooks/bundled/session-memory/handler.ts @@ -9,7 +9,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import os from "node:os"; import { fileURLToPath } from "node:url"; -import type { MoltbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import { resolveAgentWorkspaceDir } from "../../../agents/agent-scope.js"; import { resolveAgentIdFromSessionKey } from "../../../routing/session-key.js"; import { resolveHookConfig } from "../../config.js"; @@ -71,11 +71,11 @@ const saveSessionToMemory: HookHandler = async (event) => { console.log("[session-memory] Hook triggered for /new command"); const context = event.context || {}; - const cfg = context.cfg as MoltbotConfig | undefined; + const cfg = context.cfg as OpenClawConfig | undefined; const agentId = resolveAgentIdFromSessionKey(event.sessionKey); const workspaceDir = cfg ? resolveAgentWorkspaceDir(cfg, agentId) - : path.join(os.homedir(), "clawd"); + : path.join(os.homedir(), ".openclaw", "workspace"); const memoryDir = path.join(workspaceDir, "memory"); await fs.mkdir(memoryDir, { recursive: true }); @@ -117,8 +117,8 @@ const saveSessionToMemory: HookHandler = async (event) => { // Dynamically import the LLM slug generator (avoids module caching issues) // When compiled, handler is at dist/hooks/bundled/session-memory/handler.js // Going up ../.. puts us at dist/hooks/, so just add llm-slug-generator.js - const moltbotRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); - const slugGenPath = path.join(moltbotRoot, "llm-slug-generator.js"); + const openclawRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); + const slugGenPath = path.join(openclawRoot, "llm-slug-generator.js"); const { generateSlugViaLLM } = await import(slugGenPath); // Use LLM to generate a descriptive slug diff --git a/src/hooks/bundled/soul-evil/HOOK.md b/src/hooks/bundled/soul-evil/HOOK.md index 4a3a554a21..c3bc81b2dd 100644 --- a/src/hooks/bundled/soul-evil/HOOK.md +++ b/src/hooks/bundled/soul-evil/HOOK.md @@ -1,15 +1,15 @@ --- name: soul-evil description: "Swap SOUL.md with SOUL_EVIL.md during a purge window or by random chance" -homepage: https://docs.molt.bot/hooks/soul-evil +homepage: https://docs.openclaw.ai/hooks/soul-evil metadata: { - "moltbot": + "openclaw": { "emoji": "😈", "events": ["agent:bootstrap"], "requires": { "config": ["hooks.internal.entries.soul-evil.enabled"] }, - "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }], + "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }], }, } --- @@ -31,7 +31,7 @@ You can change the filename via hook config. ## Configuration -Add this to your config (`~/.clawdbot/moltbot.json`): +Add this to your config (`~/.openclaw/openclaw.json`): ```json { @@ -67,5 +67,5 @@ Add this to your config (`~/.clawdbot/moltbot.json`): ## Enable ```bash -moltbot hooks enable soul-evil +openclaw hooks enable soul-evil ``` diff --git a/src/hooks/bundled/soul-evil/README.md b/src/hooks/bundled/soul-evil/README.md index a49bfe33df..a90af5c075 100644 --- a/src/hooks/bundled/soul-evil/README.md +++ b/src/hooks/bundled/soul-evil/README.md @@ -1,11 +1,11 @@ # SOUL Evil Hook -Small persona swap hook for Clawdbot. +Small persona swap hook for OpenClaw. -Docs: https://docs.molt.bot/hooks/soul-evil +Docs: https://docs.openclaw.ai/hooks/soul-evil ## Setup -1. `clawdbot hooks enable soul-evil` +1. `openclaw hooks enable soul-evil` 2. Create `SOUL_EVIL.md` next to `SOUL.md` in your agent workspace 3. Configure `hooks.internal.entries.soul-evil` (see docs) diff --git a/src/hooks/bundled/soul-evil/handler.test.ts b/src/hooks/bundled/soul-evil/handler.test.ts index 133b428fc5..c7a2844e7b 100644 --- a/src/hooks/bundled/soul-evil/handler.test.ts +++ b/src/hooks/bundled/soul-evil/handler.test.ts @@ -5,19 +5,19 @@ import { describe, expect, it } from "vitest"; import handler from "./handler.js"; import { createHookEvent } from "../../hooks.js"; import type { AgentBootstrapHookContext } from "../../hooks.js"; -import type { MoltbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import { makeTempWorkspace, writeWorkspaceFile } from "../../../test-helpers/workspace.js"; describe("soul-evil hook", () => { it("skips subagent sessions", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); await writeWorkspaceFile({ dir: tempDir, name: "SOUL_EVIL.md", content: "chaotic", }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { entries: { diff --git a/src/hooks/bundled/soul-evil/handler.ts b/src/hooks/bundled/soul-evil/handler.ts index 2df0956b23..6b39518b1c 100644 --- a/src/hooks/bundled/soul-evil/handler.ts +++ b/src/hooks/bundled/soul-evil/handler.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import { isSubagentSessionKey } from "../../../routing/session-key.js"; import { resolveHookConfig } from "../../config.js"; import { isAgentBootstrapEvent, type HookHandler } from "../../hooks.js"; @@ -11,7 +11,7 @@ const soulEvilHook: HookHandler = async (event) => { const context = event.context; if (context.sessionKey && isSubagentSessionKey(context.sessionKey)) return; - const cfg = context.cfg as MoltbotConfig | undefined; + const cfg = context.cfg as OpenClawConfig | undefined; const hookConfig = resolveHookConfig(cfg, HOOK_KEY); if (!hookConfig || hookConfig.enabled === false) return; diff --git a/src/hooks/config.ts b/src/hooks/config.ts index b9b9c0fb2e..8a1da761d4 100644 --- a/src/hooks/config.ts +++ b/src/hooks/config.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import type { MoltbotConfig, HookConfig } from "../config/config.js"; +import type { OpenClawConfig, HookConfig } from "../config/config.js"; import { resolveHookKey } from "./frontmatter.js"; import type { HookEligibilityContext, HookEntry } from "./types.js"; @@ -18,7 +18,7 @@ function isTruthy(value: unknown): boolean { return true; } -export function resolveConfigPath(config: MoltbotConfig | undefined, pathStr: string) { +export function resolveConfigPath(config: OpenClawConfig | undefined, pathStr: string) { const parts = pathStr.split(".").filter(Boolean); let current: unknown = config; for (const part of parts) { @@ -28,7 +28,7 @@ export function resolveConfigPath(config: MoltbotConfig | undefined, pathStr: st return current; } -export function isConfigPathTruthy(config: MoltbotConfig | undefined, pathStr: string): boolean { +export function isConfigPathTruthy(config: OpenClawConfig | undefined, pathStr: string): boolean { const value = resolveConfigPath(config, pathStr); if (value === undefined && pathStr in DEFAULT_CONFIG_VALUES) { return DEFAULT_CONFIG_VALUES[pathStr] === true; @@ -37,7 +37,7 @@ export function isConfigPathTruthy(config: MoltbotConfig | undefined, pathStr: s } export function resolveHookConfig( - config: MoltbotConfig | undefined, + config: OpenClawConfig | undefined, hookKey: string, ): HookConfig | undefined { const hooks = config?.hooks?.internal?.entries; @@ -68,13 +68,13 @@ export function hasBinary(bin: string): boolean { export function shouldIncludeHook(params: { entry: HookEntry; - config?: MoltbotConfig; + config?: OpenClawConfig; eligibility?: HookEligibilityContext; }): boolean { const { entry, config, eligibility } = params; const hookKey = resolveHookKey(entry.hook.name, entry); const hookConfig = resolveHookConfig(config, hookKey); - const pluginManaged = entry.hook.source === "moltbot-plugin"; + const pluginManaged = entry.hook.source === "openclaw-plugin"; const osList = entry.metadata?.os ?? []; const remotePlatforms = eligibility?.remote?.platforms ?? []; diff --git a/src/hooks/frontmatter.test.ts b/src/hooks/frontmatter.test.ts index d1eef95746..d7660f0190 100644 --- a/src/hooks/frontmatter.test.ts +++ b/src/hooks/frontmatter.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; import { parseFrontmatter, - resolveMoltbotMetadata, + resolveOpenClawMetadata, resolveHookInvocationPolicy, } from "./frontmatter.js"; @@ -41,7 +41,7 @@ name: session-memory description: "Save session context" metadata: { - "moltbot": { + "openclaw": { "emoji": "💾", "events": ["command:new"] } @@ -58,8 +58,8 @@ metadata: // Verify the metadata is valid JSON const parsed = JSON.parse(result.metadata as string); - expect(parsed.moltbot.emoji).toBe("💾"); - expect(parsed.moltbot.events).toEqual(["command:new"]); + expect(parsed.openclaw.emoji).toBe("💾"); + expect(parsed.openclaw.events).toEqual(["command:new"]); }); it("parses multi-line metadata with complex nested structure", () => { @@ -68,7 +68,7 @@ name: command-logger description: "Log all command events" metadata: { - "moltbot": + "openclaw": { "emoji": "📝", "events": ["command"], @@ -83,21 +83,21 @@ metadata: expect(result.metadata).toBeDefined(); const parsed = JSON.parse(result.metadata as string); - expect(parsed.moltbot.emoji).toBe("📝"); - expect(parsed.moltbot.events).toEqual(["command"]); - expect(parsed.moltbot.requires.config).toEqual(["workspace.dir"]); - expect(parsed.moltbot.install[0].kind).toBe("bundled"); + expect(parsed.openclaw.emoji).toBe("📝"); + expect(parsed.openclaw.events).toEqual(["command"]); + expect(parsed.openclaw.requires.config).toEqual(["workspace.dir"]); + expect(parsed.openclaw.install[0].kind).toBe("bundled"); }); it("handles single-line metadata (inline JSON)", () => { const content = `--- name: simple-hook -metadata: {"moltbot": {"events": ["test"]}} +metadata: {"openclaw": {"events": ["test"]}} --- `; const result = parseFrontmatter(content); expect(result.name).toBe("simple-hook"); - expect(result.metadata).toBe('{"moltbot": {"events": ["test"]}}'); + expect(result.metadata).toBe('{"openclaw": {"events": ["test"]}}'); }); it("handles mixed single-line and multi-line values", () => { @@ -107,7 +107,7 @@ description: "A hook with mixed values" homepage: https://example.com metadata: { - "moltbot": { + "openclaw": { "events": ["command:new"] } } @@ -148,12 +148,12 @@ description: 'single-quoted' }); }); -describe("resolveMoltbotMetadata", () => { - it("extracts moltbot metadata from parsed frontmatter", () => { +describe("resolveOpenClawMetadata", () => { + it("extracts openclaw metadata from parsed frontmatter", () => { const frontmatter = { name: "test-hook", metadata: JSON.stringify({ - moltbot: { + openclaw: { emoji: "🔥", events: ["command:new", "command:reset"], requires: { @@ -164,7 +164,7 @@ describe("resolveMoltbotMetadata", () => { }), }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result).toBeDefined(); expect(result?.emoji).toBe("🔥"); expect(result?.events).toEqual(["command:new", "command:reset"]); @@ -174,15 +174,15 @@ describe("resolveMoltbotMetadata", () => { it("returns undefined when metadata is missing", () => { const frontmatter = { name: "no-metadata" }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result).toBeUndefined(); }); - it("returns undefined when moltbot key is missing", () => { + it("returns undefined when openclaw key is missing", () => { const frontmatter = { metadata: JSON.stringify({ other: "data" }), }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result).toBeUndefined(); }); @@ -190,41 +190,41 @@ describe("resolveMoltbotMetadata", () => { const frontmatter = { metadata: "not valid json {", }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result).toBeUndefined(); }); it("handles install specs", () => { const frontmatter = { metadata: JSON.stringify({ - moltbot: { + openclaw: { events: ["command"], install: [ - { id: "bundled", kind: "bundled", label: "Bundled with Moltbot" }, - { id: "npm", kind: "npm", package: "@moltbot/hook" }, + { id: "bundled", kind: "bundled", label: "Bundled with OpenClaw" }, + { id: "npm", kind: "npm", package: "@openclaw/hook" }, ], }, }), }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result?.install).toHaveLength(2); expect(result?.install?.[0].kind).toBe("bundled"); expect(result?.install?.[1].kind).toBe("npm"); - expect(result?.install?.[1].package).toBe("@moltbot/hook"); + expect(result?.install?.[1].package).toBe("@openclaw/hook"); }); it("handles os restrictions", () => { const frontmatter = { metadata: JSON.stringify({ - moltbot: { + openclaw: { events: ["command"], os: ["darwin", "linux"], }, }), }; - const result = resolveMoltbotMetadata(frontmatter); + const result = resolveOpenClawMetadata(frontmatter); expect(result?.os).toEqual(["darwin", "linux"]); }); @@ -233,15 +233,15 @@ describe("resolveMoltbotMetadata", () => { const content = `--- name: session-memory description: "Save session context to memory when /new command is issued" -homepage: https://docs.molt.bot/hooks#session-memory +homepage: https://docs.openclaw.ai/hooks#session-memory metadata: { - "moltbot": + "openclaw": { "emoji": "💾", "events": ["command:new"], "requires": { "config": ["workspace.dir"] }, - "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with Moltbot" }], + "install": [{ "id": "bundled", "kind": "bundled", "label": "Bundled with OpenClaw" }], }, } --- @@ -253,28 +253,28 @@ metadata: expect(frontmatter.name).toBe("session-memory"); expect(frontmatter.metadata).toBeDefined(); - const moltbot = resolveMoltbotMetadata(frontmatter); - expect(moltbot).toBeDefined(); - expect(moltbot?.emoji).toBe("💾"); - expect(moltbot?.events).toEqual(["command:new"]); - expect(moltbot?.requires?.config).toEqual(["workspace.dir"]); - expect(moltbot?.install?.[0].kind).toBe("bundled"); + const openclaw = resolveOpenClawMetadata(frontmatter); + expect(openclaw).toBeDefined(); + expect(openclaw?.emoji).toBe("💾"); + expect(openclaw?.events).toEqual(["command:new"]); + expect(openclaw?.requires?.config).toEqual(["workspace.dir"]); + expect(openclaw?.install?.[0].kind).toBe("bundled"); }); it("parses YAML metadata map", () => { const content = `--- name: yaml-metadata metadata: - moltbot: + openclaw: emoji: disk events: - command:new --- `; const frontmatter = parseFrontmatter(content); - const moltbot = resolveMoltbotMetadata(frontmatter); - expect(moltbot?.emoji).toBe("disk"); - expect(moltbot?.events).toEqual(["command:new"]); + const openclaw = resolveOpenClawMetadata(frontmatter); + expect(openclaw?.emoji).toBe("disk"); + expect(openclaw?.events).toEqual(["command:new"]); }); }); diff --git a/src/hooks/frontmatter.ts b/src/hooks/frontmatter.ts index dc433f9ba5..9bad12508c 100644 --- a/src/hooks/frontmatter.ts +++ b/src/hooks/frontmatter.ts @@ -1,10 +1,10 @@ import JSON5 from "json5"; -import { LEGACY_MANIFEST_KEY } from "../compat/legacy-names.js"; +import { LEGACY_MANIFEST_KEYS, MANIFEST_KEY } from "../compat/legacy-names.js"; import { parseFrontmatterBlock } from "../markdown/frontmatter.js"; import { parseBooleanValue } from "../utils/boolean.js"; import type { - MoltbotHookMetadata, + OpenClawHookMetadata, HookEntry, HookInstallSpec, HookInvocationPolicy, @@ -63,17 +63,23 @@ function parseFrontmatterBool(value: string | undefined, fallback: boolean): boo return parsed === undefined ? fallback : parsed; } -export function resolveMoltbotMetadata( +export function resolveOpenClawMetadata( frontmatter: ParsedHookFrontmatter, -): MoltbotHookMetadata | undefined { +): OpenClawHookMetadata | undefined { const raw = getFrontmatterValue(frontmatter, "metadata"); if (!raw) return undefined; try { - const parsed = JSON5.parse(raw) as { moltbot?: unknown } & Partial< - Record - >; + const parsed = JSON5.parse(raw) as Record; if (!parsed || typeof parsed !== "object") return undefined; - const metadataRaw = parsed.moltbot ?? parsed[LEGACY_MANIFEST_KEY]; + const metadataRawCandidates = [MANIFEST_KEY, ...LEGACY_MANIFEST_KEYS]; + let metadataRaw: unknown; + for (const key of metadataRawCandidates) { + const candidate = parsed[key]; + if (candidate && typeof candidate === "object") { + metadataRaw = candidate; + break; + } + } if (!metadataRaw || typeof metadataRaw !== "object") return undefined; const metadataObj = metadataRaw as Record; const requiresRaw = diff --git a/src/hooks/gmail-ops.ts b/src/hooks/gmail-ops.ts index 6811275249..505e26d5f8 100644 --- a/src/hooks/gmail-ops.ts +++ b/src/hooks/gmail-ops.ts @@ -1,7 +1,7 @@ import { spawn } from "node:child_process"; import { - type MoltbotConfig, + type OpenClawConfig, CONFIG_PATH, loadConfig, readConfigFileSnapshot, @@ -210,7 +210,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { true, ); - const nextConfig: MoltbotConfig = { + const nextConfig: OpenClawConfig = { ...baseConfig, hooks: { ...baseConfig.hooks, @@ -278,7 +278,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { defaultRuntime.log(`- push endpoint: ${pushEndpoint}`); defaultRuntime.log(`- hook url: ${hookUrl}`); defaultRuntime.log(`- config: ${displayPath(CONFIG_PATH)}`); - defaultRuntime.log(`Next: ${formatCliCommand("moltbot webhooks gmail run")}`); + defaultRuntime.log(`Next: ${formatCliCommand("openclaw webhooks gmail run")}`); } export async function runGmailService(opts: GmailRunOptions) { diff --git a/src/hooks/gmail-setup-utils.test.ts b/src/hooks/gmail-setup-utils.test.ts index 3e87afa6da..2038261475 100644 --- a/src/hooks/gmail-setup-utils.test.ts +++ b/src/hooks/gmail-setup-utils.test.ts @@ -14,7 +14,7 @@ describe("resolvePythonExecutablePath", () => { itUnix( "resolves a working python path and caches the result", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-python-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-python-")); const originalPath = process.env.PATH; try { const realPython = path.join(tmp, "python-real"); diff --git a/src/hooks/gmail-watcher.ts b/src/hooks/gmail-watcher.ts index bf1b08b355..256608d5b4 100644 --- a/src/hooks/gmail-watcher.ts +++ b/src/hooks/gmail-watcher.ts @@ -7,7 +7,7 @@ import { type ChildProcess, spawn } from "node:child_process"; import { hasBinary } from "../agents/skills.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { runCommandWithTimeout } from "../process/exec.js"; import { @@ -96,7 +96,7 @@ function spawnGogServe(cfg: GmailHookRuntimeConfig): ChildProcess { if (addressInUse) { log.warn( "gog serve failed to bind (address already in use); stopping restarts. " + - "Another watcher is likely running. Set CLAWDBOT_SKIP_GMAIL_WATCHER=1 or stop the other process.", + "Another watcher is likely running. Set OPENCLAW_SKIP_GMAIL_WATCHER=1 or stop the other process.", ); watcherProcess = null; return; @@ -121,7 +121,7 @@ export type GmailWatcherStartResult = { * Start the Gmail watcher service. * Called automatically by the gateway if hooks.gmail is configured. */ -export async function startGmailWatcher(cfg: MoltbotConfig): Promise { +export async function startGmailWatcher(cfg: OpenClawConfig): Promise { // Check if gmail hooks are configured if (!cfg.hooks?.enabled) { return { started: false, reason: "hooks not enabled" }; diff --git a/src/hooks/gmail.test.ts b/src/hooks/gmail.test.ts index d14ef74479..514e89c077 100644 --- a/src/hooks/gmail.test.ts +++ b/src/hooks/gmail.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { type MoltbotConfig, DEFAULT_GATEWAY_PORT } from "../config/config.js"; +import { type OpenClawConfig, DEFAULT_GATEWAY_PORT } from "../config/config.js"; import { buildDefaultHookUrl, buildTopicPath, @@ -11,12 +11,12 @@ const baseConfig = { hooks: { token: "hook-token", gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", }, }, -} satisfies MoltbotConfig; +} satisfies OpenClawConfig; describe("gmail hook config", () => { it("builds default hook url", () => { @@ -37,7 +37,7 @@ describe("gmail hook config", () => { const result = resolveGmailHookRuntimeConfig(baseConfig, {}); expect(result.ok).toBe(true); if (result.ok) { - expect(result.value.account).toBe("moltbot@gmail.com"); + expect(result.value.account).toBe("openclaw@gmail.com"); expect(result.value.label).toBe("INBOX"); expect(result.value.includeBody).toBe(true); expect(result.value.serve.port).toBe(8788); @@ -50,7 +50,7 @@ describe("gmail hook config", () => { { hooks: { gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", }, @@ -67,7 +67,7 @@ describe("gmail hook config", () => { hooks: { token: "hook-token", gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", tailscale: { mode: "funnel" }, @@ -89,7 +89,7 @@ describe("gmail hook config", () => { hooks: { token: "hook-token", gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", serve: { path: "/gmail-pubsub" }, @@ -112,7 +112,7 @@ describe("gmail hook config", () => { hooks: { token: "hook-token", gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", serve: { path: "/custom" }, @@ -135,7 +135,7 @@ describe("gmail hook config", () => { hooks: { token: "hook-token", gmail: { - account: "moltbot@gmail.com", + account: "openclaw@gmail.com", topic: "projects/demo/topics/gog-gmail-watch", pushToken: "push-token", serve: { path: "/custom" }, diff --git a/src/hooks/gmail.ts b/src/hooks/gmail.ts index 1eff9e13d0..36b0b2045e 100644 --- a/src/hooks/gmail.ts +++ b/src/hooks/gmail.ts @@ -1,7 +1,7 @@ import { randomBytes } from "node:crypto"; import { - type MoltbotConfig, + type OpenClawConfig, DEFAULT_GATEWAY_PORT, type HooksGmailTailscaleMode, resolveGatewayPort, @@ -95,7 +95,7 @@ export function buildDefaultHookUrl( } export function resolveGmailHookRuntimeConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, overrides: GmailHookOverrides, ): { ok: true; value: GmailHookRuntimeConfig } | { ok: false; error: string } { const hooks = cfg.hooks; diff --git a/src/hooks/hooks-install.e2e.test.ts b/src/hooks/hooks-install.e2e.test.ts index 165f786cb7..0ea6d8aca2 100644 --- a/src/hooks/hooks-install.e2e.test.ts +++ b/src/hooks/hooks-install.e2e.test.ts @@ -6,7 +6,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const tempDirs: string[] = []; async function makeTempDir() { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hooks-e2e-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hooks-e2e-")); tempDirs.push(dir); return dir; } @@ -21,24 +21,24 @@ describe("hooks install (e2e)", () => { workspaceDir = path.join(baseDir, "workspace"); await fs.mkdir(workspaceDir, { recursive: true }); - prevStateDir = process.env.CLAWDBOT_STATE_DIR; - prevBundledDir = process.env.CLAWDBOT_BUNDLED_HOOKS_DIR; - process.env.CLAWDBOT_STATE_DIR = path.join(baseDir, "state"); - process.env.CLAWDBOT_BUNDLED_HOOKS_DIR = path.join(baseDir, "bundled-none"); + prevStateDir = process.env.OPENCLAW_STATE_DIR; + prevBundledDir = process.env.OPENCLAW_BUNDLED_HOOKS_DIR; + process.env.OPENCLAW_STATE_DIR = path.join(baseDir, "state"); + process.env.OPENCLAW_BUNDLED_HOOKS_DIR = path.join(baseDir, "bundled-none"); vi.resetModules(); }); afterEach(async () => { if (prevStateDir === undefined) { - delete process.env.CLAWDBOT_STATE_DIR; + delete process.env.OPENCLAW_STATE_DIR; } else { - process.env.CLAWDBOT_STATE_DIR = prevStateDir; + process.env.OPENCLAW_STATE_DIR = prevStateDir; } if (prevBundledDir === undefined) { - delete process.env.CLAWDBOT_BUNDLED_HOOKS_DIR; + delete process.env.OPENCLAW_BUNDLED_HOOKS_DIR; } else { - process.env.CLAWDBOT_BUNDLED_HOOKS_DIR = prevBundledDir; + process.env.OPENCLAW_BUNDLED_HOOKS_DIR = prevBundledDir; } vi.resetModules(); @@ -63,7 +63,7 @@ describe("hooks install (e2e)", () => { { name: "@acme/hello-hooks", version: "0.0.0", - moltbot: { hooks: ["./hooks/hello-hook"] }, + openclaw: { hooks: ["./hooks/hello-hook"] }, }, null, 2, @@ -77,7 +77,7 @@ describe("hooks install (e2e)", () => { "---", 'name: "hello-hook"', 'description: "Test hook"', - 'metadata: {"moltbot":{"events":["command:new"]}}', + 'metadata: {"openclaw":{"events":["command:new"]}}', "---", "", "# Hello Hook", diff --git a/src/hooks/hooks-status.ts b/src/hooks/hooks-status.ts index 0a5aded7c0..a4bc0bb3bd 100644 --- a/src/hooks/hooks-status.ts +++ b/src/hooks/hooks-status.ts @@ -1,6 +1,6 @@ import path from "node:path"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { CONFIG_DIR } from "../utils.js"; import { hasBinary, isConfigPathTruthy, resolveConfigPath, resolveHookConfig } from "./config.js"; import type { HookEligibilityContext, HookEntry, HookInstallSpec } from "./types.js"; @@ -75,7 +75,7 @@ function normalizeInstallOptions(entry: HookEntry): HookInstallOption[] { if (!label) { if (spec.kind === "bundled") { - label = "Bundled with Moltbot"; + label = "Bundled with OpenClaw"; } else if (spec.kind === "npm" && spec.package) { label = `Install ${spec.package} (npm)`; } else if (spec.kind === "git" && spec.repository) { @@ -91,12 +91,12 @@ function normalizeInstallOptions(entry: HookEntry): HookInstallOption[] { function buildHookStatus( entry: HookEntry, - config?: MoltbotConfig, + config?: OpenClawConfig, eligibility?: HookEligibilityContext, ): HookStatusEntry { const hookKey = resolveHookKey(entry); const hookConfig = resolveHookConfig(config, hookKey); - const managedByPlugin = entry.hook.source === "moltbot-plugin"; + const managedByPlugin = entry.hook.source === "openclaw-plugin"; const disabled = managedByPlugin ? false : hookConfig?.enabled === false; const always = entry.metadata?.always === true; const emoji = entry.metadata?.emoji ?? entry.frontmatter.emoji; @@ -202,7 +202,7 @@ function buildHookStatus( export function buildWorkspaceHookStatus( workspaceDir: string, opts?: { - config?: MoltbotConfig; + config?: OpenClawConfig; managedHooksDir?: string; entries?: HookEntry[]; eligibility?: HookEligibilityContext; diff --git a/src/hooks/install.test.ts b/src/hooks/install.test.ts index e9deb8e869..4ac05e9238 100644 --- a/src/hooks/install.test.ts +++ b/src/hooks/install.test.ts @@ -9,7 +9,7 @@ import { afterEach, describe, expect, it } from "vitest"; const tempDirs: string[] = []; function makeTempDir() { - const dir = path.join(os.tmpdir(), `moltbot-hook-install-${randomUUID()}`); + const dir = path.join(os.tmpdir(), `openclaw-hook-install-${randomUUID()}`); fs.mkdirSync(dir, { recursive: true }); tempDirs.push(dir); return dir; @@ -35,9 +35,9 @@ describe("installHooksFromArchive", () => { zip.file( "package/package.json", JSON.stringify({ - name: "@moltbot/zip-hooks", + name: "@openclaw/zip-hooks", version: "0.0.1", - moltbot: { hooks: ["./hooks/zip-hook"] }, + openclaw: { hooks: ["./hooks/zip-hook"] }, }), ); zip.file( @@ -46,7 +46,7 @@ describe("installHooksFromArchive", () => { "---", "name: zip-hook", "description: Zip hook", - 'metadata: {"moltbot":{"events":["command:new"]}}', + 'metadata: {"openclaw":{"events":["command:new"]}}', "---", "", "# Zip Hook", @@ -78,9 +78,9 @@ describe("installHooksFromArchive", () => { fs.writeFileSync( path.join(pkgDir, "package.json"), JSON.stringify({ - name: "@moltbot/tar-hooks", + name: "@openclaw/tar-hooks", version: "0.0.1", - moltbot: { hooks: ["./hooks/tar-hook"] }, + openclaw: { hooks: ["./hooks/tar-hook"] }, }), "utf-8", ); @@ -90,7 +90,7 @@ describe("installHooksFromArchive", () => { "---", "name: tar-hook", "description: Tar hook", - 'metadata: {"moltbot":{"events":["command:new"]}}', + 'metadata: {"openclaw":{"events":["command:new"]}}', "---", "", "# Tar Hook", @@ -128,7 +128,7 @@ describe("installHooksFromPath", () => { "---", "name: my-hook", "description: My hook", - 'metadata: {"moltbot":{"events":["command:new"]}}', + 'metadata: {"openclaw":{"events":["command:new"]}}', "---", "", "# My Hook", diff --git a/src/hooks/install.ts b/src/hooks/install.ts index 14ae54fa06..32a6dac0b4 100644 --- a/src/hooks/install.ts +++ b/src/hooks/install.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { LEGACY_MANIFEST_KEY } from "../compat/legacy-names.js"; +import { MANIFEST_KEY } from "../compat/legacy-names.js"; import { runCommandWithTimeout } from "../process/exec.js"; import { CONFIG_DIR, resolveUserPath } from "../utils.js"; import { @@ -23,9 +23,7 @@ type HookPackageManifest = { name?: string; version?: string; dependencies?: Record; - moltbot?: { hooks?: string[] }; - [LEGACY_MANIFEST_KEY]?: { hooks?: string[] }; -}; +} & Partial>; export type InstallHooksResult = | { @@ -56,14 +54,14 @@ export function resolveHookInstallDir(hookId: string, hooksDir?: string): string return path.join(hooksBase, safeDirName(hookId)); } -async function ensureMoltbotHooks(manifest: HookPackageManifest) { - const hooks = manifest.moltbot?.hooks ?? manifest[LEGACY_MANIFEST_KEY]?.hooks; +async function ensureOpenClawHooks(manifest: HookPackageManifest) { + const hooks = manifest[MANIFEST_KEY]?.hooks; if (!Array.isArray(hooks)) { - throw new Error("package.json missing moltbot.hooks"); + throw new Error("package.json missing openclaw.hooks"); } const list = hooks.map((e) => (typeof e === "string" ? e.trim() : "")).filter(Boolean); if (list.length === 0) { - throw new Error("package.json moltbot.hooks is empty"); + throw new Error("package.json openclaw.hooks is empty"); } return list; } @@ -122,7 +120,7 @@ async function installHookPackageFromDir(params: { let hookEntries: string[]; try { - hookEntries = await ensureMoltbotHooks(manifest); + hookEntries = await ensureOpenClawHooks(manifest); } catch (err) { return { ok: false, error: String(err) }; } @@ -295,7 +293,7 @@ export async function installHooksFromArchive(params: { return { ok: false, error: `unsupported archive: ${archivePath}` }; } - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hook-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hook-")); const extractDir = path.join(tmpDir, "extract"); await fs.mkdir(extractDir, { recursive: true }); @@ -353,7 +351,7 @@ export async function installHooksFromNpmSpec(params: { const spec = params.spec.trim(); if (!spec) return { ok: false, error: "missing npm spec" }; - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hook-pack-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hook-pack-")); logger.info?.(`Downloading ${spec}…`); const res = await runCommandWithTimeout(["npm", "pack", spec], { timeoutMs: Math.max(timeoutMs, 300_000), diff --git a/src/hooks/installs.ts b/src/hooks/installs.ts index c0c35ff861..f493ec29e5 100644 --- a/src/hooks/installs.ts +++ b/src/hooks/installs.ts @@ -1,9 +1,9 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { HookInstallRecord } from "../config/types.hooks.js"; export type HookInstallUpdate = HookInstallRecord & { hookId: string }; -export function recordHookInstall(cfg: MoltbotConfig, update: HookInstallUpdate): MoltbotConfig { +export function recordHookInstall(cfg: OpenClawConfig, update: HookInstallUpdate): OpenClawConfig { const { hookId, ...record } = update; const installs = { ...cfg.hooks?.internal?.installs, diff --git a/src/hooks/internal-hooks.ts b/src/hooks/internal-hooks.ts index 1b866d4440..136bd2fd3e 100644 --- a/src/hooks/internal-hooks.ts +++ b/src/hooks/internal-hooks.ts @@ -1,19 +1,19 @@ /** - * Hook system for moltbot agent events + * Hook system for OpenClaw agent events * * Provides an extensible event-driven hook system for agent events * like command processing, session lifecycle, etc. */ import type { WorkspaceBootstrapFile } from "../agents/workspace.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; export type InternalHookEventType = "command" | "session" | "agent" | "gateway"; export type AgentBootstrapHookContext = { workspaceDir: string; bootstrapFiles: WorkspaceBootstrapFile[]; - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; sessionKey?: string; sessionId?: string; agentId?: string; diff --git a/src/hooks/llm-slug-generator.ts b/src/hooks/llm-slug-generator.ts index 7baf7aca63..c52627176e 100644 --- a/src/hooks/llm-slug-generator.ts +++ b/src/hooks/llm-slug-generator.ts @@ -6,7 +6,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { runEmbeddedPiAgent } from "../agents/pi-embedded.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveDefaultAgentId, resolveAgentWorkspaceDir, @@ -18,7 +18,7 @@ import { */ export async function generateSlugViaLLM(params: { sessionContent: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; }): Promise { let tempSessionFile: string | null = null; @@ -28,7 +28,7 @@ export async function generateSlugViaLLM(params: { const agentDir = resolveAgentDir(params.cfg, agentId); // Create a temporary session file for this one-off LLM call - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-slug-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-slug-")); tempSessionFile = path.join(tempDir, "session.jsonl"); const prompt = `Based on this conversation, generate a short 1-2 word filename slug (lowercase, hyphen-separated, no file extension). diff --git a/src/hooks/loader.test.ts b/src/hooks/loader.test.ts index a812c2dc23..634bf6f367 100644 --- a/src/hooks/loader.test.ts +++ b/src/hooks/loader.test.ts @@ -9,7 +9,7 @@ import { triggerInternalHook, createInternalHookEvent, } from "./internal-hooks.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; describe("loader", () => { let tmpDir: string; @@ -18,21 +18,21 @@ describe("loader", () => { beforeEach(async () => { clearInternalHooks(); // Create a temp directory for test modules - tmpDir = path.join(os.tmpdir(), `moltbot-test-${Date.now()}`); + tmpDir = path.join(os.tmpdir(), `openclaw-test-${Date.now()}`); await fs.mkdir(tmpDir, { recursive: true }); // Disable bundled hooks during tests by setting env var to non-existent directory - originalBundledDir = process.env.CLAWDBOT_BUNDLED_HOOKS_DIR; - process.env.CLAWDBOT_BUNDLED_HOOKS_DIR = "/nonexistent/bundled/hooks"; + originalBundledDir = process.env.OPENCLAW_BUNDLED_HOOKS_DIR; + process.env.OPENCLAW_BUNDLED_HOOKS_DIR = "/nonexistent/bundled/hooks"; }); afterEach(async () => { clearInternalHooks(); // Restore original env var if (originalBundledDir === undefined) { - delete process.env.CLAWDBOT_BUNDLED_HOOKS_DIR; + delete process.env.OPENCLAW_BUNDLED_HOOKS_DIR; } else { - process.env.CLAWDBOT_BUNDLED_HOOKS_DIR = originalBundledDir; + process.env.OPENCLAW_BUNDLED_HOOKS_DIR = originalBundledDir; } // Clean up temp directory try { @@ -44,7 +44,7 @@ describe("loader", () => { describe("loadInternalHooks", () => { it("should return 0 when hooks are not enabled", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: false, @@ -57,7 +57,7 @@ describe("loader", () => { }); it("should return 0 when hooks config is missing", async () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const count = await loadInternalHooks(cfg, tmpDir); expect(count).toBe(0); }); @@ -72,7 +72,7 @@ describe("loader", () => { `; await fs.writeFile(handlerPath, handlerCode, "utf-8"); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -101,7 +101,7 @@ describe("loader", () => { await fs.writeFile(handler1Path, "export default async function() {}", "utf-8"); await fs.writeFile(handler2Path, "export default async function() {}", "utf-8"); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -131,7 +131,7 @@ describe("loader", () => { `; await fs.writeFile(handlerPath, handlerCode, "utf-8"); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -153,7 +153,7 @@ describe("loader", () => { it("should handle module loading errors gracefully", async () => { const consoleError = vi.spyOn(console, "error").mockImplementation(() => {}); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -184,7 +184,7 @@ describe("loader", () => { const handlerPath = path.join(tmpDir, "bad-export.js"); await fs.writeFile(handlerPath, 'export default "not a function";', "utf-8"); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -213,7 +213,7 @@ describe("loader", () => { // Get relative path from cwd const relativePath = path.relative(process.cwd(), handlerPath); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, @@ -245,7 +245,7 @@ describe("loader", () => { `; await fs.writeFile(handlerPath, handlerCode, "utf-8"); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { internal: { enabled: true, diff --git a/src/hooks/loader.ts b/src/hooks/loader.ts index d246045a9e..9f0899a97a 100644 --- a/src/hooks/loader.ts +++ b/src/hooks/loader.ts @@ -8,7 +8,7 @@ import { pathToFileURL } from "node:url"; import path from "node:path"; import { registerInternalHook } from "./internal-hooks.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { InternalHookHandler } from "./internal-hooks.js"; import { loadWorkspaceHookEntries } from "./workspace.js"; import { resolveHookConfig } from "./config.js"; @@ -21,7 +21,7 @@ import { shouldIncludeHook } from "./config.js"; * 1. Directory-based discovery (bundled, managed, workspace) * 2. Legacy config handlers (backwards compatibility) * - * @param cfg - Moltbot configuration + * @param cfg - OpenClaw configuration * @param workspaceDir - Workspace directory for hook discovery * @returns Number of handlers successfully loaded * @@ -33,7 +33,10 @@ import { shouldIncludeHook } from "./config.js"; * console.log(`Loaded ${count} hook handlers`); * ``` */ -export async function loadInternalHooks(cfg: MoltbotConfig, workspaceDir: string): Promise { +export async function loadInternalHooks( + cfg: OpenClawConfig, + workspaceDir: string, +): Promise { // Check if hooks are enabled if (!cfg.hooks?.internal?.enabled) { return 0; diff --git a/src/hooks/plugin-hooks.ts b/src/hooks/plugin-hooks.ts index f65dadbfd1..2136c55e69 100644 --- a/src/hooks/plugin-hooks.ts +++ b/src/hooks/plugin-hooks.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; -import type { MoltbotPluginApi } from "../plugins/types.js"; +import type { OpenClawPluginApi } from "../plugins/types.js"; import type { HookEntry } from "./types.js"; import { shouldIncludeHook } from "./config.js"; import { loadHookEntriesFromDir } from "./workspace.js"; @@ -14,17 +14,17 @@ export type PluginHookLoadResult = { errors: string[]; }; -function resolveHookDir(api: MoltbotPluginApi, dir: string): string { +function resolveHookDir(api: OpenClawPluginApi, dir: string): string { if (path.isAbsolute(dir)) return dir; return path.resolve(path.dirname(api.source), dir); } -function normalizePluginHookEntry(api: MoltbotPluginApi, entry: HookEntry): HookEntry { +function normalizePluginHookEntry(api: OpenClawPluginApi, entry: HookEntry): HookEntry { return { ...entry, hook: { ...entry.hook, - source: "moltbot-plugin", + source: "openclaw-plugin", pluginId: api.id, }, metadata: { @@ -37,7 +37,7 @@ function normalizePluginHookEntry(api: MoltbotPluginApi, entry: HookEntry): Hook async function loadHookHandler( entry: HookEntry, - api: MoltbotPluginApi, + api: OpenClawPluginApi, ): Promise { try { const url = pathToFileURL(entry.hook.handlerPath).href; @@ -57,13 +57,13 @@ async function loadHookHandler( } export async function registerPluginHooksFromDir( - api: MoltbotPluginApi, + api: OpenClawPluginApi, dir: string, ): Promise { const resolvedDir = resolveHookDir(api, dir); const hooks = loadHookEntriesFromDir({ dir: resolvedDir, - source: "moltbot-plugin", + source: "openclaw-plugin", pluginId: api.id, }); diff --git a/src/hooks/soul-evil.test.ts b/src/hooks/soul-evil.test.ts index 6db0e8c4da..db13f24035 100644 --- a/src/hooks/soul-evil.test.ts +++ b/src/hooks/soul-evil.test.ts @@ -116,7 +116,7 @@ describe("decideSoulEvil", () => { describe("applySoulEvilOverride", () => { it("replaces SOUL content when evil is active and file exists", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_SOUL_EVIL_FILENAME, @@ -140,7 +140,7 @@ describe("applySoulEvilOverride", () => { }); it("leaves SOUL content when evil file is missing", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); const files = makeFiles({ path: path.join(tempDir, DEFAULT_SOUL_FILENAME), }); @@ -158,7 +158,7 @@ describe("applySoulEvilOverride", () => { }); it("uses custom evil filename when configured", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); await writeWorkspaceFile({ dir: tempDir, name: "SOUL_EVIL_CUSTOM.md", @@ -182,7 +182,7 @@ describe("applySoulEvilOverride", () => { }); it("warns and skips when evil file is empty", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_SOUL_EVIL_FILENAME, @@ -209,7 +209,7 @@ describe("applySoulEvilOverride", () => { }); it("leaves files untouched when SOUL.md is not in bootstrap files", async () => { - const tempDir = await makeTempWorkspace("moltbot-soul-"); + const tempDir = await makeTempWorkspace("openclaw-soul-"); await writeWorkspaceFile({ dir: tempDir, name: DEFAULT_SOUL_EVIL_FILENAME, diff --git a/src/hooks/types.ts b/src/hooks/types.ts index 3818dfd920..6675a43263 100644 --- a/src/hooks/types.ts +++ b/src/hooks/types.ts @@ -7,7 +7,7 @@ export type HookInstallSpec = { bins?: string[]; }; -export type MoltbotHookMetadata = { +export type OpenClawHookMetadata = { always?: boolean; hookKey?: string; emoji?: string; @@ -35,7 +35,7 @@ export type ParsedHookFrontmatter = Record; export type Hook = { name: string; description: string; - source: "moltbot-bundled" | "moltbot-managed" | "moltbot-workspace" | "moltbot-plugin"; + source: "openclaw-bundled" | "openclaw-managed" | "openclaw-workspace" | "openclaw-plugin"; pluginId?: string; filePath: string; // Path to HOOK.md baseDir: string; // Directory containing hook @@ -47,7 +47,7 @@ export type HookSource = Hook["source"]; export type HookEntry = { hook: Hook; frontmatter: ParsedHookFrontmatter; - metadata?: MoltbotHookMetadata; + metadata?: OpenClawHookMetadata; invocation?: HookInvocationPolicy; }; diff --git a/src/hooks/workspace.ts b/src/hooks/workspace.ts index 7f371ac100..23caf53b38 100644 --- a/src/hooks/workspace.ts +++ b/src/hooks/workspace.ts @@ -1,14 +1,14 @@ import fs from "node:fs"; import path from "node:path"; -import { LEGACY_MANIFEST_KEY } from "../compat/legacy-names.js"; -import type { MoltbotConfig } from "../config/config.js"; +import { MANIFEST_KEY } from "../compat/legacy-names.js"; +import type { OpenClawConfig } from "../config/config.js"; import { CONFIG_DIR, resolveUserPath } from "../utils.js"; import { resolveBundledHooksDir } from "./bundled-dir.js"; import { shouldIncludeHook } from "./config.js"; import { parseFrontmatter, - resolveMoltbotMetadata, + resolveOpenClawMetadata, resolveHookInvocationPolicy, } from "./frontmatter.js"; import type { @@ -22,13 +22,11 @@ import type { type HookPackageManifest = { name?: string; - moltbot?: { hooks?: string[] }; - [LEGACY_MANIFEST_KEY]?: { hooks?: string[] }; -}; +} & Partial>; function filterHookEntries( entries: HookEntry[], - config?: MoltbotConfig, + config?: OpenClawConfig, eligibility?: HookEligibilityContext, ): HookEntry[] { return entries.filter((entry) => shouldIncludeHook({ entry, config, eligibility })); @@ -46,7 +44,7 @@ function readHookPackageManifest(dir: string): HookPackageManifest | null { } function resolvePackageHooks(manifest: HookPackageManifest): string[] { - const raw = manifest.moltbot?.hooks ?? manifest[LEGACY_MANIFEST_KEY]?.hooks; + const raw = manifest[MANIFEST_KEY]?.hooks; if (!Array.isArray(raw)) return []; return raw.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean); } @@ -169,7 +167,7 @@ export function loadHookEntriesFromDir(params: { pluginId: params.pluginId, }, frontmatter, - metadata: resolveMoltbotMetadata(frontmatter), + metadata: resolveOpenClawMetadata(frontmatter), invocation: resolveHookInvocationPolicy(frontmatter), }; return entry; @@ -179,7 +177,7 @@ export function loadHookEntriesFromDir(params: { function loadHookEntries( workspaceDir: string, opts?: { - config?: MoltbotConfig; + config?: OpenClawConfig; managedHooksDir?: string; bundledHooksDir?: string; }, @@ -195,23 +193,23 @@ function loadHookEntries( const bundledHooks = bundledHooksDir ? loadHooksFromDir({ dir: bundledHooksDir, - source: "moltbot-bundled", + source: "openclaw-bundled", }) : []; const extraHooks = extraDirs.flatMap((dir) => { const resolved = resolveUserPath(dir); return loadHooksFromDir({ dir: resolved, - source: "moltbot-workspace", // Extra dirs treated as workspace + source: "openclaw-workspace", // Extra dirs treated as workspace }); }); const managedHooks = loadHooksFromDir({ dir: managedHooksDir, - source: "moltbot-managed", + source: "openclaw-managed", }); const workspaceHooks = loadHooksFromDir({ dir: workspaceHooksDir, - source: "moltbot-workspace", + source: "openclaw-workspace", }); const merged = new Map(); @@ -232,7 +230,7 @@ function loadHookEntries( return { hook, frontmatter, - metadata: resolveMoltbotMetadata(frontmatter), + metadata: resolveOpenClawMetadata(frontmatter), invocation: resolveHookInvocationPolicy(frontmatter), }; }); @@ -241,7 +239,7 @@ function loadHookEntries( export function buildWorkspaceHookSnapshot( workspaceDir: string, opts?: { - config?: MoltbotConfig; + config?: OpenClawConfig; managedHooksDir?: string; bundledHooksDir?: string; entries?: HookEntry[]; @@ -265,7 +263,7 @@ export function buildWorkspaceHookSnapshot( export function loadWorkspaceHookEntries( workspaceDir: string, opts?: { - config?: MoltbotConfig; + config?: OpenClawConfig; managedHooksDir?: string; bundledHooksDir?: string; }, diff --git a/src/imessage/accounts.ts b/src/imessage/accounts.ts index 25e825d830..61feb9d3eb 100644 --- a/src/imessage/accounts.ts +++ b/src/imessage/accounts.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { IMessageAccountConfig } from "../config/types.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; @@ -10,26 +10,26 @@ export type ResolvedIMessageAccount = { configured: boolean; }; -function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { +function listConfiguredAccountIds(cfg: OpenClawConfig): string[] { const accounts = cfg.channels?.imessage?.accounts; if (!accounts || typeof accounts !== "object") return []; return Object.keys(accounts).filter(Boolean); } -export function listIMessageAccountIds(cfg: MoltbotConfig): string[] { +export function listIMessageAccountIds(cfg: OpenClawConfig): string[] { const ids = listConfiguredAccountIds(cfg); if (ids.length === 0) return [DEFAULT_ACCOUNT_ID]; return ids.sort((a, b) => a.localeCompare(b)); } -export function resolveDefaultIMessageAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultIMessageAccountId(cfg: OpenClawConfig): string { const ids = listIMessageAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID; return ids[0] ?? DEFAULT_ACCOUNT_ID; } function resolveAccountConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId: string, ): IMessageAccountConfig | undefined { const accounts = cfg.channels?.imessage?.accounts; @@ -37,7 +37,7 @@ function resolveAccountConfig( return accounts[accountId] as IMessageAccountConfig | undefined; } -function mergeIMessageAccountConfig(cfg: MoltbotConfig, accountId: string): IMessageAccountConfig { +function mergeIMessageAccountConfig(cfg: OpenClawConfig, accountId: string): IMessageAccountConfig { const { accounts: _ignored, ...base } = (cfg.channels?.imessage ?? {}) as IMessageAccountConfig & { accounts?: unknown }; const account = resolveAccountConfig(cfg, accountId) ?? {}; @@ -45,7 +45,7 @@ function mergeIMessageAccountConfig(cfg: MoltbotConfig, accountId: string): IMes } export function resolveIMessageAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): ResolvedIMessageAccount { const accountId = normalizeAccountId(params.accountId); @@ -75,7 +75,7 @@ export function resolveIMessageAccount(params: { }; } -export function listEnabledIMessageAccounts(cfg: MoltbotConfig): ResolvedIMessageAccount[] { +export function listEnabledIMessageAccounts(cfg: OpenClawConfig): ResolvedIMessageAccount[] { return listIMessageAccountIds(cfg) .map((accountId) => resolveIMessageAccount({ cfg, accountId })) .filter((account) => account.enabled); diff --git a/src/imessage/monitor.skips-group-messages-without-mention-by-default.test.ts b/src/imessage/monitor.skips-group-messages-without-mention-by-default.test.ts index 7f0fdd3683..f066bb58f8 100644 --- a/src/imessage/monitor.skips-group-messages-without-mention-by-default.test.ts +++ b/src/imessage/monitor.skips-group-messages-without-mention-by-default.test.ts @@ -36,7 +36,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), readSessionUpdatedAt: vi.fn(() => undefined), recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined), @@ -80,7 +80,7 @@ beforeEach(() => { }, session: { mainKey: "main" }, messages: { - groupChat: { mentionPatterns: ["@clawd"] }, + groupChat: { mentionPatterns: ["@openclaw"] }, }, }; requestMock.mockReset().mockImplementation((method: string) => { @@ -219,7 +219,7 @@ describe("monitorIMessageProvider", () => { chat_id: 123, sender: "+15550001111", is_from_me: false, - text: "@clawd hello", + text: "@openclaw hello", is_group: true, }, }, @@ -364,7 +364,7 @@ describe("monitorIMessageProvider", () => { chat_id: 42, sender: "+15550002222", is_from_me: false, - text: "@clawd ping", + text: "@openclaw ping", is_group: true, chat_name: "Lobster Squad", participants: ["+1555", "+1556"], @@ -413,7 +413,7 @@ describe("monitorIMessageProvider", () => { chat_id: 202, sender: "+15550003333", is_from_me: false, - text: "@clawd hi", + text: "@openclaw hi", is_group: true, }, }, @@ -448,7 +448,7 @@ describe("monitorIMessageProvider", () => { chat_id: 303, sender: "+15550003333", is_from_me: false, - text: "@clawd hi", + text: "@openclaw hi", is_group: true, }, }, @@ -474,7 +474,7 @@ describe("monitorIMessageProvider", () => { chat_name: "Test Group", sender: "+15550001111", is_from_me: false, - text: "@clawd hi", + text: "@openclaw hi", is_group: true, created_at: "2026-01-17T00:00:00Z", }, @@ -489,7 +489,7 @@ describe("monitorIMessageProvider", () => { const ctx = replyMock.mock.calls[0]?.[0]; const body = ctx?.Body ?? ""; expect(body).toContain("Test Group id:99"); - expect(body).toContain("+15550001111: @clawd hi"); + expect(body).toContain("+15550001111: @openclaw hi"); }); it("includes reply context when imessage reply metadata is present", async () => { diff --git a/src/imessage/monitor.updates-last-route-chat-id-direct-messages.test.ts b/src/imessage/monitor.updates-last-route-chat-id-direct-messages.test.ts index 78744fedaf..6aef30f8da 100644 --- a/src/imessage/monitor.updates-last-route-chat-id-direct-messages.test.ts +++ b/src/imessage/monitor.updates-last-route-chat-id-direct-messages.test.ts @@ -36,7 +36,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), readSessionUpdatedAt: vi.fn(() => undefined), recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined), @@ -80,7 +80,7 @@ beforeEach(() => { }, session: { mainKey: "main" }, messages: { - groupChat: { mentionPatterns: ["@clawd"] }, + groupChat: { mentionPatterns: ["@openclaw"] }, }, }; requestMock.mockReset().mockImplementation((method: string) => { diff --git a/src/imessage/monitor/monitor-provider.ts b/src/imessage/monitor/monitor-provider.ts index d8d4b99ec8..4910716993 100644 --- a/src/imessage/monitor/monitor-provider.ts +++ b/src/imessage/monitor/monitor-provider.ts @@ -58,7 +58,7 @@ import type { IMessagePayload, MonitorIMessageOpts } from "./types.js"; /** * Try to detect remote host from an SSH wrapper script like: - * exec ssh -T moltbot@192.168.64.3 /opt/homebrew/bin/imsg "$@" + * exec ssh -T openclaw@192.168.64.3 /opt/homebrew/bin/imsg "$@" * exec ssh -T mac-mini imsg "$@" * Returns the user@host or host portion if found, undefined otherwise. */ @@ -70,7 +70,7 @@ async function detectRemoteHostFromCliPath(cliPath: string): Promise; groupAllowFrom?: Array; includeAttachments?: boolean; diff --git a/src/index.ts b/src/index.ts index 6a02a828d2..8c2ffc7b9b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ import { ensureBinary } from "./infra/binaries.js"; import { loadDotEnv } from "./infra/dotenv.js"; import { normalizeEnv } from "./infra/env.js"; import { isMainModule } from "./infra/is-main.js"; -import { ensureMoltbotCliOnPath } from "./infra/path-env.js"; +import { ensureOpenClawCliOnPath } from "./infra/path-env.js"; import { describePortOwner, ensurePortAvailable, @@ -36,7 +36,7 @@ import { assertWebChannel, normalizeE164, toWhatsappJid } from "./utils.js"; loadDotEnv({ quiet: true }); normalizeEnv(); -ensureMoltbotCliOnPath(); +ensureOpenClawCliOnPath(); // Capture all console output into structured logs while keeping stdout/stderr behavior. enableConsoleCapture(); @@ -83,12 +83,12 @@ if (isMain) { installUnhandledRejectionHandler(); process.on("uncaughtException", (error) => { - console.error("[moltbot] Uncaught exception:", formatUncaughtError(error)); + console.error("[openclaw] Uncaught exception:", formatUncaughtError(error)); process.exit(1); }); void program.parseAsync(process.argv).catch((err) => { - console.error("[moltbot] CLI failed:", formatUncaughtError(err)); + console.error("[openclaw] CLI failed:", formatUncaughtError(err)); process.exit(1); }); } diff --git a/src/infra/archive.test.ts b/src/infra/archive.test.ts index ccf998894d..81f986a132 100644 --- a/src/infra/archive.test.ts +++ b/src/infra/archive.test.ts @@ -9,7 +9,7 @@ import { extractArchive, resolveArchiveKind, resolvePackedRootDir } from "./arch const tempDirs: string[] = []; async function makeTempDir() { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-archive-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-archive-")); tempDirs.push(dir); return dir; } diff --git a/src/infra/bonjour-discovery.test.ts b/src/infra/bonjour-discovery.test.ts index 6720b2800f..7d0df4c4fd 100644 --- a/src/infra/bonjour-discovery.test.ts +++ b/src/infra/bonjour-discovery.test.ts @@ -2,7 +2,8 @@ import { describe, expect, it, vi } from "vitest"; import type { runCommandWithTimeout } from "../process/exec.js"; import { discoverGatewayBeacons } from "./bonjour-discovery.js"; -import { WIDE_AREA_DISCOVERY_DOMAIN } from "./widearea-dns.js"; + +const WIDE_AREA_DOMAIN = "openclaw.internal."; describe("bonjour-discovery", () => { it("discovers beacons on darwin across local + wide-area domains", async () => { @@ -17,8 +18,8 @@ describe("bonjour-discovery", () => { if (domain === "local.") { return { stdout: [ - "Add 2 3 local. _moltbot-gw._tcp. Peter\\226\\128\\153s Mac Studio Gateway", - "Add 2 3 local. _moltbot-gw._tcp. Laptop Gateway", + "Add 2 3 local. _openclaw-gw._tcp. Peter\\226\\128\\153s Mac Studio Gateway", + "Add 2 3 local. _openclaw-gw._tcp. Laptop Gateway", "", ].join("\n"), stderr: "", @@ -27,12 +28,11 @@ describe("bonjour-discovery", () => { killed: false, }; } - if (domain === WIDE_AREA_DISCOVERY_DOMAIN) { + if (domain === WIDE_AREA_DOMAIN) { return { - stdout: [ - `Add 2 3 ${WIDE_AREA_DISCOVERY_DOMAIN} _moltbot-gw._tcp. Tailnet Gateway`, - "", - ].join("\n"), + stdout: [`Add 2 3 ${WIDE_AREA_DOMAIN} _openclaw-gw._tcp. Tailnet Gateway`, ""].join( + "\n", + ), stderr: "", code: 0, signal: null, @@ -65,7 +65,7 @@ describe("bonjour-discovery", () => { return { stdout: [ - `${instance}._moltbot-gw._tcp. can be reached at ${host}:18789`, + `${instance}._openclaw-gw._tcp. can be reached at ${host}:18789`, txtParts.join(" "), "", ].join("\n"), @@ -82,6 +82,7 @@ describe("bonjour-discovery", () => { const beacons = await discoverGatewayBeacons({ platform: "darwin", timeoutMs: 1234, + wideAreaDomain: WIDE_AREA_DOMAIN, run: run as unknown as typeof runCommandWithTimeout, }); @@ -95,12 +96,12 @@ describe("bonjour-discovery", () => { ]), ); expect(beacons.map((b) => b.domain)).toEqual( - expect.arrayContaining(["local.", WIDE_AREA_DISCOVERY_DOMAIN]), + expect.arrayContaining(["local.", WIDE_AREA_DOMAIN]), ); const browseCalls = calls.filter((c) => c.argv[0] === "dns-sd" && c.argv[1] === "-B"); expect(browseCalls.map((c) => c.argv[3])).toEqual( - expect.arrayContaining(["local.", WIDE_AREA_DISCOVERY_DOMAIN]), + expect.arrayContaining(["local.", WIDE_AREA_DOMAIN]), ); expect(browseCalls.every((c) => c.timeoutMs === 1234)).toBe(true); }); @@ -112,7 +113,7 @@ describe("bonjour-discovery", () => { const domain = argv[3] ?? ""; if (argv[0] === "dns-sd" && argv[1] === "-B" && domain === "local.") { return { - stdout: ["Add 2 3 local. _moltbot-gw._tcp. Studio Gateway", ""].join("\n"), + stdout: ["Add 2 3 local. _openclaw-gw._tcp. Studio Gateway", ""].join("\n"), stderr: "", code: 0, signal: null, @@ -123,7 +124,7 @@ describe("bonjour-discovery", () => { if (argv[0] === "dns-sd" && argv[1] === "-L") { return { stdout: [ - "Studio Gateway._moltbot-gw._tcp. can be reached at studio.local:18789", + "Studio Gateway._openclaw-gw._tcp. can be reached at studio.local:18789", "txtvers=1 displayName=Peter\\226\\128\\153s\\032Mac\\032Studio lanHost=studio.local gatewayPort=18789 sshPort=22", "", ].join("\n"), @@ -164,8 +165,8 @@ describe("bonjour-discovery", () => { it("falls back to tailnet DNS probing for wide-area when split DNS is not configured", async () => { const calls: Array<{ argv: string[]; timeoutMs: number }> = []; - const zone = WIDE_AREA_DISCOVERY_DOMAIN.replace(/\.$/, ""); - const serviceBase = `_moltbot-gw._tcp.${zone}`; + const zone = WIDE_AREA_DOMAIN.replace(/\.$/, ""); + const serviceBase = `_openclaw-gw._tcp.${zone}`; const studioService = `studio-gateway.${serviceBase}`; const run = vi.fn(async (argv: string[], options: { timeoutMs: number }) => { @@ -231,7 +232,7 @@ describe("bonjour-discovery", () => { `"transport=gateway"`, `"sshPort=22"`, `"tailnetDns=peters-mac-studio-1.sheep-coho.ts.net"`, - `"cliPath=/opt/homebrew/bin/moltbot"`, + `"cliPath=/opt/homebrew/bin/openclaw"`, "", ].join(" "), stderr: "", @@ -248,13 +249,14 @@ describe("bonjour-discovery", () => { const beacons = await discoverGatewayBeacons({ platform: "darwin", timeoutMs: 1200, - domains: [WIDE_AREA_DISCOVERY_DOMAIN], + domains: [WIDE_AREA_DOMAIN], + wideAreaDomain: WIDE_AREA_DOMAIN, run: run as unknown as typeof runCommandWithTimeout, }); expect(beacons).toEqual([ expect.objectContaining({ - domain: WIDE_AREA_DISCOVERY_DOMAIN, + domain: WIDE_AREA_DOMAIN, instanceName: "studio-gateway", displayName: "Studio", host: `studio.${zone}`, @@ -262,7 +264,7 @@ describe("bonjour-discovery", () => { tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net", gatewayPort: 18789, sshPort: 22, - cliPath: "/opt/homebrew/bin/moltbot", + cliPath: "/opt/homebrew/bin/openclaw", }), ]); @@ -286,12 +288,12 @@ describe("bonjour-discovery", () => { await discoverGatewayBeacons({ platform: "darwin", timeoutMs: 1, - domains: ["local", "moltbot.internal"], + domains: ["local", "openclaw.internal"], run: run as unknown as typeof runCommandWithTimeout, }); expect(calls.filter((c) => c[1] === "-B").map((c) => c[3])).toEqual( - expect.arrayContaining(["local.", "moltbot.internal."]), + expect.arrayContaining(["local.", "openclaw.internal."]), ); calls.length = 0; diff --git a/src/infra/bonjour-discovery.ts b/src/infra/bonjour-discovery.ts index e7777484f9..8f3a59d7b8 100644 --- a/src/infra/bonjour-discovery.ts +++ b/src/infra/bonjour-discovery.ts @@ -1,5 +1,5 @@ import { runCommandWithTimeout } from "../process/exec.js"; -import { WIDE_AREA_DISCOVERY_DOMAIN } from "./widearea-dns.js"; +import { resolveWideAreaDiscoveryDomain } from "./widearea-dns.js"; export type GatewayBonjourBeacon = { instanceName: string; @@ -22,13 +22,13 @@ export type GatewayBonjourBeacon = { export type GatewayBonjourDiscoverOpts = { timeoutMs?: number; domains?: string[]; + wideAreaDomain?: string | null; platform?: NodeJS.Platform; run?: typeof runCommandWithTimeout; }; const DEFAULT_TIMEOUT_MS = 2000; - -const DEFAULT_DOMAINS = ["local.", WIDE_AREA_DISCOVERY_DOMAIN] as const; +const GATEWAY_SERVICE_TYPE = "_openclaw-gw._tcp"; function decodeDnsSdEscapes(value: string): string { let decoded = false; @@ -166,9 +166,9 @@ function parseDnsSdBrowse(stdout: string): string[] { const instances = new Set(); for (const raw of stdout.split("\n")) { const line = raw.trim(); - if (!line || !line.includes("_moltbot-gw._tcp")) continue; + if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) continue; if (!line.includes("Add")) continue; - const match = line.match(/_moltbot-gw\._tcp\.?\s+(.+)$/); + const match = line.match(/_openclaw-gw\._tcp\.?\s+(.+)$/); if (match?.[1]) { instances.add(decodeDnsSdEscapes(match[1].trim())); } @@ -225,13 +225,13 @@ async function discoverViaDnsSd( timeoutMs: number, run: typeof runCommandWithTimeout, ): Promise { - const browse = await run(["dns-sd", "-B", "_moltbot-gw._tcp", domain], { + const browse = await run(["dns-sd", "-B", GATEWAY_SERVICE_TYPE, domain], { timeoutMs, }); const instances = parseDnsSdBrowse(browse.stdout); const results: GatewayBonjourBeacon[] = []; for (const instance of instances) { - const resolved = await run(["dns-sd", "-L", instance, "_moltbot-gw._tcp", domain], { + const resolved = await run(["dns-sd", "-L", instance, GATEWAY_SERVICE_TYPE, domain], { timeoutMs, }); const parsed = parseDnsSdResolve(resolved.stdout, instance); @@ -245,7 +245,7 @@ async function discoverWideAreaViaTailnetDns( timeoutMs: number, run: typeof runCommandWithTimeout, ): Promise { - if (domain !== WIDE_AREA_DISCOVERY_DOMAIN) return []; + if (!domain || domain === "local.") return []; const startedAt = Date.now(); const remainingMs = () => timeoutMs - (Date.now() - startedAt); @@ -268,7 +268,7 @@ async function discoverWideAreaViaTailnetDns( // Keep scans bounded: this is a fallback and should not block long. ips = ips.slice(0, 40); - const probeName = `_moltbot-gw._tcp.${domain.replace(/\.$/, "")}`; + const probeName = `${GATEWAY_SERVICE_TYPE}.${domain.replace(/\.$/, "")}`; const concurrency = 6; let nextIndex = 0; @@ -312,7 +312,7 @@ async function discoverWideAreaViaTailnetDns( if (budget <= 0) break; const ptrName = ptr.trim().replace(/\.$/, ""); if (!ptrName) continue; - const instanceName = ptrName.replace(/\.?_moltbot-gw\._tcp\..*$/, ""); + const instanceName = ptrName.replace(/\.?_openclaw-gw\._tcp\..*$/, ""); const srv = await run(["dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV"], { timeoutMs: Math.max(1, Math.min(350, budget)), @@ -371,9 +371,9 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] { for (const raw of stdout.split("\n")) { const line = raw.trimEnd(); if (!line) continue; - if (line.startsWith("=") && line.includes("_moltbot-gw._tcp")) { + if (line.startsWith("=") && line.includes(GATEWAY_SERVICE_TYPE)) { if (current) results.push(current); - const marker = " _moltbot-gw._tcp"; + const marker = ` ${GATEWAY_SERVICE_TYPE}`; const idx = line.indexOf(marker); const left = idx >= 0 ? line.slice(0, idx).trim() : line; const parts = left.split(/\s+/); @@ -429,7 +429,7 @@ async function discoverViaAvahi( timeoutMs: number, run: typeof runCommandWithTimeout, ): Promise { - const args = ["avahi-browse", "-rt", "_moltbot-gw._tcp"]; + const args = ["avahi-browse", "-rt", GATEWAY_SERVICE_TYPE]; if (domain && domain !== "local.") { // avahi-browse wants a plain domain (no trailing dot) args.push("-d", domain.replace(/\.$/, "")); @@ -447,8 +447,10 @@ export async function discoverGatewayBeacons( const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS; const platform = opts.platform ?? process.platform; const run = opts.run ?? runCommandWithTimeout; + const wideAreaDomain = resolveWideAreaDiscoveryDomain({ configDomain: opts.wideAreaDomain }); const domainsRaw = Array.isArray(opts.domains) ? opts.domains : []; - const domains = (domainsRaw.length > 0 ? domainsRaw : [...DEFAULT_DOMAINS]) + const defaultDomains = ["local.", ...(wideAreaDomain ? [wideAreaDomain] : [])]; + const domains = (domainsRaw.length > 0 ? domainsRaw : defaultDomains) .map((d) => String(d).trim()) .filter(Boolean) .map((d) => (d.endsWith(".") ? d : `${d}.`)); @@ -460,15 +462,15 @@ export async function discoverGatewayBeacons( ); const discovered = perDomain.flatMap((r) => (r.status === "fulfilled" ? r.value : [])); - const wantsWideArea = domains.includes(WIDE_AREA_DISCOVERY_DOMAIN); - const hasWideArea = discovered.some((b) => b.domain === WIDE_AREA_DISCOVERY_DOMAIN); + const wantsWideArea = wideAreaDomain ? domains.includes(wideAreaDomain) : false; + const hasWideArea = wideAreaDomain + ? discovered.some((b) => b.domain === wideAreaDomain) + : false; - if (wantsWideArea && !hasWideArea) { - const fallback = await discoverWideAreaViaTailnetDns( - WIDE_AREA_DISCOVERY_DOMAIN, - timeoutMs, - run, - ).catch(() => []); + if (wantsWideArea && !hasWideArea && wideAreaDomain) { + const fallback = await discoverWideAreaViaTailnetDns(wideAreaDomain, timeoutMs, run).catch( + () => [], + ); return [...discovered, ...fallback]; } diff --git a/src/infra/bonjour.test.ts b/src/infra/bonjour.test.ts index ef93f7ffbc..5f53e7a961 100644 --- a/src/infra/bonjour.test.ts +++ b/src/infra/bonjour.test.ts @@ -86,6 +86,8 @@ describe("gateway bonjour advertiser", () => { process.env.NODE_ENV = "development"; vi.spyOn(os, "hostname").mockReturnValue("test-host"); + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; const destroy = vi.fn().mockResolvedValue(undefined); const advertise = vi.fn().mockImplementation( @@ -111,12 +113,12 @@ describe("gateway bonjour advertiser", () => { gatewayPort: 18789, sshPort: 2222, tailnetDns: "host.tailnet.ts.net", - cliPath: "/opt/homebrew/bin/moltbot", + cliPath: "/opt/homebrew/bin/openclaw", }); expect(createService).toHaveBeenCalledTimes(1); const [gatewayCall] = createService.mock.calls as Array<[Record]>; - expect(gatewayCall?.[0]?.type).toBe("moltbot-gw"); + expect(gatewayCall?.[0]?.type).toBe("openclaw-gw"); const gatewayType = asString(gatewayCall?.[0]?.type, ""); expect(gatewayType.length).toBeLessThanOrEqual(15); expect(gatewayCall?.[0]?.port).toBe(18789); @@ -126,7 +128,7 @@ describe("gateway bonjour advertiser", () => { expect((gatewayCall?.[0]?.txt as Record)?.gatewayPort).toBe("18789"); expect((gatewayCall?.[0]?.txt as Record)?.sshPort).toBe("2222"); expect((gatewayCall?.[0]?.txt as Record)?.cliPath).toBe( - "/opt/homebrew/bin/moltbot", + "/opt/homebrew/bin/openclaw", ); expect((gatewayCall?.[0]?.txt as Record)?.transport).toBe("gateway"); @@ -163,7 +165,7 @@ describe("gateway bonjour advertiser", () => { const started = await startGatewayBonjourAdvertiser({ gatewayPort: 18789, sshPort: 2222, - cliPath: "/opt/homebrew/bin/moltbot", + cliPath: "/opt/homebrew/bin/openclaw", minimal: true, }); @@ -180,6 +182,7 @@ describe("gateway bonjour advertiser", () => { process.env.NODE_ENV = "development"; vi.spyOn(os, "hostname").mockReturnValue("test-host"); + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; const destroy = vi.fn().mockResolvedValue(undefined); const advertise = vi.fn().mockResolvedValue(undefined); @@ -217,6 +220,7 @@ describe("gateway bonjour advertiser", () => { process.env.NODE_ENV = "development"; vi.spyOn(os, "hostname").mockReturnValue("test-host"); + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; const destroy = vi.fn().mockResolvedValue(undefined); const advertise = vi.fn().mockResolvedValue(undefined); @@ -261,6 +265,7 @@ describe("gateway bonjour advertiser", () => { vi.useFakeTimers(); vi.spyOn(os, "hostname").mockReturnValue("test-host"); + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; const destroy = vi.fn().mockResolvedValue(undefined); const advertise = vi @@ -308,6 +313,7 @@ describe("gateway bonjour advertiser", () => { process.env.NODE_ENV = "development"; vi.spyOn(os, "hostname").mockReturnValue("test-host"); + process.env.OPENCLAW_MDNS_HOSTNAME = "test-host"; const destroy = vi.fn().mockResolvedValue(undefined); const advertise = vi.fn(() => { @@ -364,10 +370,10 @@ describe("gateway bonjour advertiser", () => { }); const [gatewayCall] = createService.mock.calls as Array<[ServiceCall]>; - expect(gatewayCall?.[0]?.name).toBe("Mac (Moltbot)"); + expect(gatewayCall?.[0]?.name).toBe("openclaw (OpenClaw)"); expect(gatewayCall?.[0]?.domain).toBe("local"); - expect(gatewayCall?.[0]?.hostname).toBe("Mac"); - expect((gatewayCall?.[0]?.txt as Record)?.lanHost).toBe("Mac.local"); + expect(gatewayCall?.[0]?.hostname).toBe("openclaw"); + expect((gatewayCall?.[0]?.txt as Record)?.lanHost).toBe("openclaw.local"); await started.stop(); }); diff --git a/src/infra/bonjour.ts b/src/infra/bonjour.ts index cc0d50c0e7..8efa4fb829 100644 --- a/src/infra/bonjour.ts +++ b/src/infra/bonjour.ts @@ -1,5 +1,3 @@ -import os from "node:os"; - import { logDebug, logWarn } from "../logger.js"; import { getLogger } from "../logging.js"; import { ignoreCiaoCancellationRejection } from "./bonjour-ciao.js"; @@ -28,7 +26,7 @@ export type GatewayBonjourAdvertiseOpts = { }; function isDisabledByEnv() { - if (isTruthyEnvValue(process.env.CLAWDBOT_DISABLE_BONJOUR)) return true; + if (isTruthyEnvValue(process.env.OPENCLAW_DISABLE_BONJOUR)) return true; if (process.env.NODE_ENV === "test") return true; if (process.env.VITEST) return true; return false; @@ -36,12 +34,12 @@ function isDisabledByEnv() { function safeServiceName(name: string) { const trimmed = name.trim(); - return trimmed.length > 0 ? trimmed : "Moltbot"; + return trimmed.length > 0 ? trimmed : "OpenClaw"; } function prettifyInstanceName(name: string) { const normalized = name.trim().replace(/\s+/g, " "); - return normalized.replace(/\s+\(Moltbot\)\s*$/i, "").trim() || normalized; + return normalized.replace(/\s+\(OpenClaw\)\s*$/i, "").trim() || normalized; } type BonjourService = { @@ -90,16 +88,19 @@ export async function startGatewayBonjourAdvertiser( // mDNS service instance names are single DNS labels; dots in hostnames (like // `Mac.localdomain`) can confuse some resolvers/browsers and break discovery. // Keep only the first label and normalize away a trailing `.local`. + const hostnameRaw = + process.env.OPENCLAW_MDNS_HOSTNAME?.trim() || + process.env.CLAWDBOT_MDNS_HOSTNAME?.trim() || + "openclaw"; const hostname = - os - .hostname() + hostnameRaw .replace(/\.local$/i, "") .split(".")[0] - .trim() || "moltbot"; + .trim() || "openclaw"; const instanceName = typeof opts.instanceName === "string" && opts.instanceName.trim() ? opts.instanceName.trim() - : `${hostname} (Moltbot)`; + : `${hostname} (OpenClaw)`; const displayName = prettifyInstanceName(instanceName); const txtBase: Record = { @@ -140,7 +141,7 @@ export async function startGatewayBonjourAdvertiser( const gateway = responder.createService({ name: safeServiceName(instanceName), - type: "moltbot-gw", + type: "openclaw-gw", protocol: Protocol.TCP, port: opts.gatewayPort, domain: "local", diff --git a/src/infra/brew.test.ts b/src/infra/brew.test.ts index 5b09a2367d..e265d7bf00 100644 --- a/src/infra/brew.test.ts +++ b/src/infra/brew.test.ts @@ -8,7 +8,7 @@ import { resolveBrewExecutable, resolveBrewPathDirs } from "./brew.js"; describe("brew helpers", () => { it("resolves brew from ~/.linuxbrew/bin when executable exists", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-brew-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-brew-")); try { const homebrewBin = path.join(tmp, ".linuxbrew", "bin"); await fs.mkdir(homebrewBin, { recursive: true }); @@ -24,7 +24,7 @@ describe("brew helpers", () => { }); it("prefers HOMEBREW_PREFIX/bin/brew when present", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-brew-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-brew-")); try { const prefix = path.join(tmp, "prefix"); const prefixBin = path.join(prefix, "bin"); diff --git a/src/infra/channel-summary.ts b/src/infra/channel-summary.ts index 830d8b9be4..4e416b1962 100644 --- a/src/infra/channel-summary.ts +++ b/src/infra/channel-summary.ts @@ -1,6 +1,6 @@ import { listChannelPlugins } from "../channels/plugins/index.js"; import type { ChannelAccountSnapshot, ChannelPlugin } from "../channels/plugins/types.js"; -import { type MoltbotConfig, loadConfig } from "../config/config.js"; +import { type OpenClawConfig, loadConfig } from "../config/config.js"; import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js"; import { theme } from "../terminal/theme.js"; @@ -34,7 +34,7 @@ const accountLine = (label: string, details: string[]) => const resolveAccountEnabled = ( plugin: ChannelPlugin, account: unknown, - cfg: MoltbotConfig, + cfg: OpenClawConfig, ): boolean => { if (plugin.config.isEnabled) { return plugin.config.isEnabled(account, cfg); @@ -47,7 +47,7 @@ const resolveAccountEnabled = ( const resolveAccountConfigured = async ( plugin: ChannelPlugin, account: unknown, - cfg: MoltbotConfig, + cfg: OpenClawConfig, ): Promise => { if (plugin.config.isConfigured) { return await plugin.config.isConfigured(account, cfg); @@ -58,7 +58,7 @@ const resolveAccountConfigured = async ( const buildAccountSnapshot = (params: { plugin: ChannelPlugin; account: unknown; - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId: string; enabled: boolean; configured: boolean; @@ -76,7 +76,7 @@ const buildAccountSnapshot = (params: { const formatAllowFrom = (params: { plugin: ChannelPlugin; - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; allowFrom: Array; }) => { @@ -93,7 +93,7 @@ const formatAllowFrom = (params: { const buildAccountDetails = (params: { entry: ChannelAccountEntry; plugin: ChannelPlugin; - cfg: MoltbotConfig; + cfg: OpenClawConfig; includeAllowFrom: boolean; }): string[] => { const details: string[] = []; @@ -129,7 +129,7 @@ const buildAccountDetails = (params: { }; export async function buildChannelSummary( - cfg?: MoltbotConfig, + cfg?: OpenClawConfig, options?: ChannelSummaryOptions, ): Promise { const effective = cfg ?? loadConfig(); diff --git a/src/infra/control-ui-assets.test.ts b/src/infra/control-ui-assets.test.ts index b64c4c6850..2e8bd6448c 100644 --- a/src/infra/control-ui-assets.test.ts +++ b/src/infra/control-ui-assets.test.ts @@ -8,7 +8,7 @@ import { resolveControlUiDistIndexPath, resolveControlUiRepoRoot } from "./contr describe("control UI assets helpers", () => { it("resolves repo root from src argv1", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-ui-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); try { await fs.mkdir(path.join(tmp, "ui"), { recursive: true }); await fs.writeFile(path.join(tmp, "ui", "vite.config.ts"), "export {};\n"); @@ -23,7 +23,7 @@ describe("control UI assets helpers", () => { }); it("resolves repo root from dist argv1", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-ui-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); try { await fs.mkdir(path.join(tmp, "ui"), { recursive: true }); await fs.writeFile(path.join(tmp, "ui", "vite.config.ts"), "export {};\n"); diff --git a/src/infra/device-identity.ts b/src/infra/device-identity.ts index c5381785cf..a5502fb264 100644 --- a/src/infra/device-identity.ts +++ b/src/infra/device-identity.ts @@ -17,7 +17,7 @@ type StoredIdentity = { createdAtMs: number; }; -const DEFAULT_DIR = path.join(os.homedir(), ".clawdbot", "identity"); +const DEFAULT_DIR = path.join(os.homedir(), ".openclaw", "identity"); const DEFAULT_FILE = path.join(DEFAULT_DIR, "device.json"); function ensureDir(filePath: string) { diff --git a/src/infra/device-pairing.test.ts b/src/infra/device-pairing.test.ts index 5461498d9e..c1605debdb 100644 --- a/src/infra/device-pairing.test.ts +++ b/src/infra/device-pairing.test.ts @@ -11,7 +11,7 @@ import { describe("device pairing tokens", () => { test("preserves existing token scopes when rotating without scopes", async () => { - const baseDir = await mkdtemp(join(tmpdir(), "moltbot-device-pairing-")); + const baseDir = await mkdtemp(join(tmpdir(), "openclaw-device-pairing-")); const request = await requestDevicePairing( { deviceId: "device-1", diff --git a/src/infra/diagnostic-events.ts b/src/infra/diagnostic-events.ts index 586177b0b8..b0de66614d 100644 --- a/src/infra/diagnostic-events.ts +++ b/src/infra/diagnostic-events.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; export type DiagnosticSessionState = "idle" | "processing" | "waiting"; @@ -149,7 +149,7 @@ export type DiagnosticEventInput = DiagnosticEventPayload extends infer Event let seq = 0; const listeners = new Set<(evt: DiagnosticEventPayload) => void>(); -export function isDiagnosticsEnabled(config?: MoltbotConfig): boolean { +export function isDiagnosticsEnabled(config?: OpenClawConfig): boolean { return config?.diagnostics?.enabled === true; } diff --git a/src/infra/diagnostic-flags.test.ts b/src/infra/diagnostic-flags.test.ts index bdff0e5672..0d02a8314b 100644 --- a/src/infra/diagnostic-flags.test.ts +++ b/src/infra/diagnostic-flags.test.ts @@ -1,15 +1,15 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { isDiagnosticFlagEnabled, resolveDiagnosticFlags } from "./diagnostic-flags.js"; describe("diagnostic flags", () => { it("merges config + env flags", () => { const cfg = { diagnostics: { flags: ["telegram.http", "cache.*"] }, - } as MoltbotConfig; + } as OpenClawConfig; const env = { - CLAWDBOT_DIAGNOSTICS: "foo,bar", + OPENCLAW_DIAGNOSTICS: "foo,bar", } as NodeJS.ProcessEnv; const flags = resolveDiagnosticFlags(cfg, env); @@ -20,12 +20,12 @@ describe("diagnostic flags", () => { }); it("treats env true as wildcard", () => { - const env = { CLAWDBOT_DIAGNOSTICS: "1" } as NodeJS.ProcessEnv; + const env = { OPENCLAW_DIAGNOSTICS: "1" } as NodeJS.ProcessEnv; expect(isDiagnosticFlagEnabled("anything.here", undefined, env)).toBe(true); }); it("treats env false as disabled", () => { - const env = { CLAWDBOT_DIAGNOSTICS: "0" } as NodeJS.ProcessEnv; + const env = { OPENCLAW_DIAGNOSTICS: "0" } as NodeJS.ProcessEnv; expect(isDiagnosticFlagEnabled("telegram.http", undefined, env)).toBe(false); }); }); diff --git a/src/infra/diagnostic-flags.ts b/src/infra/diagnostic-flags.ts index 8ffd71b76f..eff29c4165 100644 --- a/src/infra/diagnostic-flags.ts +++ b/src/infra/diagnostic-flags.ts @@ -1,6 +1,6 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; -const DIAGNOSTICS_ENV = "CLAWDBOT_DIAGNOSTICS"; +const DIAGNOSTICS_ENV = "OPENCLAW_DIAGNOSTICS"; function normalizeFlag(value: string): string { return value.trim().toLowerCase(); @@ -32,7 +32,7 @@ function uniqueFlags(flags: string[]): string[] { } export function resolveDiagnosticFlags( - cfg?: MoltbotConfig, + cfg?: OpenClawConfig, env: NodeJS.ProcessEnv = process.env, ): string[] { const configFlags = Array.isArray(cfg?.diagnostics?.flags) ? cfg?.diagnostics?.flags : []; @@ -62,7 +62,7 @@ export function matchesDiagnosticFlag(flag: string, enabledFlags: string[]): boo export function isDiagnosticFlagEnabled( flag: string, - cfg?: MoltbotConfig, + cfg?: OpenClawConfig, env: NodeJS.ProcessEnv = process.env, ): boolean { const flags = resolveDiagnosticFlags(cfg, env); diff --git a/src/infra/dotenv.test.ts b/src/infra/dotenv.test.ts index 5aa7538812..58803ed9fd 100644 --- a/src/infra/dotenv.test.ts +++ b/src/infra/dotenv.test.ts @@ -12,15 +12,15 @@ async function writeEnvFile(filePath: string, contents: string) { } describe("loadDotEnv", () => { - it("loads ~/.clawdbot/.env as fallback without overriding CWD .env", async () => { + it("loads ~/.openclaw/.env as fallback without overriding CWD .env", async () => { const prevEnv = { ...process.env }; const prevCwd = process.cwd(); - const base = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-dotenv-test-")); + const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-")); const cwdDir = path.join(base, "cwd"); const stateDir = path.join(base, "state"); - process.env.CLAWDBOT_STATE_DIR = stateDir; + process.env.OPENCLAW_STATE_DIR = stateDir; await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\nBAR=1\n"); await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); @@ -48,11 +48,11 @@ describe("loadDotEnv", () => { const prevEnv = { ...process.env }; const prevCwd = process.cwd(); - const base = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-dotenv-test-")); + const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-")); const cwdDir = path.join(base, "cwd"); const stateDir = path.join(base, "state"); - process.env.CLAWDBOT_STATE_DIR = stateDir; + process.env.OPENCLAW_STATE_DIR = stateDir; process.env.FOO = "from-shell"; await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); diff --git a/src/infra/dotenv.ts b/src/infra/dotenv.ts index 6a0669deca..d031ad1377 100644 --- a/src/infra/dotenv.ts +++ b/src/infra/dotenv.ts @@ -11,7 +11,7 @@ export function loadDotEnv(opts?: { quiet?: boolean }) { // Load from process CWD first (dotenv default). dotenv.config({ quiet }); - // Then load global fallback: ~/.clawdbot/.env (or CLAWDBOT_STATE_DIR/.env), + // Then load global fallback: ~/.openclaw/.env (or OPENCLAW_STATE_DIR/.env), // without overriding any env vars already present. const globalEnvPath = path.join(resolveConfigDir(process.env), ".env"); if (!fs.existsSync(globalEnvPath)) return; diff --git a/src/infra/exec-approval-forwarder.test.ts b/src/infra/exec-approval-forwarder.test.ts index 8e9bba7d8a..71368d3132 100644 --- a/src/infra/exec-approval-forwarder.test.ts +++ b/src/infra/exec-approval-forwarder.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { createExecApprovalForwarder } from "./exec-approval-forwarder.js"; const baseRequest = { @@ -24,7 +24,7 @@ describe("exec approval forwarder", () => { const deliver = vi.fn().mockResolvedValue([]); const cfg = { approvals: { exec: { enabled: true, mode: "session" } }, - } as MoltbotConfig; + } as OpenClawConfig; const forwarder = createExecApprovalForwarder({ getConfig: () => cfg, @@ -59,7 +59,7 @@ describe("exec approval forwarder", () => { targets: [{ channel: "telegram", to: "123" }], }, }, - } as MoltbotConfig; + } as OpenClawConfig; const forwarder = createExecApprovalForwarder({ getConfig: () => cfg, diff --git a/src/infra/exec-approval-forwarder.ts b/src/infra/exec-approval-forwarder.ts index 776fbb1eca..8972b58fa7 100644 --- a/src/infra/exec-approval-forwarder.ts +++ b/src/infra/exec-approval-forwarder.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { loadSessionStore, resolveStorePath } from "../config/sessions.js"; import type { @@ -52,11 +52,11 @@ export type ExecApprovalForwarder = { }; export type ExecApprovalForwarderDeps = { - getConfig?: () => MoltbotConfig; + getConfig?: () => OpenClawConfig; deliver?: typeof deliverOutboundPayloads; nowMs?: () => number; resolveSessionTarget?: (params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; request: ExecApprovalRequest; }) => ExecApprovalForwardTarget | null; }; @@ -136,7 +136,7 @@ function buildExpiredMessage(request: ExecApprovalRequest) { } function defaultResolveSessionTarget(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; request: ExecApprovalRequest; }): ExecApprovalForwardTarget | null { const sessionKey = params.request.request.sessionKey?.trim(); @@ -159,7 +159,7 @@ function defaultResolveSessionTarget(params: { } async function deliverToTargets(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; targets: ForwardTarget[]; text: string; deliver: typeof deliverOutboundPayloads; diff --git a/src/infra/exec-approvals.test.ts b/src/infra/exec-approvals.test.ts index d63be8c755..16a9cfc987 100644 --- a/src/infra/exec-approvals.test.ts +++ b/src/infra/exec-approvals.test.ts @@ -29,7 +29,7 @@ function makePathEnv(binDir: string): NodeJS.ProcessEnv { } function makeTempDir() { - return fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-exec-approvals-")); + return fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-exec-approvals-")); } describe("exec approvals allowlist matching", () => { @@ -381,7 +381,7 @@ describe("exec approvals wildcard agent", () => { const homedirSpy = vi.spyOn(os, "homedir").mockReturnValue(dir); try { - const approvalsPath = path.join(dir, ".clawdbot", "exec-approvals.json"); + const approvalsPath = path.join(dir, ".openclaw", "exec-approvals.json"); fs.mkdirSync(path.dirname(approvalsPath), { recursive: true }); fs.writeFileSync( approvalsPath, diff --git a/src/infra/exec-approvals.ts b/src/infra/exec-approvals.ts index 0830ed89ac..5c5622cb10 100644 --- a/src/infra/exec-approvals.ts +++ b/src/infra/exec-approvals.ts @@ -61,8 +61,8 @@ const DEFAULT_SECURITY: ExecSecurity = "deny"; const DEFAULT_ASK: ExecAsk = "on-miss"; const DEFAULT_ASK_FALLBACK: ExecSecurity = "deny"; const DEFAULT_AUTO_ALLOW_SKILLS = false; -const DEFAULT_SOCKET = "~/.clawdbot/exec-approvals.sock"; -const DEFAULT_FILE = "~/.clawdbot/exec-approvals.json"; +const DEFAULT_SOCKET = "~/.openclaw/exec-approvals.sock"; +const DEFAULT_FILE = "~/.openclaw/exec-approvals.json"; export const DEFAULT_SAFE_BINS = ["jq", "grep", "cut", "sort", "uniq", "head", "tail", "tr", "wc"]; function hashExecApprovalsRaw(raw: string | null): string { diff --git a/src/infra/gateway-lock.test.ts b/src/infra/gateway-lock.test.ts index 54c1db6b9a..f40dd62b16 100644 --- a/src/infra/gateway-lock.test.ts +++ b/src/infra/gateway-lock.test.ts @@ -10,15 +10,15 @@ import { acquireGatewayLock, GatewayLockError } from "./gateway-lock.js"; import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js"; async function makeEnv() { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gateway-lock-")); - const configPath = path.join(dir, "moltbot.json"); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-lock-")); + const configPath = path.join(dir, "openclaw.json"); await fs.writeFile(configPath, "{}", "utf8"); await fs.mkdir(resolveGatewayLockDir(), { recursive: true }); return { env: { ...process.env, - CLAWDBOT_STATE_DIR: dir, - CLAWDBOT_CONFIG_PATH: configPath, + OPENCLAW_STATE_DIR: dir, + OPENCLAW_CONFIG_PATH: configPath, }, cleanup: async () => { await fs.rm(dir, { recursive: true, force: true }); diff --git a/src/infra/gateway-lock.ts b/src/infra/gateway-lock.ts index aa65e7d81e..6d707ff683 100644 --- a/src/infra/gateway-lock.ts +++ b/src/infra/gateway-lock.ts @@ -72,7 +72,7 @@ function isGatewayArgv(args: string[]): boolean { "dist/index.js", "dist/index.mjs", "dist/entry.js", - "moltbot.mjs", + "openclaw.mjs", "dist/entry.mjs", "scripts/run-node.mjs", "src/index.ts", @@ -82,7 +82,7 @@ function isGatewayArgv(args: string[]): boolean { } const exe = normalized[0] ?? ""; - return exe.endsWith("/moltbot") || exe === "moltbot"; + return exe.endsWith("/openclaw") || exe === "openclaw"; } function readLinuxCmdline(pid: number): string[] | null { @@ -162,7 +162,7 @@ export async function acquireGatewayLock( const env = opts.env ?? process.env; const allowInTests = opts.allowInTests === true; if ( - env.CLAWDBOT_ALLOW_MULTI_GATEWAY === "1" || + env.OPENCLAW_ALLOW_MULTI_GATEWAY === "1" || (!allowInTests && (env.VITEST || env.NODE_ENV === "test")) ) { return null; diff --git a/src/infra/heartbeat-runner.respects-ackmaxchars-heartbeat-acks.test.ts b/src/infra/heartbeat-runner.respects-ackmaxchars-heartbeat-acks.test.ts index 18c1ab0631..773cc5342c 100644 --- a/src/infra/heartbeat-runner.respects-ackmaxchars-heartbeat-acks.test.ts +++ b/src/infra/heartbeat-runner.respects-ackmaxchars-heartbeat-acks.test.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import * as replyModule from "../auto-reply/reply.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveMainSessionKey } from "../config/sessions.js"; import { runHeartbeatOnce } from "./heartbeat-runner.js"; import { setActivePluginRegistry } from "../plugins/runtime.js"; @@ -31,11 +31,11 @@ beforeEach(() => { describe("resolveHeartbeatIntervalMs", () => { it("respects ackMaxChars for heartbeat acks", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -93,11 +93,11 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("sends HEARTBEAT_OK when visibility.showOk is true", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -155,11 +155,11 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("skips heartbeat LLM calls when visibility disables all output", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -222,11 +222,11 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("skips delivery for markup-wrapped HEARTBEAT_OK", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -283,13 +283,13 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("does not regress updatedAt when restoring heartbeat sessions", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { const originalUpdatedAt = 1000; const bumpedUpdatedAt = 2000; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -356,11 +356,11 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("skips WhatsApp delivery when not linked or running", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -416,13 +416,13 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("passes through accountId for telegram heartbeats", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = ""; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -484,13 +484,13 @@ describe("resolveHeartbeatIntervalMs", () => { }); it("does not pre-resolve telegram accountId (allows config-only account tokens)", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = ""; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, diff --git a/src/infra/heartbeat-runner.returns-default-unset.test.ts b/src/infra/heartbeat-runner.returns-default-unset.test.ts index cbe92ba93c..5c52332b03 100644 --- a/src/infra/heartbeat-runner.returns-default-unset.test.ts +++ b/src/infra/heartbeat-runner.returns-default-unset.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { HEARTBEAT_PROMPT } from "../auto-reply/heartbeat.js"; import * as replyModule from "../auto-reply/reply.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveAgentIdFromSessionKey, resolveAgentMainSessionKey, @@ -95,7 +95,7 @@ describe("resolveHeartbeatPrompt", () => { }); it("uses a trimmed override when configured", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { prompt: " ping " } } }, }; expect(resolveHeartbeatPrompt(cfg)).toBe("ping"); @@ -104,7 +104,7 @@ describe("resolveHeartbeatPrompt", () => { describe("isHeartbeatEnabledForAgent", () => { it("enables only explicit heartbeat agents when configured", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { every: "30m" } }, list: [{ id: "main" }, { id: "ops", heartbeat: { every: "1h" } }], @@ -115,7 +115,7 @@ describe("isHeartbeatEnabledForAgent", () => { }); it("falls back to default agent when no explicit heartbeat entries", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { every: "30m" } }, list: [{ id: "main" }, { id: "ops" }], @@ -133,7 +133,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }; it("respects target none", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { target: "none" } } }, }; expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({ @@ -146,7 +146,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("uses last route by default", () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const entry = { ...baseEntry, lastChannel: "whatsapp" as const, @@ -162,7 +162,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("normalizes explicit WhatsApp targets when allowFrom is '*'", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { target: "whatsapp", to: "whatsapp:(555) 123" }, @@ -180,7 +180,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("skips when last route is webchat", () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const entry = { ...baseEntry, lastChannel: "webchat" as const, @@ -196,7 +196,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("applies allowFrom fallback for WhatsApp targets", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { target: "whatsapp", to: "+1999" } } }, channels: { whatsapp: { allowFrom: ["+1555", "+1666"] } }, }; @@ -216,7 +216,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("keeps WhatsApp group targets even with allowFrom set", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["+1555"] } }, }; const entry = { @@ -234,7 +234,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("normalizes prefixed WhatsApp group targets for heartbeat delivery", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["+1555"] } }, }; const entry = { @@ -252,7 +252,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("keeps explicit telegram targets", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { target: "telegram", to: "123" } } }, }; expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({ @@ -265,7 +265,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("prefers per-agent heartbeat overrides when provided", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { target: "telegram", to: "123" } } }, }; const heartbeat = { target: "whatsapp", to: "+1555" } as const; @@ -287,7 +287,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { describe("runHeartbeatOnce", () => { it("skips when agent heartbeat is not enabled", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { every: "30m" } }, list: [{ id: "main" }, { id: "ops", heartbeat: { every: "1h" } }], @@ -302,7 +302,7 @@ describe("runHeartbeatOnce", () => { }); it("skips outside active hours", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { userTimezone: "UTC", @@ -326,11 +326,11 @@ describe("runHeartbeatOnce", () => { }); it("uses the last non-empty payload for delivery", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -384,11 +384,11 @@ describe("runHeartbeatOnce", () => { }); it("uses per-agent heartbeat overrides and session keys", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { heartbeat: { every: "30m", prompt: "Default prompt" }, @@ -454,12 +454,12 @@ describe("runHeartbeatOnce", () => { }); it("runs heartbeats in the explicit session key when configured", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { const groupId = "120363401234567890@g.us"; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -537,11 +537,11 @@ describe("runHeartbeatOnce", () => { }); it("suppresses duplicate heartbeat payloads within 24h", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -593,11 +593,11 @@ describe("runHeartbeatOnce", () => { }); it("can include reasoning payloads when enabled", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -665,11 +665,11 @@ describe("runHeartbeatOnce", () => { }); it("delivers reasoning even when the main heartbeat reply is HEARTBEAT_OK", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, @@ -736,11 +736,11 @@ describe("runHeartbeatOnce", () => { }); it("loads the default agent session from templated stores", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storeTemplate = path.join(tmpDir, "agents", "{agentId}", "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, heartbeat: { every: "5m" } }, list: [{ id: "work", default: true }], @@ -800,7 +800,7 @@ describe("runHeartbeatOnce", () => { }); it("skips heartbeat when HEARTBEAT.md is effectively empty (saves API calls)", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const workspaceDir = path.join(tmpDir, "workspace"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); @@ -814,7 +814,7 @@ describe("runHeartbeatOnce", () => { "utf-8", ); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: workspaceDir, @@ -872,7 +872,7 @@ describe("runHeartbeatOnce", () => { }); it("runs heartbeat when HEARTBEAT.md has actionable content", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const workspaceDir = path.join(tmpDir, "workspace"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); @@ -886,7 +886,7 @@ describe("runHeartbeatOnce", () => { "utf-8", ); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: workspaceDir, @@ -942,7 +942,7 @@ describe("runHeartbeatOnce", () => { }); it("runs heartbeat when HEARTBEAT.md does not exist (lets LLM decide)", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const workspaceDir = path.join(tmpDir, "workspace"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); @@ -950,7 +950,7 @@ describe("runHeartbeatOnce", () => { await fs.mkdir(workspaceDir, { recursive: true }); // Don't create HEARTBEAT.md - it doesn't exist - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: workspaceDir, diff --git a/src/infra/heartbeat-runner.scheduler.test.ts b/src/infra/heartbeat-runner.scheduler.test.ts index 3cfd75c81e..e95058880a 100644 --- a/src/infra/heartbeat-runner.scheduler.test.ts +++ b/src/infra/heartbeat-runner.scheduler.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { startHeartbeatRunner } from "./heartbeat-runner.js"; describe("startHeartbeatRunner", () => { @@ -17,7 +17,7 @@ describe("startHeartbeatRunner", () => { const runner = startHeartbeatRunner({ cfg: { agents: { defaults: { heartbeat: { every: "30m" } } }, - } as MoltbotConfig, + } as OpenClawConfig, runOnce: runSpy, }); @@ -36,7 +36,7 @@ describe("startHeartbeatRunner", () => { { id: "ops", heartbeat: { every: "15m" } }, ], }, - } as MoltbotConfig); + } as OpenClawConfig); await vi.advanceTimersByTimeAsync(10 * 60_000 + 1_000); diff --git a/src/infra/heartbeat-runner.sender-prefers-delivery-target.test.ts b/src/infra/heartbeat-runner.sender-prefers-delivery-target.test.ts index 0ff1d7cd04..d55bb712a8 100644 --- a/src/infra/heartbeat-runner.sender-prefers-delivery-target.test.ts +++ b/src/infra/heartbeat-runner.sender-prefers-delivery-target.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import * as replyModule from "../auto-reply/reply.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveMainSessionKey } from "../config/sessions.js"; import { setActivePluginRegistry } from "../plugins/runtime.js"; import { createPluginRuntime } from "../plugins/runtime/index.js"; @@ -36,11 +36,11 @@ beforeEach(() => { describe("runHeartbeatOnce", () => { it("uses the delivery target as sender when lastTo differs", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { workspace: tmpDir, diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 8e0c9a4eee..ac3471adf3 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -22,7 +22,7 @@ import type { ReplyPayload } from "../auto-reply/types.js"; import { getChannelPlugin } from "../channels/plugins/index.js"; import type { ChannelHeartbeatDeps } from "../channels/plugins/types.js"; import { parseDurationMs } from "../cli/parse-duration.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { canonicalizeMainSessionAlias, @@ -97,7 +97,7 @@ const EXEC_EVENT_PROMPT = "Please relay the command output to the user in a helpful way. If the command succeeded, share the relevant output. " + "If it failed, explain what went wrong."; -function resolveActiveHoursTimezone(cfg: MoltbotConfig, raw?: string): string { +function resolveActiveHoursTimezone(cfg: OpenClawConfig, raw?: string): string { const trimmed = raw?.trim(); if (!trimmed || trimmed === "user") { return resolveUserTimezone(cfg.agents?.defaults?.userTimezone); @@ -149,7 +149,7 @@ function resolveMinutesInTimeZone(nowMs: number, timeZone: string): number | nul } function isWithinActiveHours( - cfg: MoltbotConfig, + cfg: OpenClawConfig, heartbeat?: HeartbeatConfig, nowMs?: number, ): boolean { @@ -181,15 +181,15 @@ type HeartbeatAgentState = { export type HeartbeatRunner = { stop: () => void; - updateConfig: (cfg: MoltbotConfig) => void; + updateConfig: (cfg: OpenClawConfig) => void; }; -function hasExplicitHeartbeatAgents(cfg: MoltbotConfig) { +function hasExplicitHeartbeatAgents(cfg: OpenClawConfig) { const list = cfg.agents?.list ?? []; return list.some((entry) => Boolean(entry?.heartbeat)); } -export function isHeartbeatEnabledForAgent(cfg: MoltbotConfig, agentId?: string): boolean { +export function isHeartbeatEnabledForAgent(cfg: OpenClawConfig, agentId?: string): boolean { const resolvedAgentId = normalizeAgentId(agentId ?? resolveDefaultAgentId(cfg)); const list = cfg.agents?.list ?? []; const hasExplicit = hasExplicitHeartbeatAgents(cfg); @@ -201,7 +201,10 @@ export function isHeartbeatEnabledForAgent(cfg: MoltbotConfig, agentId?: string) return resolvedAgentId === resolveDefaultAgentId(cfg); } -function resolveHeartbeatConfig(cfg: MoltbotConfig, agentId?: string): HeartbeatConfig | undefined { +function resolveHeartbeatConfig( + cfg: OpenClawConfig, + agentId?: string, +): HeartbeatConfig | undefined { const defaults = cfg.agents?.defaults?.heartbeat; if (!agentId) return defaults; const overrides = resolveAgentConfig(cfg, agentId)?.heartbeat; @@ -210,7 +213,7 @@ function resolveHeartbeatConfig(cfg: MoltbotConfig, agentId?: string): Heartbeat } export function resolveHeartbeatSummaryForAgent( - cfg: MoltbotConfig, + cfg: OpenClawConfig, agentId?: string, ): HeartbeatSummary { const defaults = cfg.agents?.defaults?.heartbeat; @@ -257,7 +260,7 @@ export function resolveHeartbeatSummaryForAgent( }; } -function resolveHeartbeatAgents(cfg: MoltbotConfig): HeartbeatAgent[] { +function resolveHeartbeatAgents(cfg: OpenClawConfig): HeartbeatAgent[] { const list = cfg.agents?.list ?? []; if (hasExplicitHeartbeatAgents(cfg)) { return list @@ -273,7 +276,7 @@ function resolveHeartbeatAgents(cfg: MoltbotConfig): HeartbeatAgent[] { } export function resolveHeartbeatIntervalMs( - cfg: MoltbotConfig, + cfg: OpenClawConfig, overrideEvery?: string, heartbeat?: HeartbeatConfig, ) { @@ -295,11 +298,11 @@ export function resolveHeartbeatIntervalMs( return ms; } -export function resolveHeartbeatPrompt(cfg: MoltbotConfig, heartbeat?: HeartbeatConfig) { +export function resolveHeartbeatPrompt(cfg: OpenClawConfig, heartbeat?: HeartbeatConfig) { return resolveHeartbeatPromptText(heartbeat?.prompt ?? cfg.agents?.defaults?.heartbeat?.prompt); } -function resolveHeartbeatAckMaxChars(cfg: MoltbotConfig, heartbeat?: HeartbeatConfig) { +function resolveHeartbeatAckMaxChars(cfg: OpenClawConfig, heartbeat?: HeartbeatConfig) { return Math.max( 0, heartbeat?.ackMaxChars ?? @@ -309,7 +312,7 @@ function resolveHeartbeatAckMaxChars(cfg: MoltbotConfig, heartbeat?: HeartbeatCo } function resolveHeartbeatSession( - cfg: MoltbotConfig, + cfg: OpenClawConfig, agentId?: string, heartbeat?: HeartbeatConfig, ) { @@ -428,7 +431,7 @@ function normalizeHeartbeatReply( } export async function runHeartbeatOnce(opts: { - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; agentId?: string; heartbeat?: HeartbeatConfig; reason?: string; @@ -755,7 +758,7 @@ export async function runHeartbeatOnce(opts: { } export function startHeartbeatRunner(opts: { - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; runtime?: RuntimeEnv; abortSignal?: AbortSignal; runOnce?: typeof runHeartbeatOnce; @@ -801,7 +804,7 @@ export function startHeartbeatRunner(opts: { state.timer.unref?.(); }; - const updateConfig = (cfg: MoltbotConfig) => { + const updateConfig = (cfg: OpenClawConfig) => { if (state.stopped) return; const now = Date.now(); const prevAgents = state.agents; diff --git a/src/infra/heartbeat-visibility.test.ts b/src/infra/heartbeat-visibility.test.ts index 33b7952074..1a7ab6df72 100644 --- a/src/infra/heartbeat-visibility.test.ts +++ b/src/infra/heartbeat-visibility.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveHeartbeatVisibility } from "./heartbeat-visibility.js"; describe("resolveHeartbeatVisibility", () => { it("returns default values when no config is provided", () => { - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" }); expect(result).toEqual({ @@ -25,7 +25,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" }); @@ -52,7 +52,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" }); @@ -88,7 +88,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, @@ -120,7 +120,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, @@ -151,7 +151,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" }); @@ -174,7 +174,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, @@ -195,7 +195,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "whatsapp" }); @@ -215,7 +215,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "discord" }); @@ -237,7 +237,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "slack" }); @@ -259,7 +259,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "webchat" }); @@ -271,7 +271,7 @@ describe("resolveHeartbeatVisibility", () => { }); it("webchat returns defaults when no channel defaults configured", () => { - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, channel: "webchat" }); @@ -291,7 +291,7 @@ describe("resolveHeartbeatVisibility", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = resolveHeartbeatVisibility({ cfg, diff --git a/src/infra/heartbeat-visibility.ts b/src/infra/heartbeat-visibility.ts index 808e818b45..d7b7bc12e0 100644 --- a/src/infra/heartbeat-visibility.ts +++ b/src/infra/heartbeat-visibility.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { ChannelHeartbeatVisibilityConfig } from "../config/types.channels.js"; import type { GatewayMessageChannel } from "../utils/message-channel.js"; @@ -20,7 +20,7 @@ const DEFAULT_VISIBILITY: ResolvedHeartbeatVisibility = { * For webchat, uses channels.defaults.heartbeat since webchat doesn't have per-channel config. */ export function resolveHeartbeatVisibility(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: GatewayMessageChannel; accountId?: string; }): ResolvedHeartbeatVisibility { diff --git a/src/infra/is-main.test.ts b/src/infra/is-main.test.ts index 5bb41a3367..5a0eaaab04 100644 --- a/src/infra/is-main.test.ts +++ b/src/infra/is-main.test.ts @@ -28,7 +28,7 @@ describe("isMainModule", () => { it("returns false when running under PM2 but this module is imported", () => { expect( isMainModule({ - currentFile: "/repo/node_modules/moltbot/dist/index.js", + currentFile: "/repo/node_modules/openclaw/dist/index.js", argv: ["node", "/repo/app.js"], cwd: "/repo", env: { pm_exec_path: "/repo/app.js", pm_id: "0" }, diff --git a/src/infra/machine-name.ts b/src/infra/machine-name.ts index 4c9211d5fd..684540f21c 100644 --- a/src/infra/machine-name.ts +++ b/src/infra/machine-name.ts @@ -24,7 +24,7 @@ function fallbackHostName() { os .hostname() .replace(/\.local$/i, "") - .trim() || "moltbot" + .trim() || "openclaw" ); } diff --git a/src/infra/moltbot-root.ts b/src/infra/openclaw-root.ts similarity index 94% rename from src/infra/moltbot-root.ts rename to src/infra/openclaw-root.ts index 950ce46e26..97ee4978c2 100644 --- a/src/infra/moltbot-root.ts +++ b/src/infra/openclaw-root.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; -const CORE_PACKAGE_NAMES = new Set(["moltbot", "moltbot"]); +const CORE_PACKAGE_NAMES = new Set(["openclaw"]); async function readPackageName(dir: string): Promise { try { @@ -39,7 +39,7 @@ function candidateDirsFromArgv1(argv1: string): string[] { return candidates; } -export async function resolveMoltbotPackageRoot(opts: { +export async function resolveOpenClawPackageRoot(opts: { cwd?: string; argv1?: string; moduleUrl?: string; diff --git a/src/infra/outbound/agent-delivery.test.ts b/src/infra/outbound/agent-delivery.test.ts index 27a10b58c4..ac76d327a6 100644 --- a/src/infra/outbound/agent-delivery.test.ts +++ b/src/infra/outbound/agent-delivery.test.ts @@ -12,7 +12,7 @@ vi.mock("./targets.js", async () => { }; }); -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveAgentDeliveryPlan, resolveAgentOutboundTarget } from "./agent-delivery.js"; describe("agent delivery helpers", () => { @@ -45,7 +45,7 @@ describe("agent delivery helpers", () => { }); const resolved = resolveAgentOutboundTarget({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, plan, targetMode: "implicit", }); @@ -68,7 +68,7 @@ describe("agent delivery helpers", () => { mocks.resolveOutboundTarget.mockClear(); const resolved = resolveAgentOutboundTarget({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, plan, targetMode: "explicit", validateExplicitTarget: false, diff --git a/src/infra/outbound/agent-delivery.ts b/src/infra/outbound/agent-delivery.ts index 2c83c70865..adc5ffe4cd 100644 --- a/src/infra/outbound/agent-delivery.ts +++ b/src/infra/outbound/agent-delivery.ts @@ -14,7 +14,7 @@ import { resolveSessionDeliveryTarget, type SessionDeliveryTarget, } from "./targets.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import type { OutboundTargetResolution } from "./targets.js"; export type AgentDeliveryPlan = { @@ -98,7 +98,7 @@ export function resolveAgentDeliveryPlan(params: { } export function resolveAgentOutboundTarget(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; plan: AgentDeliveryPlan; targetMode?: ChannelOutboundTargetMode; validateExplicitTarget?: boolean; diff --git a/src/infra/outbound/channel-selection.ts b/src/infra/outbound/channel-selection.ts index 833603ff3a..86f6439c60 100644 --- a/src/infra/outbound/channel-selection.ts +++ b/src/infra/outbound/channel-selection.ts @@ -1,6 +1,6 @@ import { listChannelPlugins } from "../../channels/plugins/index.js"; import type { ChannelPlugin } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { listDeliverableMessageChannels, type DeliverableMessageChannel, @@ -21,7 +21,7 @@ function isAccountEnabled(account: unknown): boolean { return enabled !== false; } -async function isPluginConfigured(plugin: ChannelPlugin, cfg: MoltbotConfig): Promise { +async function isPluginConfigured(plugin: ChannelPlugin, cfg: OpenClawConfig): Promise { const accountIds = plugin.config.listAccountIds(cfg); if (accountIds.length === 0) return false; @@ -40,7 +40,7 @@ async function isPluginConfigured(plugin: ChannelPlugin, cfg: MoltbotConfig): Pr } export async function listConfiguredMessageChannels( - cfg: MoltbotConfig, + cfg: OpenClawConfig, ): Promise { const channels: MessageChannelId[] = []; for (const plugin of listChannelPlugins()) { @@ -53,7 +53,7 @@ export async function listConfiguredMessageChannels( } export async function resolveMessageChannelSelection(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel?: string | null; }): Promise<{ channel: MessageChannelId; configured: MessageChannelId[] }> { const normalized = normalizeMessageChannel(params.channel); diff --git a/src/infra/outbound/deliver.test.ts b/src/infra/outbound/deliver.test.ts index ebbe30c447..abae530bb5 100644 --- a/src/infra/outbound/deliver.test.ts +++ b/src/infra/outbound/deliver.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { signalOutbound } from "../../channels/plugins/outbound/signal.js"; import { telegramOutbound } from "../../channels/plugins/outbound/telegram.js"; import { whatsappOutbound } from "../../channels/plugins/outbound/whatsapp.js"; @@ -38,7 +38,7 @@ describe("deliverOutboundPayloads", () => { }); it("chunks telegram markdown and passes through accountId", async () => { const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } }, }; const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; @@ -71,7 +71,7 @@ describe("deliverOutboundPayloads", () => { it("passes explicit accountId to sendTelegram", async () => { const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } }, }; @@ -93,7 +93,7 @@ describe("deliverOutboundPayloads", () => { it("uses signal media maxBytes from config", async () => { const sendSignal = vi.fn().mockResolvedValue({ messageId: "s1", timestamp: 123 }); - const cfg: MoltbotConfig = { channels: { signal: { mediaMaxMb: 2 } } }; + const cfg: OpenClawConfig = { channels: { signal: { mediaMaxMb: 2 } } }; const results = await deliverOutboundPayloads({ cfg, @@ -118,7 +118,7 @@ describe("deliverOutboundPayloads", () => { it("chunks Signal markdown using the format-first chunker", async () => { const sendSignal = vi.fn().mockResolvedValue({ messageId: "s1", timestamp: 123 }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { signal: { textChunkLimit: 20 } }, }; const text = `Intro\\n\\n\`\`\`\`md\\n${"y".repeat(60)}\\n\`\`\`\\n\\nOutro`; @@ -152,7 +152,7 @@ describe("deliverOutboundPayloads", () => { .fn() .mockResolvedValueOnce({ messageId: "w1", toJid: "jid" }) .mockResolvedValueOnce({ messageId: "w2", toJid: "jid" }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { textChunkLimit: 2 } }, }; @@ -170,7 +170,7 @@ describe("deliverOutboundPayloads", () => { it("respects newline chunk mode for WhatsApp", async () => { const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "w1", toJid: "jid" }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { textChunkLimit: 4000, chunkMode: "newline" } }, }; @@ -229,7 +229,7 @@ describe("deliverOutboundPayloads", () => { ]), ); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { matrix: { textChunkLimit: 4000, chunkMode: "newline" } }, }; const text = "```js\nconst a = 1;\nconst b = 2;\n```\nAfter"; @@ -256,7 +256,7 @@ describe("deliverOutboundPayloads", () => { }, ]), ); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { mediaMaxMb: 3 } }, }; @@ -293,7 +293,7 @@ describe("deliverOutboundPayloads", () => { .mockRejectedValueOnce(new Error("fail")) .mockResolvedValueOnce({ messageId: "w2", toJid: "jid" }); const onError = vi.fn(); - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const results = await deliverOutboundPayloads({ cfg, @@ -313,7 +313,7 @@ describe("deliverOutboundPayloads", () => { it("passes normalized payload to onError", async () => { const sendWhatsApp = vi.fn().mockRejectedValue(new Error("boom")); const onError = vi.fn(); - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; await deliverOutboundPayloads({ cfg, @@ -334,7 +334,7 @@ describe("deliverOutboundPayloads", () => { it("mirrors delivered output when mirror options are provided", async () => { const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" }); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } }, }; mocks.appendAssistantMessageToSessionTranscript.mockClear(); diff --git a/src/infra/outbound/deliver.ts b/src/infra/outbound/deliver.ts index 1abbd3557e..c9d260711d 100644 --- a/src/infra/outbound/deliver.ts +++ b/src/infra/outbound/deliver.ts @@ -8,7 +8,7 @@ import type { ReplyPayload } from "../../auto-reply/types.js"; import { resolveChannelMediaMaxBytes } from "../../channels/plugins/media-limits.js"; import { loadChannelOutboundAdapter } from "../../channels/plugins/outbound/load.js"; import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveMarkdownTableMode } from "../../config/markdown-tables.js"; import type { sendMessageDiscord } from "../../discord/send.js"; import type { sendMessageIMessage } from "../../imessage/send.js"; @@ -82,7 +82,7 @@ function throwIfAborted(abortSignal?: AbortSignal): void { // Channel docking: outbound delivery delegates to plugin.outbound adapters. async function createChannelHandler(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: Exclude; to: string; accountId?: string; @@ -114,7 +114,7 @@ async function createChannelHandler(params: { function createPluginHandler(params: { outbound?: ChannelOutboundAdapter; - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: Exclude; to: string; accountId?: string; @@ -175,7 +175,7 @@ function createPluginHandler(params: { } export async function deliverOutboundPayloads(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: Exclude; to: string; accountId?: string; diff --git a/src/infra/outbound/directory-cache.ts b/src/infra/outbound/directory-cache.ts index e957daeb68..13e7f039ef 100644 --- a/src/infra/outbound/directory-cache.ts +++ b/src/infra/outbound/directory-cache.ts @@ -1,5 +1,5 @@ import type { ChannelDirectoryEntryKind, ChannelId } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; type CacheEntry = { value: T; @@ -21,11 +21,11 @@ export function buildDirectoryCacheKey(key: DirectoryCacheKey): string { export class DirectoryCache { private readonly cache = new Map>(); - private lastConfigRef: MoltbotConfig | null = null; + private lastConfigRef: OpenClawConfig | null = null; constructor(private readonly ttlMs: number) {} - get(key: string, cfg: MoltbotConfig): T | undefined { + get(key: string, cfg: OpenClawConfig): T | undefined { this.resetIfConfigChanged(cfg); const entry = this.cache.get(key); if (!entry) return undefined; @@ -36,7 +36,7 @@ export class DirectoryCache { return entry.value; } - set(key: string, value: T, cfg: MoltbotConfig): void { + set(key: string, value: T, cfg: OpenClawConfig): void { this.resetIfConfigChanged(cfg); this.cache.set(key, { value, fetchedAt: Date.now() }); } @@ -47,12 +47,12 @@ export class DirectoryCache { } } - clear(cfg?: MoltbotConfig): void { + clear(cfg?: OpenClawConfig): void { this.cache.clear(); if (cfg) this.lastConfigRef = cfg; } - private resetIfConfigChanged(cfg: MoltbotConfig): void { + private resetIfConfigChanged(cfg: OpenClawConfig): void { if (this.lastConfigRef && this.lastConfigRef !== cfg) { this.cache.clear(); } diff --git a/src/infra/outbound/message-action-runner.test.ts b/src/infra/outbound/message-action-runner.test.ts index 9ae25561de..6445292f6a 100644 --- a/src/infra/outbound/message-action-runner.test.ts +++ b/src/infra/outbound/message-action-runner.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { setActivePluginRegistry } from "../../plugins/runtime.js"; import { createIMessageTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js"; import { slackPlugin } from "../../../extensions/slack/src/channel.js"; @@ -26,7 +26,7 @@ const slackConfig = { appToken: "xapp-test", }, }, -} as MoltbotConfig; +} as OpenClawConfig; const whatsappConfig = { channels: { @@ -34,7 +34,7 @@ const whatsappConfig = { allowFrom: ["*"], }, }, -} as MoltbotConfig; +} as OpenClawConfig; describe("runMessageAction context isolation", () => { beforeEach(async () => { @@ -263,7 +263,7 @@ describe("runMessageAction context isolation", () => { token: "tg-test", }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = await runMessageAction({ cfg: multiConfig, @@ -305,7 +305,7 @@ describe("runMessageAction context isolation", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; await expect( runMessageAction({ @@ -423,7 +423,7 @@ describe("runMessageAction sendAttachment hydration", () => { password: "test-password", }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = await runMessageAction({ cfg, @@ -491,7 +491,7 @@ describe("runMessageAction accountId defaults", () => { it("propagates defaultAccountId into params", async () => { await runMessageAction({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, action: "send", params: { channel: "discord", diff --git a/src/infra/outbound/message-action-runner.threading.test.ts b/src/infra/outbound/message-action-runner.threading.test.ts index 68a719fc51..0a6ca44e9e 100644 --- a/src/infra/outbound/message-action-runner.threading.test.ts +++ b/src/infra/outbound/message-action-runner.threading.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { setActivePluginRegistry } from "../../plugins/runtime.js"; import { createTestRegistry } from "../../test-utils/channel-plugins.js"; import { slackPlugin } from "../../../extensions/slack/src/channel.js"; @@ -39,7 +39,7 @@ const slackConfig = { appToken: "xapp-test", }, }, -} as MoltbotConfig; +} as OpenClawConfig; describe("runMessageAction Slack threading", () => { beforeEach(async () => { diff --git a/src/infra/outbound/message-action-runner.ts b/src/infra/outbound/message-action-runner.ts index 8f99ad7917..98beaa828e 100644 --- a/src/infra/outbound/message-action-runner.ts +++ b/src/infra/outbound/message-action-runner.ts @@ -15,7 +15,7 @@ import type { ChannelMessageActionName, ChannelThreadingToolContext, } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { isDeliverableMessageChannel, normalizeMessageChannel, @@ -54,7 +54,7 @@ export type MessageActionRunnerGateway = { }; export type RunMessageActionParams = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; action: ChannelMessageActionName; params: Record; defaultAccountId?: string; @@ -168,7 +168,7 @@ function applyCrossContextMessageDecoration({ } async function maybeApplyCrossContextMarker(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; action: ChannelMessageActionName; target: string; @@ -224,7 +224,7 @@ function resolveSlackAutoThreadId(params: { } function resolveAttachmentMaxBytes(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; accountId?: string | null; }): number | undefined { @@ -298,7 +298,7 @@ function normalizeBase64Payload(params: { base64?: string; contentType?: string } async function hydrateSetGroupIconParams(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; accountId?: string | null; args: Record; @@ -355,7 +355,7 @@ async function hydrateSetGroupIconParams(params: { } async function hydrateSendAttachmentParams(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; accountId?: string | null; args: Record; @@ -444,7 +444,7 @@ function parseCardParam(params: Record): void { } } -async function resolveChannel(cfg: MoltbotConfig, params: Record) { +async function resolveChannel(cfg: OpenClawConfig, params: Record) { const channelHint = readStringParam(params, "channel"); const selection = await resolveMessageChannelSelection({ cfg, @@ -454,7 +454,7 @@ async function resolveChannel(cfg: MoltbotConfig, params: Record; @@ -499,7 +499,7 @@ async function resolveActionTarget(params: { } type ResolvedActionContext = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; params: Record; channel: ChannelId; accountId?: string | null; diff --git a/src/infra/outbound/message.ts b/src/infra/outbound/message.ts index 517b72ee54..12bf16a359 100644 --- a/src/infra/outbound/message.ts +++ b/src/infra/outbound/message.ts @@ -1,6 +1,6 @@ import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js"; import type { ChannelId } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { loadConfig } from "../../config/config.js"; import { callGateway, randomIdempotencyKey } from "../../gateway/call.js"; import type { PollInput } from "../../polls.js"; @@ -41,7 +41,7 @@ type MessageSendParams = { dryRun?: boolean; bestEffort?: boolean; deps?: OutboundSendDeps; - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; gateway?: MessageGatewayOptions; idempotencyKey?: string; mirror?: { @@ -71,7 +71,7 @@ type MessagePollParams = { durationHours?: number; channel?: string; dryRun?: boolean; - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; gateway?: MessageGatewayOptions; idempotencyKey?: string; }; diff --git a/src/infra/outbound/outbound-policy.test.ts b/src/infra/outbound/outbound-policy.test.ts index f798d7e9b1..9d47a79262 100644 --- a/src/infra/outbound/outbound-policy.test.ts +++ b/src/infra/outbound/outbound-policy.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { applyCrossContextDecoration, buildCrossContextDecoration, @@ -14,13 +14,13 @@ const slackConfig = { appToken: "xapp-test", }, }, -} as MoltbotConfig; +} as OpenClawConfig; const discordConfig = { channels: { discord: {}, }, -} as MoltbotConfig; +} as OpenClawConfig; describe("outbound policy", () => { it("blocks cross-provider sends by default", () => { @@ -41,7 +41,7 @@ describe("outbound policy", () => { tools: { message: { crossContext: { allowAcrossProviders: true } }, }, - } as MoltbotConfig; + } as OpenClawConfig; expect(() => enforceCrossContextPolicy({ @@ -58,7 +58,7 @@ describe("outbound policy", () => { const cfg = { ...slackConfig, tools: { message: { crossContext: { allowWithinProvider: false } } }, - } as MoltbotConfig; + } as OpenClawConfig; expect(() => enforceCrossContextPolicy({ diff --git a/src/infra/outbound/outbound-policy.ts b/src/infra/outbound/outbound-policy.ts index 9b34709495..9585d56d05 100644 --- a/src/infra/outbound/outbound-policy.ts +++ b/src/infra/outbound/outbound-policy.ts @@ -4,7 +4,7 @@ import type { ChannelMessageActionName, ChannelThreadingToolContext, } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { getChannelMessageAdapter } from "./channel-adapters.js"; import { formatTargetDisplay, lookupDirectoryDisplay } from "./target-resolver.js"; @@ -74,7 +74,7 @@ export function enforceCrossContextPolicy(params: { action: ChannelMessageActionName; args: Record; toolContext?: ChannelThreadingToolContext; - cfg: MoltbotConfig; + cfg: OpenClawConfig; }): void { const currentTarget = params.toolContext?.currentChannelId?.trim(); if (!currentTarget) return; @@ -112,7 +112,7 @@ export function enforceCrossContextPolicy(params: { } export async function buildCrossContextDecoration(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; target: string; toolContext?: ChannelThreadingToolContext; diff --git a/src/infra/outbound/outbound-send-service.ts b/src/infra/outbound/outbound-send-service.ts index 6499eb452c..b296a6fad8 100644 --- a/src/infra/outbound/outbound-send-service.ts +++ b/src/infra/outbound/outbound-send-service.ts @@ -1,7 +1,7 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import { dispatchChannelMessageAction } from "../../channels/plugins/message-actions.js"; import type { ChannelId, ChannelThreadingToolContext } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { appendAssistantMessageToSessionTranscript } from "../../config/sessions.js"; import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js"; import type { OutboundSendDeps } from "./deliver.js"; @@ -18,7 +18,7 @@ export type OutboundGatewayContext = { }; export type OutboundSendContext = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; params: Record; accountId?: string | null; diff --git a/src/infra/outbound/outbound-session.test.ts b/src/infra/outbound/outbound-session.test.ts index 23db09e748..b06864d2c2 100644 --- a/src/infra/outbound/outbound-session.test.ts +++ b/src/infra/outbound/outbound-session.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveOutboundSessionRoute } from "./outbound-session.js"; -const baseConfig = {} as MoltbotConfig; +const baseConfig = {} as OpenClawConfig; describe("resolveOutboundSessionRoute", () => { it("builds Slack thread session keys", async () => { @@ -36,7 +36,7 @@ describe("resolveOutboundSessionRoute", () => { }); it("treats Telegram usernames as DMs when unresolved", async () => { - const cfg = { session: { dmScope: "per-channel-peer" } } as MoltbotConfig; + const cfg = { session: { dmScope: "per-channel-peer" } } as OpenClawConfig; const route = await resolveOutboundSessionRoute({ cfg, channel: "telegram", @@ -56,7 +56,7 @@ describe("resolveOutboundSessionRoute", () => { alice: ["discord:123"], }, }, - } as MoltbotConfig; + } as OpenClawConfig; const route = await resolveOutboundSessionRoute({ cfg, @@ -81,7 +81,7 @@ describe("resolveOutboundSessionRoute", () => { }); it("treats Zalo Personal DM targets as direct sessions", async () => { - const cfg = { session: { dmScope: "per-channel-peer" } } as MoltbotConfig; + const cfg = { session: { dmScope: "per-channel-peer" } } as OpenClawConfig; const route = await resolveOutboundSessionRoute({ cfg, channel: "zalouser", @@ -102,7 +102,7 @@ describe("resolveOutboundSessionRoute", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const route = await resolveOutboundSessionRoute({ cfg, diff --git a/src/infra/outbound/outbound-session.ts b/src/infra/outbound/outbound-session.ts index 9c12fab969..79a1295751 100644 --- a/src/infra/outbound/outbound-session.ts +++ b/src/infra/outbound/outbound-session.ts @@ -1,7 +1,7 @@ import type { MsgContext } from "../../auto-reply/templating.js"; import { getChannelPlugin } from "../../channels/plugins/index.js"; import type { ChannelId } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { recordSessionMetaFromInbound, resolveStorePath } from "../../config/sessions.js"; import { parseDiscordTarget } from "../../discord/targets.js"; import { parseIMessageTarget, normalizeIMessageHandle } from "../../imessage/targets.js"; @@ -37,7 +37,7 @@ export type OutboundSessionRoute = { }; export type ResolveOutboundSessionRouteParams = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; agentId: string; accountId?: string | null; @@ -100,7 +100,7 @@ function inferPeerKind(params: { } function buildBaseSessionKey(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId: string; channel: ChannelId; accountId?: string | null; @@ -118,7 +118,7 @@ function buildBaseSessionKey(params: { // Best-effort mpim detection: allowlist/config, then Slack API (if token available). async function resolveSlackChannelType(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; channelId: string; }): Promise<"channel" | "group" | "dm" | "unknown"> { @@ -824,7 +824,7 @@ export async function resolveOutboundSessionRoute( } export async function ensureOutboundSessionEntry(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId: string; channel: ChannelId; accountId?: string | null; diff --git a/src/infra/outbound/target-resolver.test.ts b/src/infra/outbound/target-resolver.test.ts index f4734f544f..62e9ab84a5 100644 --- a/src/infra/outbound/target-resolver.test.ts +++ b/src/infra/outbound/target-resolver.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { ChannelDirectoryEntry } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resetDirectoryCache, resolveMessagingTarget } from "./target-resolver.js"; const mocks = vi.hoisted(() => ({ @@ -16,7 +16,7 @@ vi.mock("../../channels/plugins/index.js", () => ({ })); describe("resolveMessagingTarget (directory fallback)", () => { - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; beforeEach(() => { mocks.listGroups.mockReset(); diff --git a/src/infra/outbound/target-resolver.ts b/src/infra/outbound/target-resolver.ts index 6b2505a794..ed9deec390 100644 --- a/src/infra/outbound/target-resolver.ts +++ b/src/infra/outbound/target-resolver.ts @@ -4,7 +4,7 @@ import type { ChannelDirectoryEntryKind, ChannelId, } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { defaultRuntime, type RuntimeEnv } from "../../runtime.js"; import { buildDirectoryCacheKey, DirectoryCache } from "./directory-cache.js"; import { @@ -30,7 +30,7 @@ export type ResolveMessagingTargetResult = | { ok: false; error: Error; candidates?: ChannelDirectoryEntry[] }; export async function resolveChannelTarget(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; input: string; accountId?: string | null; @@ -177,7 +177,7 @@ function resolveMatch(params: { } async function listDirectoryEntries(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; accountId?: string | null; kind: ChannelDirectoryEntryKind; @@ -213,7 +213,7 @@ async function listDirectoryEntries(params: { } async function getDirectoryEntries(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; accountId?: string | null; kind: ChannelDirectoryEntryKind; @@ -281,7 +281,7 @@ function pickAmbiguousMatch( } export async function resolveMessagingTarget(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; input: string; accountId?: string | null; @@ -397,7 +397,7 @@ export async function resolveMessagingTarget(params: { } export async function lookupDirectoryDisplay(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: ChannelId; targetId: string; accountId?: string | null; diff --git a/src/infra/outbound/targets.test.ts b/src/infra/outbound/targets.test.ts index d8b968d064..1040f0c65c 100644 --- a/src/infra/outbound/targets.test.ts +++ b/src/infra/outbound/targets.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { setActivePluginRegistry } from "../../plugins/runtime.js"; import { createTestRegistry } from "../../test-utils/channel-plugins.js"; @@ -18,7 +18,7 @@ describe("resolveOutboundTarget", () => { }); it("falls back to whatsapp allowFrom via config", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["+1555"] } }, }; const res = resolveOutboundTarget({ diff --git a/src/infra/outbound/targets.ts b/src/infra/outbound/targets.ts index 8b557c0a69..0660b31c91 100644 --- a/src/infra/outbound/targets.ts +++ b/src/infra/outbound/targets.ts @@ -1,7 +1,7 @@ import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js"; import { formatCliCommand } from "../../cli/command-format.js"; import type { ChannelId, ChannelOutboundTargetMode } from "../../channels/plugins/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import type { SessionEntry } from "../../config/sessions.js"; import type { AgentDefaultsConfig } from "../../config/types.agent-defaults.js"; import { deliveryContextFromSession } from "../../utils/delivery-context.js"; @@ -119,7 +119,7 @@ export function resolveOutboundTarget(params: { channel: GatewayMessageChannel; to?: string; allowFrom?: string[]; - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; accountId?: string | null; mode?: ChannelOutboundTargetMode; }): OutboundTargetResolution { @@ -127,7 +127,7 @@ export function resolveOutboundTarget(params: { return { ok: false, error: new Error( - `Delivering to WebChat is not supported via \`${formatCliCommand("moltbot agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`, + `Delivering to WebChat is not supported via \`${formatCliCommand("openclaw agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`, ), }; } @@ -172,7 +172,7 @@ export function resolveOutboundTarget(params: { } export function resolveHeartbeatDeliveryTarget(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; entry?: SessionEntry; heartbeat?: AgentDefaultsConfig["heartbeat"]; }): OutboundTarget { @@ -289,7 +289,7 @@ function resolveHeartbeatSenderId(params: { } export function resolveHeartbeatSenderContext(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; entry?: SessionEntry; delivery: OutboundTarget; }): HeartbeatSenderContext { diff --git a/src/infra/path-env.test.ts b/src/infra/path-env.test.ts index 9c54ff6d5b..2b46ccf500 100644 --- a/src/infra/path-env.test.ts +++ b/src/infra/path-env.test.ts @@ -4,24 +4,24 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; -import { ensureMoltbotCliOnPath } from "./path-env.js"; +import { ensureOpenClawCliOnPath } from "./path-env.js"; -describe("ensureMoltbotCliOnPath", () => { - it("prepends the bundled app bin dir when a sibling moltbot exists", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-")); +describe("ensureOpenClawCliOnPath", () => { + it("prepends the bundled app bin dir when a sibling openclaw exists", async () => { + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-path-")); try { const appBinDir = path.join(tmp, "AppBin"); await fs.mkdir(appBinDir, { recursive: true }); - const cliPath = path.join(appBinDir, "moltbot"); + const cliPath = path.join(appBinDir, "openclaw"); await fs.writeFile(cliPath, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(cliPath, 0o755); const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + const originalFlag = process.env.OPENCLAW_PATH_BOOTSTRAPPED; process.env.PATH = "/usr/bin"; - delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; try { - ensureMoltbotCliOnPath({ + ensureOpenClawCliOnPath({ execPath: cliPath, cwd: tmp, homeDir: tmp, @@ -31,8 +31,8 @@ describe("ensureMoltbotCliOnPath", () => { expect(updated.split(path.delimiter)[0]).toBe(appBinDir); } finally { process.env.PATH = originalPath; - if (originalFlag === undefined) delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; - else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; + if (originalFlag === undefined) delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; + else process.env.OPENCLAW_PATH_BOOTSTRAPPED = originalFlag; } } finally { await fs.rm(tmp, { recursive: true, force: true }); @@ -41,11 +41,11 @@ describe("ensureMoltbotCliOnPath", () => { it("is idempotent", () => { const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + const originalFlag = process.env.OPENCLAW_PATH_BOOTSTRAPPED; process.env.PATH = "/bin"; - process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1"; + process.env.OPENCLAW_PATH_BOOTSTRAPPED = "1"; try { - ensureMoltbotCliOnPath({ + ensureOpenClawCliOnPath({ execPath: "/tmp/does-not-matter", cwd: "/tmp", homeDir: "/tmp", @@ -54,26 +54,26 @@ describe("ensureMoltbotCliOnPath", () => { expect(process.env.PATH).toBe("/bin"); } finally { process.env.PATH = originalPath; - if (originalFlag === undefined) delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; - else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; + if (originalFlag === undefined) delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; + else process.env.OPENCLAW_PATH_BOOTSTRAPPED = originalFlag; } }); it("prepends mise shims when available", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-path-")); const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + const originalFlag = process.env.OPENCLAW_PATH_BOOTSTRAPPED; const originalMiseDataDir = process.env.MISE_DATA_DIR; try { const appBinDir = path.join(tmp, "AppBin"); await fs.mkdir(appBinDir, { recursive: true }); - const appCli = path.join(appBinDir, "moltbot"); + const appCli = path.join(appBinDir, "openclaw"); await fs.writeFile(appCli, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(appCli, 0o755); const localBinDir = path.join(tmp, "node_modules", ".bin"); await fs.mkdir(localBinDir, { recursive: true }); - const localCli = path.join(localBinDir, "moltbot"); + const localCli = path.join(localBinDir, "openclaw"); await fs.writeFile(localCli, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(localCli, 0o755); @@ -82,9 +82,9 @@ describe("ensureMoltbotCliOnPath", () => { await fs.mkdir(shimsDir, { recursive: true }); process.env.MISE_DATA_DIR = miseDataDir; process.env.PATH = "/usr/bin"; - delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; - ensureMoltbotCliOnPath({ + ensureOpenClawCliOnPath({ execPath: appCli, cwd: tmp, homeDir: tmp, @@ -101,8 +101,8 @@ describe("ensureMoltbotCliOnPath", () => { expect(shimsIndex).toBeGreaterThan(localIndex); } finally { process.env.PATH = originalPath; - if (originalFlag === undefined) delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; - else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; + if (originalFlag === undefined) delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; + else process.env.OPENCLAW_PATH_BOOTSTRAPPED = originalFlag; if (originalMiseDataDir === undefined) delete process.env.MISE_DATA_DIR; else process.env.MISE_DATA_DIR = originalMiseDataDir; await fs.rm(tmp, { recursive: true, force: true }); @@ -110,9 +110,9 @@ describe("ensureMoltbotCliOnPath", () => { }); it("prepends Linuxbrew dirs when present", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-path-")); const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + const originalFlag = process.env.OPENCLAW_PATH_BOOTSTRAPPED; const originalHomebrewPrefix = process.env.HOMEBREW_PREFIX; const originalHomebrewBrewFile = process.env.HOMEBREW_BREW_FILE; const originalXdgBinHome = process.env.XDG_BIN_HOME; @@ -126,12 +126,12 @@ describe("ensureMoltbotCliOnPath", () => { await fs.mkdir(linuxbrewSbin, { recursive: true }); process.env.PATH = "/usr/bin"; - delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; delete process.env.HOMEBREW_PREFIX; delete process.env.HOMEBREW_BREW_FILE; delete process.env.XDG_BIN_HOME; - ensureMoltbotCliOnPath({ + ensureOpenClawCliOnPath({ execPath: path.join(execDir, "node"), cwd: tmp, homeDir: tmp, @@ -144,8 +144,8 @@ describe("ensureMoltbotCliOnPath", () => { expect(parts[1]).toBe(linuxbrewSbin); } finally { process.env.PATH = originalPath; - if (originalFlag === undefined) delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; - else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; + if (originalFlag === undefined) delete process.env.OPENCLAW_PATH_BOOTSTRAPPED; + else process.env.OPENCLAW_PATH_BOOTSTRAPPED = originalFlag; if (originalHomebrewPrefix === undefined) delete process.env.HOMEBREW_PREFIX; else process.env.HOMEBREW_PREFIX = originalHomebrewPrefix; if (originalHomebrewBrewFile === undefined) delete process.env.HOMEBREW_BREW_FILE; diff --git a/src/infra/path-env.ts b/src/infra/path-env.ts index b079b36ece..24d0d82b91 100644 --- a/src/infra/path-env.ts +++ b/src/infra/path-env.ts @@ -5,7 +5,7 @@ import { isTruthyEnvValue } from "./env.js"; import { resolveBrewPathDirs } from "./brew.js"; -type EnsureMoltbotPathOpts = { +type EnsureOpenClawPathOpts = { execPath?: string; cwd?: string; homeDir?: string; @@ -48,7 +48,7 @@ function mergePath(params: { existing: string; prepend: string[] }): string { return merged.join(path.delimiter); } -function candidateBinDirs(opts: EnsureMoltbotPathOpts): string[] { +function candidateBinDirs(opts: EnsureOpenClawPathOpts): string[] { const execPath = opts.execPath ?? process.execPath; const cwd = opts.cwd ?? process.cwd(); const homeDir = opts.homeDir ?? os.homedir(); @@ -56,19 +56,19 @@ function candidateBinDirs(opts: EnsureMoltbotPathOpts): string[] { const candidates: string[] = []; - // Bundled macOS app: `moltbot` lives next to the executable (process.execPath). + // Bundled macOS app: `openclaw` lives next to the executable (process.execPath). try { const execDir = path.dirname(execPath); - const siblingMoltbot = path.join(execDir, "moltbot"); - if (isExecutable(siblingMoltbot)) candidates.push(execDir); + const siblingCli = path.join(execDir, "openclaw"); + if (isExecutable(siblingCli)) candidates.push(execDir); } catch { // ignore } - // Project-local installs (best effort): if a `node_modules/.bin/moltbot` exists near cwd, + // Project-local installs (best effort): if a `node_modules/.bin/openclaw` exists near cwd, // include it. This helps when running under launchd or other minimal PATH environments. const localBinDir = path.join(cwd, "node_modules", ".bin"); - if (isExecutable(path.join(localBinDir, "moltbot"))) candidates.push(localBinDir); + if (isExecutable(path.join(localBinDir, "openclaw"))) candidates.push(localBinDir); const miseDataDir = process.env.MISE_DATA_DIR ?? path.join(homeDir, ".local", "share", "mise"); const miseShims = path.join(miseDataDir, "shims"); @@ -91,12 +91,14 @@ function candidateBinDirs(opts: EnsureMoltbotPathOpts): string[] { } /** - * Best-effort PATH bootstrap so skills that require the `moltbot` CLI can run + * Best-effort PATH bootstrap so skills that require the `openclaw` CLI can run * under launchd/minimal environments (and inside the macOS app bundle). */ -export function ensureMoltbotCliOnPath(opts: EnsureMoltbotPathOpts = {}) { - if (isTruthyEnvValue(process.env.CLAWDBOT_PATH_BOOTSTRAPPED)) return; - process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1"; +export function ensureOpenClawCliOnPath(opts: EnsureOpenClawPathOpts = {}) { + if (isTruthyEnvValue(process.env.OPENCLAW_PATH_BOOTSTRAPPED)) { + return; + } + process.env.OPENCLAW_PATH_BOOTSTRAPPED = "1"; const existing = opts.pathEnv ?? process.env.PATH ?? ""; const prepend = candidateBinDirs(opts); diff --git a/src/infra/ports-format.ts b/src/infra/ports-format.ts index 5767d6d9b7..3cada2879e 100644 --- a/src/infra/ports-format.ts +++ b/src/infra/ports-format.ts @@ -3,7 +3,9 @@ import type { PortListener, PortListenerKind, PortUsage } from "./ports-types.js export function classifyPortListener(listener: PortListener, port: number): PortListenerKind { const raw = `${listener.commandLine ?? ""} ${listener.command ?? ""}`.trim().toLowerCase(); - if (raw.includes("moltbot")) return "gateway"; + if (raw.includes("openclaw")) { + return "gateway"; + } if (raw.includes("ssh")) { const portToken = String(port); const tunnelPattern = new RegExp( @@ -21,7 +23,7 @@ export function buildPortHints(listeners: PortListener[], port: number): string[ const hints: string[] = []; if (kinds.has("gateway")) { hints.push( - `Gateway already running locally. Stop it (${formatCliCommand("moltbot gateway stop")}) or use a different port.`, + `Gateway already running locally. Stop it (${formatCliCommand("openclaw gateway stop")}) or use a different port.`, ); } if (kinds.has("ssh")) { diff --git a/src/infra/ports.test.ts b/src/infra/ports.test.ts index abb28ea53c..9a70d049e0 100644 --- a/src/infra/ports.test.ts +++ b/src/infra/ports.test.ts @@ -37,7 +37,7 @@ describe("ports helpers", () => { expect( classifyPortListener( { - commandLine: "node /Users/me/Projects/moltbot/dist/entry.js gateway", + commandLine: "node /Users/me/Projects/openclaw/dist/entry.js gateway", }, 18789, ), diff --git a/src/infra/ports.ts b/src/infra/ports.ts index 0270824325..37030ca9b8 100644 --- a/src/infra/ports.ts +++ b/src/infra/ports.ts @@ -63,10 +63,10 @@ export async function handlePortError( if (details) { runtime.error(info("Port listener details:")); runtime.error(details); - if (/moltbot|src\/index\.ts|dist\/index\.js/.test(details)) { + if (/openclaw|src\/index\.ts|dist\/index\.js/.test(details)) { runtime.error( warn( - "It looks like another moltbot instance is already running. Stop it or pick a different port.", + "It looks like another OpenClaw instance is already running. Stop it or pick a different port.", ), ); } diff --git a/src/infra/provider-usage.fetch.claude.ts b/src/infra/provider-usage.fetch.claude.ts index a0f6a241a3..654962c934 100644 --- a/src/infra/provider-usage.fetch.claude.ts +++ b/src/infra/provider-usage.fetch.claude.ts @@ -104,7 +104,7 @@ export async function fetchClaudeUsage( { headers: { Authorization: `Bearer ${token}`, - "User-Agent": "moltbot", + "User-Agent": "openclaw", Accept: "application/json", "anthropic-version": "2023-06-01", "anthropic-beta": "oauth-2025-04-20", diff --git a/src/infra/provider-usage.fetch.minimax.ts b/src/infra/provider-usage.fetch.minimax.ts index 1cc2cea51e..cc1dedb174 100644 --- a/src/infra/provider-usage.fetch.minimax.ts +++ b/src/infra/provider-usage.fetch.minimax.ts @@ -289,7 +289,7 @@ export async function fetchMinimaxUsage( headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", - "MM-API-Source": "Moltbot", + "MM-API-Source": "OpenClaw", }, }, timeoutMs, diff --git a/src/infra/provider-usage.test.ts b/src/infra/provider-usage.test.ts index 077e70918b..5bc6ba5754 100644 --- a/src/infra/provider-usage.test.ts +++ b/src/infra/provider-usage.test.ts @@ -253,7 +253,7 @@ describe("provider usage loading", () => { await withTempHome( async (tempHome) => { const agentDir = path.join( - process.env.CLAWDBOT_STATE_DIR ?? path.join(tempHome, ".clawdbot"), + process.env.OPENCLAW_STATE_DIR ?? path.join(tempHome, ".openclaw"), "agents", "main", "agent", @@ -328,9 +328,9 @@ describe("provider usage loading", () => { }, { env: { - CLAWDBOT_STATE_DIR: (home) => path.join(home, ".clawdbot"), + OPENCLAW_STATE_DIR: (home) => path.join(home, ".openclaw"), }, - prefix: "moltbot-provider-usage-", + prefix: "openclaw-provider-usage-", }, ); }); diff --git a/src/infra/restart-sentinel.test.ts b/src/infra/restart-sentinel.test.ts index cc49347743..030dea65d0 100644 --- a/src/infra/restart-sentinel.test.ts +++ b/src/infra/restart-sentinel.test.ts @@ -16,14 +16,14 @@ describe("restart sentinel", () => { let tempDir: string; beforeEach(async () => { - prevStateDir = process.env.CLAWDBOT_STATE_DIR; - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sentinel-")); - process.env.CLAWDBOT_STATE_DIR = tempDir; + prevStateDir = process.env.OPENCLAW_STATE_DIR; + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sentinel-")); + process.env.OPENCLAW_STATE_DIR = tempDir; }); afterEach(async () => { - if (prevStateDir) process.env.CLAWDBOT_STATE_DIR = prevStateDir; - else delete process.env.CLAWDBOT_STATE_DIR; + if (prevStateDir) process.env.OPENCLAW_STATE_DIR = prevStateDir; + else delete process.env.OPENCLAW_STATE_DIR; await fs.rm(tempDir, { recursive: true, force: true }); }); diff --git a/src/infra/restart-sentinel.ts b/src/infra/restart-sentinel.ts index 06ea96426c..3d2ad07fd8 100644 --- a/src/infra/restart-sentinel.ts +++ b/src/infra/restart-sentinel.ts @@ -56,7 +56,7 @@ const SENTINEL_FILENAME = "restart-sentinel.json"; export function formatDoctorNonInteractiveHint( env: Record = process.env as Record, ): string { - return `Run: ${formatCliCommand("moltbot doctor --non-interactive", env)}`; + return `Run: ${formatCliCommand("openclaw doctor --non-interactive", env)}`; } export function resolveRestartSentinelPath(env: NodeJS.ProcessEnv = process.env): string { diff --git a/src/infra/restart.ts b/src/infra/restart.ts index 130029e531..543c875ff5 100644 --- a/src/infra/restart.ts +++ b/src/infra/restart.ts @@ -87,7 +87,7 @@ function normalizeSystemdUnit(raw?: string, profile?: string): string { return unit.endsWith(".service") ? unit : `${unit}.service`; } -export function triggerMoltbotRestart(): RestartAttempt { +export function triggerOpenClawRestart(): RestartAttempt { if (process.env.VITEST || process.env.NODE_ENV === "test") { return { ok: true, method: "supervisor", detail: "test mode" }; } @@ -95,8 +95,8 @@ export function triggerMoltbotRestart(): RestartAttempt { if (process.platform !== "darwin") { if (process.platform === "linux") { const unit = normalizeSystemdUnit( - process.env.CLAWDBOT_SYSTEMD_UNIT, - process.env.CLAWDBOT_PROFILE, + process.env.OPENCLAW_SYSTEMD_UNIT, + process.env.OPENCLAW_PROFILE, ); const userArgs = ["--user", "restart", unit]; tried.push(`systemctl ${userArgs.join(" ")}`); @@ -130,8 +130,8 @@ export function triggerMoltbotRestart(): RestartAttempt { } const label = - process.env.CLAWDBOT_LAUNCHD_LABEL || - resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE); + process.env.OPENCLAW_LAUNCHD_LABEL || + resolveGatewayLaunchAgentLabel(process.env.OPENCLAW_PROFILE); const uid = typeof process.getuid === "function" ? process.getuid() : undefined; const target = uid !== undefined ? `gui/${uid}/${label}` : label; const args = ["kickstart", "-k", target]; diff --git a/src/infra/runtime-guard.ts b/src/infra/runtime-guard.ts index 7f0b330fe1..0c3140bf27 100644 --- a/src/infra/runtime-guard.ts +++ b/src/infra/runtime-guard.ts @@ -75,11 +75,11 @@ export function assertSupportedRuntime( runtime.error( [ - "moltbot requires Node >=22.0.0.", + "openclaw requires Node >=22.0.0.", `Detected: ${runtimeLabel} (exec: ${execLabel}).`, `PATH searched: ${details.pathEnv}`, "Install Node: https://nodejs.org/en/download", - "Upgrade Node and re-run moltbot.", + "Upgrade Node and re-run openclaw.", ].join("\n"), ); runtime.exit(1); diff --git a/src/infra/session-cost-usage.test.ts b/src/infra/session-cost-usage.test.ts index 79b99b76d5..2fc36e1a96 100644 --- a/src/infra/session-cost-usage.test.ts +++ b/src/infra/session-cost-usage.test.ts @@ -4,12 +4,12 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadCostUsageSummary, loadSessionCostSummary } from "./session-cost-usage.js"; describe("session cost usage", () => { it("aggregates daily totals with log cost and pricing fallback", async () => { - const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-cost-")); + const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cost-")); const sessionsDir = path.join(root, "agents", "main", "sessions"); await fs.mkdir(sessionsDir, { recursive: true }); const sessionFile = path.join(sessionsDir, "sess-1.jsonl"); @@ -92,23 +92,23 @@ describe("session cost usage", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; - const originalState = process.env.CLAWDBOT_STATE_DIR; - process.env.CLAWDBOT_STATE_DIR = root; + const originalState = process.env.OPENCLAW_STATE_DIR; + process.env.OPENCLAW_STATE_DIR = root; try { const summary = await loadCostUsageSummary({ days: 30, config }); expect(summary.daily.length).toBe(1); expect(summary.totals.totalTokens).toBe(50); expect(summary.totals.totalCost).toBeCloseTo(0.03003, 5); } finally { - if (originalState === undefined) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = originalState; + if (originalState === undefined) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = originalState; } }); it("summarizes a single session file", async () => { - const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-cost-session-")); + const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cost-session-")); const sessionFile = path.join(root, "session.jsonl"); const now = new Date(); diff --git a/src/infra/session-cost-usage.ts b/src/infra/session-cost-usage.ts index 6d8578743b..28cbaa0b27 100644 --- a/src/infra/session-cost-usage.ts +++ b/src/infra/session-cost-usage.ts @@ -4,7 +4,7 @@ import readline from "node:readline"; import type { NormalizedUsage, UsageLike } from "../agents/usage.js"; import { normalizeUsage } from "../agents/usage.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions/types.js"; import { resolveSessionFilePath, @@ -138,7 +138,7 @@ const applyCostTotal = (totals: CostUsageTotals, costTotal: number | undefined) async function scanUsageFile(params: { filePath: string; - config?: MoltbotConfig; + config?: OpenClawConfig; onEntry: (entry: ParsedUsageEntry) => void; }): Promise { const fileStream = fs.createReadStream(params.filePath, { encoding: "utf-8" }); @@ -170,7 +170,7 @@ async function scanUsageFile(params: { export async function loadCostUsageSummary(params?: { days?: number; - config?: MoltbotConfig; + config?: OpenClawConfig; agentId?: string; }): Promise { const days = Math.max(1, Math.floor(params?.days ?? 30)); @@ -233,7 +233,7 @@ export async function loadSessionCostSummary(params: { sessionId?: string; sessionEntry?: SessionEntry; sessionFile?: string; - config?: MoltbotConfig; + config?: OpenClawConfig; }): Promise { const sessionFile = params.sessionFile ?? diff --git a/src/infra/shell-env.test.ts b/src/infra/shell-env.test.ts index 8c3d3f018b..3dc48b7713 100644 --- a/src/infra/shell-env.test.ts +++ b/src/infra/shell-env.test.ts @@ -9,16 +9,16 @@ import { describe("shell env fallback", () => { it("is disabled by default", () => { expect(shouldEnableShellEnvFallback({} as NodeJS.ProcessEnv)).toBe(false); - expect(shouldEnableShellEnvFallback({ CLAWDBOT_LOAD_SHELL_ENV: "0" })).toBe(false); - expect(shouldEnableShellEnvFallback({ CLAWDBOT_LOAD_SHELL_ENV: "1" })).toBe(true); + expect(shouldEnableShellEnvFallback({ OPENCLAW_LOAD_SHELL_ENV: "0" })).toBe(false); + expect(shouldEnableShellEnvFallback({ OPENCLAW_LOAD_SHELL_ENV: "1" })).toBe(true); }); it("resolves timeout from env with default fallback", () => { expect(resolveShellEnvFallbackTimeoutMs({} as NodeJS.ProcessEnv)).toBe(15000); - expect(resolveShellEnvFallbackTimeoutMs({ CLAWDBOT_SHELL_ENV_TIMEOUT_MS: "42" })).toBe(42); + expect(resolveShellEnvFallbackTimeoutMs({ OPENCLAW_SHELL_ENV_TIMEOUT_MS: "42" })).toBe(42); expect( resolveShellEnvFallbackTimeoutMs({ - CLAWDBOT_SHELL_ENV_TIMEOUT_MS: "nope", + OPENCLAW_SHELL_ENV_TIMEOUT_MS: "nope", }), ).toBe(15000); }); diff --git a/src/infra/shell-env.ts b/src/infra/shell-env.ts index 11c7759aa4..3998f2836b 100644 --- a/src/infra/shell-env.ts +++ b/src/infra/shell-env.ts @@ -74,7 +74,7 @@ export function loadShellEnvFallback(opts: ShellEnvFallbackOptions): ShellEnvFal }); } catch (err) { const msg = err instanceof Error ? err.message : String(err); - logger.warn(`[moltbot] shell env fallback failed: ${msg}`); + logger.warn(`[openclaw] shell env fallback failed: ${msg}`); lastAppliedKeys = []; return { ok: false, error: msg, applied: [] }; } @@ -95,15 +95,15 @@ export function loadShellEnvFallback(opts: ShellEnvFallbackOptions): ShellEnvFal } export function shouldEnableShellEnvFallback(env: NodeJS.ProcessEnv): boolean { - return isTruthyEnvValue(env.CLAWDBOT_LOAD_SHELL_ENV); + return isTruthyEnvValue(env.OPENCLAW_LOAD_SHELL_ENV); } export function shouldDeferShellEnvFallback(env: NodeJS.ProcessEnv): boolean { - return isTruthyEnvValue(env.CLAWDBOT_DEFER_SHELL_ENV_FALLBACK); + return isTruthyEnvValue(env.OPENCLAW_DEFER_SHELL_ENV_FALLBACK); } export function resolveShellEnvFallbackTimeoutMs(env: NodeJS.ProcessEnv): number { - const raw = env.CLAWDBOT_SHELL_ENV_TIMEOUT_MS?.trim(); + const raw = env.OPENCLAW_SHELL_ENV_TIMEOUT_MS?.trim(); if (!raw) return DEFAULT_TIMEOUT_MS; const parsed = Number.parseInt(raw, 10); if (!Number.isFinite(parsed)) return DEFAULT_TIMEOUT_MS; diff --git a/src/infra/skills-remote.ts b/src/infra/skills-remote.ts index 00329af6bb..0c43e5f6f6 100644 --- a/src/infra/skills-remote.ts +++ b/src/infra/skills-remote.ts @@ -1,7 +1,7 @@ import type { SkillEligibilityContext, SkillEntry } from "../agents/skills.js"; import { loadWorkspaceSkillEntries } from "../agents/skills.js"; import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { listNodePairing, updatePairedNodeMetadata } from "./node-pairing.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { bumpSkillsSnapshotVersion } from "../agents/skills/refresh.js"; @@ -156,7 +156,7 @@ export function recordRemoteNodeBins(nodeId: string, bins: string[]) { upsertNode({ nodeId, bins }); } -function listWorkspaceDirs(cfg: MoltbotConfig): string[] { +function listWorkspaceDirs(cfg: OpenClawConfig): string[] { const dirs = new Set(); const list = cfg.agents?.list; if (Array.isArray(list)) { @@ -227,7 +227,7 @@ export async function refreshRemoteNodeBins(params: { platform?: string; deviceFamily?: string; commands?: string[]; - cfg: MoltbotConfig; + cfg: OpenClawConfig; timeoutMs?: number; }) { if (!remoteRegistry) return; @@ -304,7 +304,7 @@ export function getRemoteSkillEligibility(): SkillEligibilityContext["remote"] | }; } -export async function refreshRemoteBinsForConnectedNodes(cfg: MoltbotConfig) { +export async function refreshRemoteBinsForConnectedNodes(cfg: OpenClawConfig) { if (!remoteRegistry) return; const connected = remoteRegistry.listConnected(); for (const node of connected) { diff --git a/src/infra/state-migrations.fs.test.ts b/src/infra/state-migrations.fs.test.ts index 95604ebe55..d9e6992477 100644 --- a/src/infra/state-migrations.fs.test.ts +++ b/src/infra/state-migrations.fs.test.ts @@ -7,7 +7,7 @@ import { readSessionStoreJson5 } from "./state-migrations.fs.js"; describe("state migrations fs", () => { it("treats array session stores as invalid", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-store-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-store-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, "[]", "utf-8"); diff --git a/src/infra/state-migrations.ts b/src/infra/state-migrations.ts index f5e50740ea..5a3f7751b6 100644 --- a/src/infra/state-migrations.ts +++ b/src/infra/state-migrations.ts @@ -3,9 +3,9 @@ import os from "node:os"; import path from "node:path"; import { resolveDefaultAgentId } from "../agents/agent-scope.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { - resolveLegacyStateDir, + resolveLegacyStateDirs, resolveNewStateDir, resolveOAuthDir, resolveStateDir, @@ -316,19 +316,25 @@ export async function autoMigrateLegacyStateDir(params: { autoMigrateStateDirChecked = true; const env = params.env ?? process.env; - if (env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim()) { + if (env.OPENCLAW_STATE_DIR?.trim()) { return { migrated: false, skipped: true, changes: [], warnings: [] }; } const homedir = params.homedir ?? os.homedir; - const legacyDir = resolveLegacyStateDir(homedir); const targetDir = resolveNewStateDir(homedir); + const legacyDir = resolveLegacyStateDirs(homedir).find((dir) => { + try { + return fs.existsSync(dir); + } catch { + return false; + } + }); const warnings: string[] = []; const changes: string[] = []; let legacyStat: fs.Stats | null = null; try { - legacyStat = fs.lstatSync(legacyDir); + legacyStat = legacyDir ? fs.lstatSync(legacyDir) : null; } catch { legacyStat = null; } @@ -341,12 +347,12 @@ export async function autoMigrateLegacyStateDir(params: { } if (legacyStat.isSymbolicLink()) { - const legacyTarget = resolveSymlinkTarget(legacyDir); + const legacyTarget = legacyDir ? resolveSymlinkTarget(legacyDir) : null; if (legacyTarget && path.resolve(legacyTarget) === path.resolve(targetDir)) { return { migrated: false, skipped: false, changes, warnings }; } warnings.push( - `Legacy state dir is a symlink (${legacyDir} → ${legacyTarget ?? "unknown"}); skipping auto-migration.`, + `Legacy state dir is a symlink (${legacyDir ?? "unknown"} → ${legacyTarget ?? "unknown"}); skipping auto-migration.`, ); return { migrated: false, skipped: false, changes, warnings }; } @@ -359,18 +365,23 @@ export async function autoMigrateLegacyStateDir(params: { } try { + if (!legacyDir) throw new Error("Legacy state dir not found"); fs.renameSync(legacyDir, targetDir); } catch (err) { - warnings.push(`Failed to move legacy state dir (${legacyDir} → ${targetDir}): ${String(err)}`); + warnings.push( + `Failed to move legacy state dir (${legacyDir ?? "unknown"} → ${targetDir}): ${String(err)}`, + ); return { migrated: false, skipped: false, changes, warnings }; } try { + if (!legacyDir) throw new Error("Legacy state dir not found"); fs.symlinkSync(targetDir, legacyDir, "dir"); changes.push(formatStateDirMigration(legacyDir, targetDir)); } catch (err) { try { if (process.platform === "win32") { + if (!legacyDir) throw new Error("Legacy state dir not found"); fs.symlinkSync(targetDir, legacyDir, "junction"); changes.push(formatStateDirMigration(legacyDir, targetDir)); } else { @@ -378,6 +389,7 @@ export async function autoMigrateLegacyStateDir(params: { } } catch (fallbackErr) { try { + if (!legacyDir) throw new Error("Legacy state dir not found"); fs.renameSync(targetDir, legacyDir); warnings.push( `State dir migration rolled back (failed to link legacy path): ${String(fallbackErr)}`, @@ -385,12 +397,12 @@ export async function autoMigrateLegacyStateDir(params: { return { migrated: false, skipped: false, changes: [], warnings }; } catch (rollbackErr) { warnings.push( - `State dir moved but failed to link legacy path (${legacyDir} → ${targetDir}): ${String(fallbackErr)}`, + `State dir moved but failed to link legacy path (${legacyDir ?? "unknown"} → ${targetDir}): ${String(fallbackErr)}`, ); warnings.push( - `Rollback failed; set MOLTBOT_STATE_DIR=${targetDir} to avoid split state: ${String(rollbackErr)}`, + `Rollback failed; set OPENCLAW_STATE_DIR=${targetDir} to avoid split state: ${String(rollbackErr)}`, ); - changes.push(`State dir: ${legacyDir} → ${targetDir}`); + changes.push(`State dir: ${legacyDir ?? "unknown"} → ${targetDir}`); } } } @@ -399,7 +411,7 @@ export async function autoMigrateLegacyStateDir(params: { } export async function detectLegacyStateMigrations(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env?: NodeJS.ProcessEnv; homedir?: () => string; }): Promise { @@ -690,7 +702,7 @@ export async function runLegacyStateMigrations(params: { } export async function autoMigrateLegacyAgentDir(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env?: NodeJS.ProcessEnv; homedir?: () => string; log?: MigrationLogger; @@ -705,7 +717,7 @@ export async function autoMigrateLegacyAgentDir(params: { } export async function autoMigrateLegacyState(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env?: NodeJS.ProcessEnv; homedir?: () => string; log?: MigrationLogger; @@ -727,7 +739,7 @@ export async function autoMigrateLegacyState(params: { homedir: params.homedir, log: params.log, }); - if (env.CLAWDBOT_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim()) { + if (env.OPENCLAW_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim()) { return { migrated: stateDirResult.migrated, skipped: true, diff --git a/src/infra/system-events.test.ts b/src/infra/system-events.test.ts index dc5cea2505..eb394a87fe 100644 --- a/src/infra/system-events.test.ts +++ b/src/infra/system-events.test.ts @@ -1,11 +1,11 @@ import { beforeEach, describe, expect, it } from "vitest"; import { prependSystemEvents } from "../auto-reply/reply/session-updates.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveMainSessionKey } from "../config/sessions.js"; import { enqueueSystemEvent, peekSystemEvents, resetSystemEventsForTest } from "./system-events.js"; -const cfg = {} as unknown as MoltbotConfig; +const cfg = {} as unknown as OpenClawConfig; const mainKey = resolveMainSessionKey(cfg); describe("system events (session routing)", () => { diff --git a/src/infra/system-presence.test.ts b/src/infra/system-presence.test.ts index 16e03a06ab..982c7d6112 100644 --- a/src/infra/system-presence.test.ts +++ b/src/infra/system-presence.test.ts @@ -8,7 +8,7 @@ describe("system-presence", () => { const instanceIdLower = instanceIdUpper.toLowerCase(); upsertPresence(instanceIdUpper, { - host: "moltbot", + host: "openclaw", mode: "ui", instanceId: instanceIdUpper, reason: "connect", @@ -39,7 +39,7 @@ describe("system-presence", () => { upsertPresence(deviceId, { deviceId, - host: "moltbot", + host: "openclaw", roles: ["operator"], scopes: ["operator.admin"], reason: "connect", diff --git a/src/infra/system-presence.ts b/src/infra/system-presence.ts index 0e5d453ace..0c9cb74cfb 100644 --- a/src/infra/system-presence.ts +++ b/src/infra/system-presence.ts @@ -59,7 +59,7 @@ function resolvePrimaryIPv4(): string | undefined { function initSelfPresence() { const host = os.hostname(); const ip = resolvePrimaryIPv4() ?? undefined; - const version = process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "unknown"; + const version = process.env.OPENCLAW_VERSION ?? process.env.npm_package_version ?? "unknown"; const modelIdentifier = (() => { const p = os.platform(); if (p === "darwin") { diff --git a/src/infra/tailscale.ts b/src/infra/tailscale.ts index 47df93a82a..abbb561faf 100644 --- a/src/infra/tailscale.ts +++ b/src/infra/tailscale.ts @@ -345,7 +345,7 @@ export async function ensureFunnel( runtime.error("Failed to enable Tailscale Funnel. Is it allowed on your tailnet?"); runtime.error( info( - `Tip: Funnel is optional for Moltbot. You can keep running the web gateway without it: \`${formatCliCommand("moltbot gateway")}\``, + `Tip: Funnel is optional for OpenClaw. You can keep running the web gateway without it: \`${formatCliCommand("openclaw gateway")}\``, ), ); if (shouldLogVerbose()) { diff --git a/src/infra/tls/gateway.ts b/src/infra/tls/gateway.ts index 8c9d7c640d..6163d0010a 100644 --- a/src/infra/tls/gateway.ts +++ b/src/infra/tls/gateway.ts @@ -56,7 +56,7 @@ async function generateSelfSignedCert(params: { "-out", params.certPath, "-subj", - "/CN=moltbot-gateway", + "/CN=openclaw-gateway", ]); await fs.chmod(params.keyPath, 0o600).catch(() => {}); await fs.chmod(params.certPath, 0o600).catch(() => {}); diff --git a/src/infra/unhandled-rejections.fatal-detection.test.ts b/src/infra/unhandled-rejections.fatal-detection.test.ts index 7944a1e734..e991c67c95 100644 --- a/src/infra/unhandled-rejections.fatal-detection.test.ts +++ b/src/infra/unhandled-rejections.fatal-detection.test.ts @@ -47,7 +47,7 @@ describe("installUnhandledRejectionHandler - fatal detection", () => { expect(exitCalls).toEqual([1]); expect(consoleErrorSpy).toHaveBeenCalledWith( - "[moltbot] FATAL unhandled rejection:", + "[openclaw] FATAL unhandled rejection:", expect.stringContaining("Out of memory"), ); }); @@ -83,7 +83,7 @@ describe("installUnhandledRejectionHandler - fatal detection", () => { expect(exitCalls).toEqual([1]); expect(consoleErrorSpy).toHaveBeenCalledWith( - "[moltbot] CONFIGURATION ERROR - requires fix:", + "[openclaw] CONFIGURATION ERROR - requires fix:", expect.stringContaining("Invalid config"), ); }); @@ -109,7 +109,7 @@ describe("installUnhandledRejectionHandler - fatal detection", () => { expect(exitCalls).toEqual([]); expect(consoleWarnSpy).toHaveBeenCalledWith( - "[moltbot] Non-fatal unhandled rejection (continuing):", + "[openclaw] Non-fatal unhandled rejection (continuing):", expect.stringContaining("fetch failed"), ); }); @@ -132,7 +132,7 @@ describe("installUnhandledRejectionHandler - fatal detection", () => { expect(exitCalls).toEqual([1]); expect(consoleErrorSpy).toHaveBeenCalledWith( - "[moltbot] Unhandled promise rejection:", + "[openclaw] Unhandled promise rejection:", expect.stringContaining("Something went wrong"), ); }); diff --git a/src/infra/unhandled-rejections.ts b/src/infra/unhandled-rejections.ts index d186c6a78b..4d2a48d232 100644 --- a/src/infra/unhandled-rejections.ts +++ b/src/infra/unhandled-rejections.ts @@ -115,7 +115,7 @@ export function isUnhandledRejectionHandled(reason: unknown): boolean { if (handler(reason)) return true; } catch (err) { console.error( - "[moltbot] Unhandled rejection handler failed:", + "[openclaw] Unhandled rejection handler failed:", err instanceof Error ? (err.stack ?? err.message) : err, ); } @@ -130,31 +130,31 @@ export function installUnhandledRejectionHandler(): void { // AbortError is typically an intentional cancellation (e.g., during shutdown) // Log it but don't crash - these are expected during graceful shutdown if (isAbortError(reason)) { - console.warn("[moltbot] Suppressed AbortError:", formatUncaughtError(reason)); + console.warn("[openclaw] Suppressed AbortError:", formatUncaughtError(reason)); return; } if (isFatalError(reason)) { - console.error("[moltbot] FATAL unhandled rejection:", formatUncaughtError(reason)); + console.error("[openclaw] FATAL unhandled rejection:", formatUncaughtError(reason)); process.exit(1); return; } if (isConfigError(reason)) { - console.error("[moltbot] CONFIGURATION ERROR - requires fix:", formatUncaughtError(reason)); + console.error("[openclaw] CONFIGURATION ERROR - requires fix:", formatUncaughtError(reason)); process.exit(1); return; } if (isTransientNetworkError(reason)) { console.warn( - "[moltbot] Non-fatal unhandled rejection (continuing):", + "[openclaw] Non-fatal unhandled rejection (continuing):", formatUncaughtError(reason), ); return; } - console.error("[moltbot] Unhandled promise rejection:", formatUncaughtError(reason)); + console.error("[openclaw] Unhandled promise rejection:", formatUncaughtError(reason)); process.exit(1); }); } diff --git a/src/infra/update-check.ts b/src/infra/update-check.ts index 8e10d412b6..e97215a548 100644 --- a/src/infra/update-check.ts +++ b/src/infra/update-check.ts @@ -303,7 +303,7 @@ export async function fetchNpmTagVersion(params: { const tag = params.tag; try { const res = await fetchWithTimeout( - `https://registry.npmjs.org/moltbot/${encodeURIComponent(tag)}`, + `https://registry.npmjs.org/openclaw/${encodeURIComponent(tag)}`, timeoutMs, ); if (!res.ok) { diff --git a/src/infra/update-global.ts b/src/infra/update-global.ts index 7050ad0eb4..312521901f 100644 --- a/src/infra/update-global.ts +++ b/src/infra/update-global.ts @@ -9,6 +9,9 @@ export type CommandRunner = ( options: { timeoutMs: number; cwd?: string; env?: NodeJS.ProcessEnv }, ) => Promise<{ stdout: string; stderr: string; code: number | null }>; +const PRIMARY_PACKAGE_NAME = "openclaw"; +const ALL_PACKAGE_NAMES = [PRIMARY_PACKAGE_NAME] as const; + async function pathExists(targetPath: string): Promise { try { await fs.access(targetPath); @@ -51,7 +54,7 @@ export async function resolveGlobalPackageRoot( ): Promise { const root = await resolveGlobalRoot(manager, runCommand, timeoutMs); if (!root) return null; - return path.join(root, "moltbot"); + return path.join(root, PRIMARY_PACKAGE_NAME); } export async function detectGlobalInstallManagerForRoot( @@ -75,14 +78,18 @@ export async function detectGlobalInstallManagerForRoot( const globalRoot = res.stdout.trim(); if (!globalRoot) continue; const globalReal = await tryRealpath(globalRoot); - const expected = path.join(globalReal, "moltbot"); - if (path.resolve(expected) === path.resolve(pkgReal)) return manager; + for (const name of ALL_PACKAGE_NAMES) { + const expected = path.join(globalReal, name); + if (path.resolve(expected) === path.resolve(pkgReal)) return manager; + } } const bunGlobalRoot = resolveBunGlobalRoot(); const bunGlobalReal = await tryRealpath(bunGlobalRoot); - const bunExpected = path.join(bunGlobalReal, "moltbot"); - if (path.resolve(bunExpected) === path.resolve(pkgReal)) return "bun"; + for (const name of ALL_PACKAGE_NAMES) { + const bunExpected = path.join(bunGlobalReal, name); + if (path.resolve(bunExpected) === path.resolve(pkgReal)) return "bun"; + } return null; } @@ -94,11 +101,15 @@ export async function detectGlobalInstallManagerByPresence( for (const manager of ["npm", "pnpm"] as const) { const root = await resolveGlobalRoot(manager, runCommand, timeoutMs); if (!root) continue; - if (await pathExists(path.join(root, "moltbot"))) return manager; + for (const name of ALL_PACKAGE_NAMES) { + if (await pathExists(path.join(root, name))) return manager; + } } const bunRoot = resolveBunGlobalRoot(); - if (await pathExists(path.join(bunRoot, "moltbot"))) return "bun"; + for (const name of ALL_PACKAGE_NAMES) { + if (await pathExists(path.join(bunRoot, name))) return "bun"; + } return null; } diff --git a/src/infra/update-runner.test.ts b/src/infra/update-runner.test.ts index 6a49a85c0f..918b0d3c8d 100644 --- a/src/infra/update-runner.test.ts +++ b/src/infra/update-runner.test.ts @@ -26,7 +26,7 @@ describe("runGatewayUpdate", () => { let tempDir: string; beforeEach(async () => { - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-")); + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-")); }); afterEach(async () => { @@ -37,7 +37,7 @@ describe("runGatewayUpdate", () => { await fs.mkdir(path.join(tempDir, ".git")); await fs.writeFile( path.join(tempDir, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0" }), "utf-8", ); const { runner, calls } = createRunner({ @@ -62,7 +62,7 @@ describe("runGatewayUpdate", () => { await fs.mkdir(path.join(tempDir, ".git")); await fs.writeFile( path.join(tempDir, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0" }), "utf-8", ); const { runner, calls } = createRunner({ @@ -95,7 +95,7 @@ describe("runGatewayUpdate", () => { await fs.mkdir(path.join(tempDir, ".git")); await fs.writeFile( path.join(tempDir, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0", packageManager: "pnpm@8.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0", packageManager: "pnpm@8.0.0" }), "utf-8", ); const stableTag = "v1.0.1-1"; @@ -113,7 +113,7 @@ describe("runGatewayUpdate", () => { "pnpm build": { stdout: "" }, "pnpm ui:build": { stdout: "" }, [`git -C ${tempDir} checkout -- dist/control-ui/`]: { stdout: "" }, - "pnpm moltbot doctor --non-interactive": { stdout: "" }, + "pnpm openclaw doctor --non-interactive": { stdout: "" }, }); const result = await runGatewayUpdate({ @@ -131,7 +131,7 @@ describe("runGatewayUpdate", () => { it("skips update when no git root", async () => { await fs.writeFile( path.join(tempDir, "package.json"), - JSON.stringify({ name: "moltbot", packageManager: "pnpm@8.0.0" }), + JSON.stringify({ name: "openclaw", packageManager: "pnpm@8.0.0" }), "utf-8", ); await fs.writeFile(path.join(tempDir, "pnpm-lock.yaml"), "", "utf-8"); @@ -155,11 +155,11 @@ describe("runGatewayUpdate", () => { it("updates global npm installs when detected", async () => { const nodeModules = path.join(tempDir, "node_modules"); - const pkgRoot = path.join(nodeModules, "moltbot"); + const pkgRoot = path.join(nodeModules, "openclaw"); await fs.mkdir(pkgRoot, { recursive: true }); await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0" }), "utf-8", ); @@ -173,10 +173,10 @@ describe("runGatewayUpdate", () => { if (key === "npm root -g") { return { stdout: nodeModules, stderr: "", code: 0 }; } - if (key === "npm i -g moltbot@latest") { + if (key === "npm i -g openclaw@latest") { await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "2.0.0" }), + JSON.stringify({ name: "openclaw", version: "2.0.0" }), "utf-8", ); return { stdout: "ok", stderr: "", code: 0 }; @@ -197,16 +197,16 @@ describe("runGatewayUpdate", () => { expect(result.mode).toBe("npm"); expect(result.before?.version).toBe("1.0.0"); expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "npm i -g moltbot@latest")).toBe(true); + expect(calls.some((call) => call === "npm i -g openclaw@latest")).toBe(true); }); it("updates global npm installs with tag override", async () => { const nodeModules = path.join(tempDir, "node_modules"); - const pkgRoot = path.join(nodeModules, "moltbot"); + const pkgRoot = path.join(nodeModules, "openclaw"); await fs.mkdir(pkgRoot, { recursive: true }); await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0" }), "utf-8", ); @@ -220,10 +220,10 @@ describe("runGatewayUpdate", () => { if (key === "npm root -g") { return { stdout: nodeModules, stderr: "", code: 0 }; } - if (key === "npm i -g moltbot@beta") { + if (key === "npm i -g openclaw@beta") { await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "2.0.0" }), + JSON.stringify({ name: "openclaw", version: "2.0.0" }), "utf-8", ); return { stdout: "ok", stderr: "", code: 0 }; @@ -245,7 +245,7 @@ describe("runGatewayUpdate", () => { expect(result.mode).toBe("npm"); expect(result.before?.version).toBe("1.0.0"); expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "npm i -g moltbot@beta")).toBe(true); + expect(calls.some((call) => call === "npm i -g openclaw@beta")).toBe(true); }); it("updates global bun installs when detected", async () => { @@ -255,11 +255,11 @@ describe("runGatewayUpdate", () => { try { const bunGlobalRoot = path.join(bunInstall, "install", "global", "node_modules"); - const pkgRoot = path.join(bunGlobalRoot, "moltbot"); + const pkgRoot = path.join(bunGlobalRoot, "openclaw"); await fs.mkdir(pkgRoot, { recursive: true }); await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "1.0.0" }), + JSON.stringify({ name: "openclaw", version: "1.0.0" }), "utf-8", ); @@ -276,10 +276,10 @@ describe("runGatewayUpdate", () => { if (key === "pnpm root -g") { return { stdout: "", stderr: "", code: 1 }; } - if (key === "bun add -g moltbot@latest") { + if (key === "bun add -g openclaw@latest") { await fs.writeFile( path.join(pkgRoot, "package.json"), - JSON.stringify({ name: "moltbot", version: "2.0.0" }), + JSON.stringify({ name: "openclaw", version: "2.0.0" }), "utf-8", ); return { stdout: "ok", stderr: "", code: 0 }; @@ -297,14 +297,14 @@ describe("runGatewayUpdate", () => { expect(result.mode).toBe("bun"); expect(result.before?.version).toBe("1.0.0"); expect(result.after?.version).toBe("2.0.0"); - expect(calls.some((call) => call === "bun add -g moltbot@latest")).toBe(true); + expect(calls.some((call) => call === "bun add -g openclaw@latest")).toBe(true); } finally { if (oldBunInstall === undefined) delete process.env.BUN_INSTALL; else process.env.BUN_INSTALL = oldBunInstall; } }); - it("rejects git roots that are not a moltbot checkout", async () => { + it("rejects git roots that are not a openclaw checkout", async () => { await fs.mkdir(path.join(tempDir, ".git")); const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(tempDir); const { runner, calls } = createRunner({ @@ -320,7 +320,7 @@ describe("runGatewayUpdate", () => { cwdSpy.mockRestore(); expect(result.status).toBe("error"); - expect(result.reason).toBe("not-moltbot-root"); + expect(result.reason).toBe("not-openclaw-root"); expect(calls.some((call) => call.includes("status --porcelain"))).toBe(false); }); }); diff --git a/src/infra/update-runner.ts b/src/infra/update-runner.ts index 0735edb394..5136d9f782 100644 --- a/src/infra/update-runner.ts +++ b/src/infra/update-runner.ts @@ -66,8 +66,8 @@ const DEFAULT_TIMEOUT_MS = 20 * 60_000; const MAX_LOG_CHARS = 8000; const PREFLIGHT_MAX_COMMITS = 10; const START_DIRS = ["cwd", "argv1", "process"]; -const DEFAULT_PACKAGE_NAME = "moltbot"; -const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "moltbot"]); +const DEFAULT_PACKAGE_NAME = "openclaw"; +const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME]); function normalizeDir(value?: string | null) { if (!value) return null; @@ -291,7 +291,7 @@ function managerInstallArgs(manager: "pnpm" | "bun" | "npm") { function normalizeTag(tag?: string) { const trimmed = tag?.trim(); if (!trimmed) return "latest"; - if (trimmed.startsWith("moltbot@")) return trimmed.slice("moltbot@".length); + if (trimmed.startsWith("openclaw@")) return trimmed.slice("openclaw@".length); if (trimmed.startsWith(`${DEFAULT_PACKAGE_NAME}@`)) { return trimmed.slice(`${DEFAULT_PACKAGE_NAME}@`.length); } @@ -347,7 +347,7 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise< status: "error", mode: "unknown", root: gitRoot, - reason: "not-moltbot-root", + reason: "not-openclaw-root", steps: [], durationMs: Date.now() - startedAt, }; @@ -502,7 +502,7 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise< } const manager = await detectPackageManager(gitRoot); - const preflightRoot = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-preflight-")); + const preflightRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-preflight-")); const worktreeDir = path.join(preflightRoot, "worktree"); const worktreeStep = await runStep( step( @@ -689,10 +689,10 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise< const doctorStep = await runStep( step( - "moltbot doctor", - managerScriptArgs(manager, "moltbot", ["doctor", "--non-interactive"]), + "openclaw doctor", + managerScriptArgs(manager, "openclaw", ["doctor", "--non-interactive"]), gitRoot, - { CLAWDBOT_UPDATE_IN_PROGRESS: "1" }, + { OPENCLAW_UPDATE_IN_PROGRESS: "1" }, ), ); steps.push(doctorStep); diff --git a/src/infra/update-startup.test.ts b/src/infra/update-startup.test.ts index 9a792b190d..85041f99bc 100644 --- a/src/infra/update-startup.test.ts +++ b/src/infra/update-startup.test.ts @@ -5,8 +5,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { UpdateCheckResult } from "./update-check.js"; -vi.mock("./moltbot-root.js", () => ({ - resolveMoltbotPackageRoot: vi.fn(), +vi.mock("./openclaw-root.js", () => ({ + resolveOpenClawPackageRoot: vi.fn(), })); vi.mock("./update-check.js", async () => { @@ -30,8 +30,8 @@ describe("update-startup", () => { beforeEach(async () => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-01-17T10:00:00Z")); - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-check-")); - process.env.CLAWDBOT_STATE_DIR = tempDir; + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-check-")); + process.env.OPENCLAW_STATE_DIR = tempDir; delete process.env.VITEST; process.env.NODE_ENV = "test"; }); @@ -43,13 +43,13 @@ describe("update-startup", () => { }); it("logs update hint for npm installs when newer tag exists", async () => { - const { resolveMoltbotPackageRoot } = await import("./moltbot-root.js"); + const { resolveOpenClawPackageRoot } = await import("./openclaw-root.js"); const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js"); const { runGatewayUpdateCheck } = await import("./update-startup.js"); - vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue("/opt/moltbot"); + vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw"); vi.mocked(checkUpdateStatus).mockResolvedValue({ - root: "/opt/moltbot", + root: "/opt/openclaw", installKind: "package", packageManager: "npm", } satisfies UpdateCheckResult); @@ -77,13 +77,13 @@ describe("update-startup", () => { }); it("uses latest when beta tag is older than release", async () => { - const { resolveMoltbotPackageRoot } = await import("./moltbot-root.js"); + const { resolveOpenClawPackageRoot } = await import("./openclaw-root.js"); const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js"); const { runGatewayUpdateCheck } = await import("./update-startup.js"); - vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue("/opt/moltbot"); + vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue("/opt/openclaw"); vi.mocked(checkUpdateStatus).mockResolvedValue({ - root: "/opt/moltbot", + root: "/opt/openclaw", installKind: "package", packageManager: "npm", } satisfies UpdateCheckResult); diff --git a/src/infra/update-startup.ts b/src/infra/update-startup.ts index 07fc0293f5..d3dbc58621 100644 --- a/src/infra/update-startup.ts +++ b/src/infra/update-startup.ts @@ -3,7 +3,7 @@ import path from "node:path"; import type { loadConfig } from "../config/config.js"; import { resolveStateDir } from "../config/paths.js"; -import { resolveMoltbotPackageRoot } from "./moltbot-root.js"; +import { resolveOpenClawPackageRoot } from "./openclaw-root.js"; import { compareSemverStrings, resolveNpmChannelTag, checkUpdateStatus } from "./update-check.js"; import { normalizeUpdateChannel, DEFAULT_PACKAGE_CHANNEL } from "./update-channels.js"; import { VERSION } from "../version.js"; @@ -57,7 +57,7 @@ export async function runGatewayUpdateCheck(params: { if (now - lastCheckedAt < UPDATE_CHECK_INTERVAL_MS) return; } - const root = await resolveMoltbotPackageRoot({ + const root = await resolveOpenClawPackageRoot({ moduleUrl: import.meta.url, argv1: process.argv[1], cwd: process.cwd(), @@ -93,7 +93,7 @@ export async function runGatewayUpdateCheck(params: { state.lastNotifiedVersion !== resolved.version || state.lastNotifiedTag !== tag; if (shouldNotify) { params.log.info( - `update available (${tag}): v${resolved.version} (current v${VERSION}). Run: ${formatCliCommand("moltbot update")}`, + `update available (${tag}): v${resolved.version} (current v${VERSION}). Run: ${formatCliCommand("openclaw update")}`, ); nextState.lastNotifiedVersion = resolved.version; nextState.lastNotifiedTag = tag; diff --git a/src/infra/voicewake.test.ts b/src/infra/voicewake.test.ts index 308a3dc9b7..ce3a110a47 100644 --- a/src/infra/voicewake.test.ts +++ b/src/infra/voicewake.test.ts @@ -12,14 +12,14 @@ import { describe("voicewake store", () => { it("returns defaults when missing", async () => { - const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-")); + const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-voicewake-")); const cfg = await loadVoiceWakeConfig(baseDir); expect(cfg.triggers).toEqual(defaultVoiceWakeTriggers()); expect(cfg.updatedAtMs).toBe(0); }); it("sanitizes and persists triggers", async () => { - const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-")); + const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-voicewake-")); const saved = await setVoiceWakeTriggers([" hi ", "", " there "], baseDir); expect(saved.triggers).toEqual(["hi", "there"]); expect(saved.updatedAtMs).toBeGreaterThan(0); @@ -30,7 +30,7 @@ describe("voicewake store", () => { }); it("falls back to defaults when triggers empty", async () => { - const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-")); + const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-voicewake-")); const saved = await setVoiceWakeTriggers(["", " "], baseDir); expect(saved.triggers).toEqual(defaultVoiceWakeTriggers()); }); diff --git a/src/infra/voicewake.ts b/src/infra/voicewake.ts index 204d7e3790..9d0867a0a0 100644 --- a/src/infra/voicewake.ts +++ b/src/infra/voicewake.ts @@ -8,7 +8,7 @@ export type VoiceWakeConfig = { updatedAtMs: number; }; -const DEFAULT_TRIGGERS = ["clawd", "claude", "computer"]; +const DEFAULT_TRIGGERS = ["openclaw", "claude", "computer"]; function resolvePath(baseDir?: string) { const root = baseDir ?? resolveStateDir(); diff --git a/src/infra/warnings.ts b/src/infra/warnings.ts index 5fe7a9955e..b4d82a56ee 100644 --- a/src/infra/warnings.ts +++ b/src/infra/warnings.ts @@ -1,4 +1,4 @@ -const warningFilterKey = Symbol.for("moltbot.warning-filter"); +const warningFilterKey = Symbol.for("openclaw.warning-filter"); type Warning = Error & { code?: string; diff --git a/src/infra/widearea-dns.test.ts b/src/infra/widearea-dns.test.ts index d702d8072b..820aa29c5d 100644 --- a/src/infra/widearea-dns.test.ts +++ b/src/infra/widearea-dns.test.ts @@ -1,37 +1,39 @@ import { describe, expect, it } from "vitest"; -import { renderWideAreaGatewayZoneText, WIDE_AREA_DISCOVERY_DOMAIN } from "./widearea-dns.js"; +import { renderWideAreaGatewayZoneText } from "./widearea-dns.js"; describe("wide-area DNS-SD zone rendering", () => { - it("renders a moltbot.internal zone with gateway PTR/SRV/TXT records", () => { + it("renders a zone with gateway PTR/SRV/TXT records", () => { const txt = renderWideAreaGatewayZoneText({ + domain: "openclaw.internal.", serial: 2025121701, gatewayPort: 18789, - displayName: "Mac Studio (Moltbot)", + displayName: "Mac Studio (OpenClaw)", tailnetIPv4: "100.123.224.76", tailnetIPv6: "fd7a:115c:a1e0::8801:e04c", hostLabel: "studio-london", instanceLabel: "studio-london", sshPort: 22, - cliPath: "/opt/homebrew/bin/moltbot", + cliPath: "/opt/homebrew/bin/openclaw", }); - expect(txt).toContain(`$ORIGIN ${WIDE_AREA_DISCOVERY_DOMAIN}`); + expect(txt).toContain(`$ORIGIN openclaw.internal.`); expect(txt).toContain(`studio-london IN A 100.123.224.76`); expect(txt).toContain(`studio-london IN AAAA fd7a:115c:a1e0::8801:e04c`); - expect(txt).toContain(`_moltbot-gw._tcp IN PTR studio-london._moltbot-gw._tcp`); - expect(txt).toContain(`studio-london._moltbot-gw._tcp IN SRV 0 0 18789 studio-london`); - expect(txt).toContain(`displayName=Mac Studio (Moltbot)`); + expect(txt).toContain(`_openclaw-gw._tcp IN PTR studio-london._openclaw-gw._tcp`); + expect(txt).toContain(`studio-london._openclaw-gw._tcp IN SRV 0 0 18789 studio-london`); + expect(txt).toContain(`displayName=Mac Studio (OpenClaw)`); expect(txt).toContain(`gatewayPort=18789`); expect(txt).toContain(`sshPort=22`); - expect(txt).toContain(`cliPath=/opt/homebrew/bin/moltbot`); + expect(txt).toContain(`cliPath=/opt/homebrew/bin/openclaw`); }); it("includes tailnetDns when provided", () => { const txt = renderWideAreaGatewayZoneText({ + domain: "openclaw.internal.", serial: 2025121701, gatewayPort: 18789, - displayName: "Mac Studio (Moltbot)", + displayName: "Mac Studio (OpenClaw)", tailnetIPv4: "100.123.224.76", tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net", hostLabel: "studio-london", diff --git a/src/infra/widearea-dns.ts b/src/infra/widearea-dns.ts index c796275dd3..01106b6844 100644 --- a/src/infra/widearea-dns.ts +++ b/src/infra/widearea-dns.ts @@ -4,11 +4,27 @@ import path from "node:path"; import { CONFIG_DIR, ensureDir } from "../utils.js"; -export const WIDE_AREA_DISCOVERY_DOMAIN = "moltbot.internal."; -export const WIDE_AREA_ZONE_FILENAME = "moltbot.internal.db"; +export function normalizeWideAreaDomain(raw?: string | null): string | null { + const trimmed = raw?.trim(); + if (!trimmed) return null; + return trimmed.endsWith(".") ? trimmed : `${trimmed}.`; +} -export function getWideAreaZonePath(): string { - return path.join(CONFIG_DIR, "dns", WIDE_AREA_ZONE_FILENAME); +export function resolveWideAreaDiscoveryDomain(params?: { + env?: NodeJS.ProcessEnv; + configDomain?: string | null; +}): string | null { + const env = params?.env ?? process.env; + const candidate = params?.configDomain ?? env.OPENCLAW_WIDE_AREA_DOMAIN ?? null; + return normalizeWideAreaDomain(candidate); +} + +function zoneFilenameForDomain(domain: string): string { + return `${domain.replace(/\.$/, "")}.db`; +} + +export function getWideAreaZonePath(domain: string): string { + return path.join(CONFIG_DIR, "dns", zoneFilenameForDomain(domain)); } function dnsLabel(raw: string, fallback: string): string { @@ -51,7 +67,7 @@ function extractSerial(zoneText: string): number | null { } function extractContentHash(zoneText: string): string | null { - const match = zoneText.match(/^\s*;\s*moltbot-content-hash:\s*(\S+)\s*$/m); + const match = zoneText.match(/^\s*;\s*openclaw-content-hash:\s*(\S+)\s*$/m); return match?.[1] ?? null; } @@ -66,6 +82,7 @@ function computeContentHash(body: string): string { } export type WideAreaGatewayZoneOpts = { + domain: string; gatewayPort: number; displayName: string; tailnetIPv4: string; @@ -80,9 +97,10 @@ export type WideAreaGatewayZoneOpts = { }; function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string { - const hostname = os.hostname().split(".")[0] ?? "moltbot"; - const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "moltbot"); - const instanceLabel = dnsLabel(opts.instanceLabel ?? `${hostname}-gateway`, "moltbot-gw"); + const hostname = os.hostname().split(".")[0] ?? "openclaw"; + const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "openclaw"); + const instanceLabel = dnsLabel(opts.instanceLabel ?? `${hostname}-gateway`, "openclaw-gw"); + const domain = normalizeWideAreaDomain(opts.domain) ?? "local."; const txt = [ `displayName=${opts.displayName.trim() || hostname}`, @@ -108,7 +126,7 @@ function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string const records: string[] = []; - records.push(`$ORIGIN ${WIDE_AREA_DISCOVERY_DOMAIN}`); + records.push(`$ORIGIN ${domain}`); records.push(`$TTL 60`); const soaLine = `@ IN SOA ns1 hostmaster ${opts.serial} 7200 3600 1209600 60`; records.push(soaLine); @@ -119,9 +137,9 @@ function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string records.push(`${hostLabel} IN AAAA ${opts.tailnetIPv6}`); } - records.push(`_moltbot-gw._tcp IN PTR ${instanceLabel}._moltbot-gw._tcp`); - records.push(`${instanceLabel}._moltbot-gw._tcp IN SRV 0 0 ${opts.gatewayPort} ${hostLabel}`); - records.push(`${instanceLabel}._moltbot-gw._tcp IN TXT ${txt.map(txtQuote).join(" ")}`); + records.push(`_openclaw-gw._tcp IN PTR ${instanceLabel}._openclaw-gw._tcp`); + records.push(`${instanceLabel}._openclaw-gw._tcp IN SRV 0 0 ${opts.gatewayPort} ${hostLabel}`); + records.push(`${instanceLabel}._openclaw-gw._tcp IN TXT ${txt.map(txtQuote).join(" ")}`); const contentBody = `${records.join("\n")}\n`; const hashBody = `${records @@ -131,7 +149,7 @@ function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string .join("\n")}\n`; const contentHash = computeContentHash(hashBody); - return `; moltbot-content-hash: ${contentHash}\n${contentBody}`; + return `; openclaw-content-hash: ${contentHash}\n${contentBody}`; } export function renderWideAreaGatewayZoneText( @@ -143,7 +161,11 @@ export function renderWideAreaGatewayZoneText( export async function writeWideAreaGatewayZone( opts: WideAreaGatewayZoneOpts, ): Promise<{ zonePath: string; changed: boolean }> { - const zonePath = getWideAreaZonePath(); + const domain = normalizeWideAreaDomain(opts.domain); + if (!domain) { + throw new Error("wide-area discovery domain is required"); + } + const zonePath = getWideAreaZonePath(domain); await ensureDir(path.dirname(zonePath)); const existing = (() => { diff --git a/src/line/accounts.test.ts b/src/line/accounts.test.ts index 4b2188d690..a4658d29d2 100644 --- a/src/line/accounts.test.ts +++ b/src/line/accounts.test.ts @@ -6,7 +6,7 @@ import { normalizeAccountId, DEFAULT_ACCOUNT_ID, } from "./accounts.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; describe("LINE accounts", () => { const originalEnv = { ...process.env }; @@ -23,7 +23,7 @@ describe("LINE accounts", () => { describe("resolveLineAccount", () => { it("resolves account from config", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { enabled: true, @@ -48,7 +48,7 @@ describe("LINE accounts", () => { process.env.LINE_CHANNEL_ACCESS_TOKEN = "env-token"; process.env.LINE_CHANNEL_SECRET = "env-secret"; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { enabled: true, @@ -64,7 +64,7 @@ describe("LINE accounts", () => { }); it("resolves named account", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { enabled: true, @@ -90,7 +90,7 @@ describe("LINE accounts", () => { }); it("returns empty token when not configured", () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const account = resolveLineAccount({ cfg }); @@ -102,7 +102,7 @@ describe("LINE accounts", () => { describe("listLineAccountIds", () => { it("returns default account when configured at base level", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { channelAccessToken: "test-token", @@ -116,7 +116,7 @@ describe("LINE accounts", () => { }); it("returns named accounts", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { accounts: { @@ -135,7 +135,7 @@ describe("LINE accounts", () => { it("returns default from env", () => { process.env.LINE_CHANNEL_ACCESS_TOKEN = "env-token"; - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const ids = listLineAccountIds(cfg); @@ -145,7 +145,7 @@ describe("LINE accounts", () => { describe("resolveDefaultLineAccountId", () => { it("returns default when configured", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { channelAccessToken: "test-token", @@ -159,7 +159,7 @@ describe("LINE accounts", () => { }); it("returns first named account when default not configured", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { line: { accounts: { diff --git a/src/line/accounts.ts b/src/line/accounts.ts index dc08a2695a..6ec2a1cfd7 100644 --- a/src/line/accounts.ts +++ b/src/line/accounts.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { LineConfig, LineAccountConfig, @@ -95,7 +95,7 @@ function resolveSecret(params: { } export function resolveLineAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string; }): ResolvedLineAccount { const { cfg, accountId = DEFAULT_ACCOUNT_ID } = params; @@ -138,7 +138,7 @@ export function resolveLineAccount(params: { }; } -export function listLineAccountIds(cfg: MoltbotConfig): string[] { +export function listLineAccountIds(cfg: OpenClawConfig): string[] { const lineConfig = cfg.channels?.line as LineConfig | undefined; const accounts = lineConfig?.accounts; const ids = new Set(); @@ -162,7 +162,7 @@ export function listLineAccountIds(cfg: MoltbotConfig): string[] { return Array.from(ids); } -export function resolveDefaultLineAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultLineAccountId(cfg: OpenClawConfig): string { const ids = listLineAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) { return DEFAULT_ACCOUNT_ID; diff --git a/src/line/bot-handlers.ts b/src/line/bot-handlers.ts index 912cc315c2..e3f1eaa48a 100644 --- a/src/line/bot-handlers.ts +++ b/src/line/bot-handlers.ts @@ -8,7 +8,7 @@ import type { PostbackEvent, EventSource, } from "@line/bot-sdk"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { danger, logVerbose } from "../globals.js"; import { resolvePairingIdLabel } from "../pairing/pairing-labels.js"; import { buildPairingReply } from "../pairing/pairing-messages.js"; @@ -33,7 +33,7 @@ interface MediaRef { } export interface LineHandlerContext { - cfg: MoltbotConfig; + cfg: OpenClawConfig; account: ResolvedLineAccount; runtime: RuntimeEnv; mediaMaxBytes: number; diff --git a/src/line/bot-message-context.test.ts b/src/line/bot-message-context.test.ts index 01cd0035ba..2960cc081e 100644 --- a/src/line/bot-message-context.test.ts +++ b/src/line/bot-message-context.test.ts @@ -3,14 +3,14 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import type { MessageEvent, PostbackEvent } from "@line/bot-sdk"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { ResolvedLineAccount } from "./types.js"; import { buildLineMessageContext, buildLinePostbackContext } from "./bot-message-context.js"; describe("buildLineMessageContext", () => { let tmpDir: string; let storePath: string; - let cfg: MoltbotConfig; + let cfg: OpenClawConfig; const account: ResolvedLineAccount = { accountId: "default", enabled: true, @@ -21,7 +21,7 @@ describe("buildLineMessageContext", () => { }; beforeEach(async () => { - tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-line-context-")); + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-line-context-")); storePath = path.join(tmpDir, "sessions.json"); cfg = { session: { store: storePath } }; }); diff --git a/src/line/bot-message-context.ts b/src/line/bot-message-context.ts index eb483ea948..8a1c049d29 100644 --- a/src/line/bot-message-context.ts +++ b/src/line/bot-message-context.ts @@ -9,7 +9,7 @@ import type { import { formatInboundEnvelope, resolveEnvelopeFormatOptions } from "../auto-reply/envelope.js"; import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js"; import { formatLocationText, toLocationContext } from "../channels/location.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { readSessionUpdatedAt, recordSessionMetaFromInbound, @@ -29,7 +29,7 @@ interface MediaRef { interface BuildLineMessageContextParams { event: MessageEvent; allMedia: MediaRef[]; - cfg: MoltbotConfig; + cfg: OpenClawConfig; account: ResolvedLineAccount; } @@ -315,7 +315,7 @@ export async function buildLineMessageContext(params: BuildLineMessageContextPar export async function buildLinePostbackContext(params: { event: PostbackEvent; - cfg: MoltbotConfig; + cfg: OpenClawConfig; account: ResolvedLineAccount; }) { const { event, cfg, account } = params; diff --git a/src/line/bot.ts b/src/line/bot.ts index a22604932b..b14eecb23f 100644 --- a/src/line/bot.ts +++ b/src/line/bot.ts @@ -1,5 +1,5 @@ import type { WebhookRequestBody } from "@line/bot-sdk"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { logVerbose } from "../globals.js"; import type { RuntimeEnv } from "../runtime.js"; @@ -14,7 +14,7 @@ export interface LineBotOptions { channelSecret: string; accountId?: string; runtime?: RuntimeEnv; - config?: MoltbotConfig; + config?: OpenClawConfig; mediaMaxMb?: number; onMessage?: (ctx: LineInboundContext) => Promise; } diff --git a/src/line/monitor.ts b/src/line/monitor.ts index 764dbf1301..f06fd693ec 100644 --- a/src/line/monitor.ts +++ b/src/line/monitor.ts @@ -1,6 +1,6 @@ import type { WebhookRequestBody } from "@line/bot-sdk"; import type { IncomingMessage, ServerResponse } from "node:http"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { danger, logVerbose } from "../globals.js"; import type { RuntimeEnv } from "../runtime.js"; import { createLineBot } from "./bot.js"; @@ -33,7 +33,7 @@ export interface MonitorLineProviderOptions { channelAccessToken: string; channelSecret: string; accountId?: string; - config: MoltbotConfig; + config: OpenClawConfig; runtime: RuntimeEnv; abortSignal?: AbortSignal; webhookUrl?: string; diff --git a/src/line/probe.test.ts b/src/line/probe.test.ts index e76715b7f5..688c754b1e 100644 --- a/src/line/probe.test.ts +++ b/src/line/probe.test.ts @@ -37,9 +37,9 @@ describe("probeLineBot", () => { it("returns bot info when available", async () => { getBotInfoMock.mockResolvedValue({ - displayName: "Moltbot", + displayName: "OpenClaw", userId: "U123", - basicId: "@moltbot", + basicId: "@openclaw", pictureUrl: "https://example.com/bot.png", }); diff --git a/src/link-understanding/apply.ts b/src/link-understanding/apply.ts index 1bc18a66df..17ab6c249c 100644 --- a/src/link-understanding/apply.ts +++ b/src/link-understanding/apply.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js"; import { formatLinkUnderstandingBody } from "./format.js"; @@ -11,7 +11,7 @@ export type ApplyLinkUnderstandingResult = { export async function applyLinkUnderstanding(params: { ctx: MsgContext; - cfg: MoltbotConfig; + cfg: OpenClawConfig; }): Promise { const result = await runLinkUnderstanding({ cfg: params.cfg, diff --git a/src/link-understanding/runner.ts b/src/link-understanding/runner.ts index bfd2e7286d..ff0a46b193 100644 --- a/src/link-understanding/runner.ts +++ b/src/link-understanding/runner.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { applyTemplate } from "../auto-reply/templating.js"; import type { LinkModelConfig, LinkToolsConfig } from "../config/types.tools.js"; @@ -99,7 +99,7 @@ async function runLinkEntries(params: { } export async function runLinkUnderstanding(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; ctx: MsgContext; message?: string; }): Promise { diff --git a/src/logger.test.ts b/src/logger.test.ts index 1853d42b92..96e4591383 100644 --- a/src/logger.test.ts +++ b/src/logger.test.ts @@ -71,10 +71,10 @@ describe("logger helpers", () => { resetLogger(); setLoggerOverride({}); // force defaults regardless of user config const today = localDateString(new Date()); - const todayPath = path.join(DEFAULT_LOG_DIR, `moltbot-${today}.log`); + const todayPath = path.join(DEFAULT_LOG_DIR, `openclaw-${today}.log`); // create an old file to be pruned - const oldPath = path.join(DEFAULT_LOG_DIR, "moltbot-2000-01-01.log"); + const oldPath = path.join(DEFAULT_LOG_DIR, "openclaw-2000-01-01.log"); fs.mkdirSync(DEFAULT_LOG_DIR, { recursive: true }); fs.writeFileSync(oldPath, "old"); fs.utimesSync(oldPath, new Date(0), new Date(0)); @@ -91,7 +91,7 @@ describe("logger helpers", () => { }); function pathForTest() { - const file = path.join(os.tmpdir(), `moltbot-log-${crypto.randomUUID()}.log`); + const file = path.join(os.tmpdir(), `openclaw-log-${crypto.randomUUID()}.log`); fs.mkdirSync(path.dirname(file), { recursive: true }); return file; } diff --git a/src/logging/config.ts b/src/logging/config.ts index 50e8f30d64..b85a8336fb 100644 --- a/src/logging/config.ts +++ b/src/logging/config.ts @@ -3,9 +3,9 @@ import fs from "node:fs"; import json5 from "json5"; import { resolveConfigPath } from "../config/paths.js"; -import type { MoltbotConfig } from "../config/types.js"; +import type { OpenClawConfig } from "../config/types.js"; -type LoggingConfig = MoltbotConfig["logging"]; +type LoggingConfig = OpenClawConfig["logging"]; export function readLoggingConfig(): LoggingConfig | undefined { const configPath = resolveConfigPath(); diff --git a/src/logging/console-capture.test.ts b/src/logging/console-capture.test.ts index 25add68b5d..c9581bd37b 100644 --- a/src/logging/console-capture.test.ts +++ b/src/logging/console-capture.test.ts @@ -126,7 +126,7 @@ describe("enableConsoleCapture", () => { }); function tempLogPath() { - return path.join(os.tmpdir(), `moltbot-log-${crypto.randomUUID()}.log`); + return path.join(os.tmpdir(), `openclaw-log-${crypto.randomUUID()}.log`); } function eioError() { diff --git a/src/logging/console.ts b/src/logging/console.ts index 0a12184949..9d64f49ab3 100644 --- a/src/logging/console.ts +++ b/src/logging/console.ts @@ -1,7 +1,7 @@ import { createRequire } from "node:module"; import util from "node:util"; -import type { MoltbotConfig } from "../config/types.js"; +import type { OpenClawConfig } from "../config/types.js"; import { isVerbose } from "../globals.js"; import { stripAnsi } from "../terminal/ansi.js"; import { type LogLevel, normalizeLogLevel } from "./levels.js"; @@ -32,7 +32,7 @@ function normalizeConsoleStyle(style?: string): ConsoleStyle { } function resolveConsoleSettings(): ConsoleSettings { - let cfg: MoltbotConfig["logging"] | undefined = + let cfg: OpenClawConfig["logging"] | undefined = (loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig(); if (!cfg) { if (loggingState.resolvingConsoleSettings) { @@ -41,7 +41,7 @@ function resolveConsoleSettings(): ConsoleSettings { loggingState.resolvingConsoleSettings = true; try { const loaded = requireConfig("../config/config.js") as { - loadConfig?: () => MoltbotConfig; + loadConfig?: () => OpenClawConfig; }; cfg = loaded.loadConfig?.().logging; } catch { diff --git a/src/logging/logger.ts b/src/logging/logger.ts index ae36a75e17..ef0dddcf53 100644 --- a/src/logging/logger.ts +++ b/src/logging/logger.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { Logger as TsLogger } from "tslog"; -import type { MoltbotConfig } from "../config/types.js"; +import type { OpenClawConfig } from "../config/types.js"; import type { ConsoleStyle } from "./console.js"; import { type LogLevel, levelToMinLevel, normalizeLogLevel } from "./levels.js"; import { readLoggingConfig } from "./config.js"; @@ -12,10 +12,10 @@ import { loggingState } from "./state.js"; // Pin to /tmp so mac Debug UI and docs match; os.tmpdir() can be a per-user // randomized path on macOS which made the “Open log” button a no-op. -export const DEFAULT_LOG_DIR = "/tmp/moltbot"; -export const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "moltbot.log"); // legacy single-file path +export const DEFAULT_LOG_DIR = "/tmp/openclaw"; +export const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "openclaw.log"); // legacy single-file path -const LOG_PREFIX = "moltbot"; +const LOG_PREFIX = "openclaw"; const LOG_SUFFIX = ".log"; const MAX_LOG_AGE_MS = 24 * 60 * 60 * 1000; // 24h @@ -52,12 +52,12 @@ function attachExternalTransport(logger: TsLogger, transport: LogTranspo } function resolveSettings(): ResolvedSettings { - let cfg: MoltbotConfig["logging"] | undefined = + let cfg: OpenClawConfig["logging"] | undefined = (loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig(); if (!cfg) { try { const loaded = requireConfig("../config/config.js") as { - loadConfig?: () => MoltbotConfig; + loadConfig?: () => OpenClawConfig; }; cfg = loaded.loadConfig?.().logging; } catch { @@ -88,7 +88,7 @@ function buildLogger(settings: ResolvedSettings): TsLogger { pruneOldRollingLogs(path.dirname(settings.file)); } const logger = new TsLogger({ - name: "moltbot", + name: "openclaw", minLevel: levelToMinLevel(settings.level), type: "hidden", // no ansi formatting }); diff --git a/src/logging/redact.ts b/src/logging/redact.ts index f2be8339ec..c3926d8681 100644 --- a/src/logging/redact.ts +++ b/src/logging/redact.ts @@ -1,6 +1,6 @@ import { createRequire } from "node:module"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; const requireConfig = createRequire(import.meta.url); @@ -97,10 +97,10 @@ function redactText(text: string, patterns: RegExp[]): string { } function resolveConfigRedaction(): RedactOptions { - let cfg: MoltbotConfig["logging"] | undefined; + let cfg: OpenClawConfig["logging"] | undefined; try { const loaded = requireConfig("../config/config.js") as { - loadConfig?: () => MoltbotConfig; + loadConfig?: () => OpenClawConfig; }; cfg = loaded.loadConfig?.().logging; } catch { diff --git a/src/macos/gateway-daemon.ts b/src/macos/gateway-daemon.ts index 686f705c2c..44bec8d8fe 100644 --- a/src/macos/gateway-daemon.ts +++ b/src/macos/gateway-daemon.ts @@ -2,11 +2,11 @@ import process from "node:process"; import type { GatewayLockHandle } from "../infra/gateway-lock.js"; -declare const __CLAWDBOT_VERSION__: string; +declare const __OPENCLAW_VERSION__: string | undefined; const BUNDLED_VERSION = - (typeof __CLAWDBOT_VERSION__ === "string" && __CLAWDBOT_VERSION__) || - process.env.CLAWDBOT_BUNDLED_VERSION || + (typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) || + process.env.OPENCLAW_BUNDLED_VERSION || "0.0.0"; function argValue(args: string[], flag: string): string | undefined { @@ -26,7 +26,7 @@ type GatewayWsLogStyle = "auto" | "full" | "compact"; async function main() { if (hasFlag(args, "--version") || hasFlag(args, "-v")) { - // Match `moltbot --version` behavior for Swift env/version checks. + // Match `openclaw --version` behavior for Swift env/version checks. // Keep output a single line. console.log(BUNDLED_VERSION); process.exit(0); @@ -75,6 +75,7 @@ async function main() { const cfg = loadConfig(); const portRaw = argValue(args, "--port") ?? + process.env.OPENCLAW_GATEWAY_PORT ?? process.env.CLAWDBOT_GATEWAY_PORT ?? (typeof cfg.gateway?.port === "number" ? String(cfg.gateway.port) : "") ?? "18789"; @@ -86,6 +87,7 @@ async function main() { const bindRaw = argValue(args, "--bind") ?? + process.env.OPENCLAW_GATEWAY_BIND ?? process.env.CLAWDBOT_GATEWAY_BIND ?? cfg.gateway?.bind ?? "loopback"; @@ -103,7 +105,9 @@ async function main() { } const token = argValue(args, "--token"); - if (token) process.env.CLAWDBOT_GATEWAY_TOKEN = token; + if (token) { + process.env.OPENCLAW_GATEWAY_TOKEN = token; + } let server: Awaited> | null = null; let lock: GatewayLockHandle | null = null; @@ -211,7 +215,7 @@ async function main() { void main().catch((err) => { console.error( - "[moltbot] Gateway daemon failed:", + "[openclaw] Gateway daemon failed:", err instanceof Error ? (err.stack ?? err.message) : err, ); process.exit(1); diff --git a/src/macos/relay-smoke.test.ts b/src/macos/relay-smoke.test.ts index 9d546a0534..bbd75c5719 100644 --- a/src/macos/relay-smoke.test.ts +++ b/src/macos/relay-smoke.test.ts @@ -15,8 +15,8 @@ describe("parseRelaySmokeTest", () => { }); it("parses env var smoke mode only when no args", () => { - expect(parseRelaySmokeTest([], { CLAWDBOT_SMOKE_QR: "1" })).toBe("qr"); - expect(parseRelaySmokeTest(["send"], { CLAWDBOT_SMOKE_QR: "1" })).toBe(null); + expect(parseRelaySmokeTest([], { OPENCLAW_SMOKE_QR: "1" })).toBe("qr"); + expect(parseRelaySmokeTest(["send"], { OPENCLAW_SMOKE_QR: "1" })).toBe(null); }); it("rejects unknown smoke values", () => { diff --git a/src/macos/relay-smoke.ts b/src/macos/relay-smoke.ts index 7d228cbf21..1c1f44090d 100644 --- a/src/macos/relay-smoke.ts +++ b/src/macos/relay-smoke.ts @@ -15,7 +15,7 @@ export function parseRelaySmokeTest(args: string[], env: NodeJS.ProcessEnv): Rel // Back-compat: only run env-based smoke mode when no CLI args are present, // to avoid surprising early-exit when users set env vars globally. - if (args.length === 0 && (env.CLAWDBOT_SMOKE_QR === "1" || env.CLAWDBOT_SMOKE === "qr")) { + if (args.length === 0 && (env.OPENCLAW_SMOKE_QR === "1" || env.OPENCLAW_SMOKE === "qr")) { return "qr"; } diff --git a/src/macos/relay.ts b/src/macos/relay.ts index ec580760b2..a171adc722 100644 --- a/src/macos/relay.ts +++ b/src/macos/relay.ts @@ -1,11 +1,11 @@ #!/usr/bin/env node import process from "node:process"; -declare const __CLAWDBOT_VERSION__: string | undefined; +declare const __OPENCLAW_VERSION__: string | undefined; const BUNDLED_VERSION = - (typeof __CLAWDBOT_VERSION__ === "string" && __CLAWDBOT_VERSION__) || - process.env.CLAWDBOT_BUNDLED_VERSION || + (typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) || + process.env.OPENCLAW_BUNDLED_VERSION || "0.0.0"; function hasFlag(args: string[], flag: string): boolean { @@ -47,8 +47,8 @@ async function main() { const { loadDotEnv } = await import("../infra/dotenv.js"); loadDotEnv({ quiet: true }); - const { ensureMoltbotCliOnPath } = await import("../infra/path-env.js"); - ensureMoltbotCliOnPath(); + const { ensureOpenClawCliOnPath } = await import("../infra/path-env.js"); + ensureOpenClawCliOnPath(); const { enableConsoleCapture } = await import("../logging.js"); enableConsoleCapture(); @@ -64,7 +64,7 @@ async function main() { installUnhandledRejectionHandler(); process.on("uncaughtException", (error) => { - console.error("[moltbot] Uncaught exception:", formatUncaughtError(error)); + console.error("[openclaw] Uncaught exception:", formatUncaughtError(error)); process.exit(1); }); @@ -72,6 +72,9 @@ async function main() { } void main().catch((err) => { - console.error("[moltbot] Relay failed:", err instanceof Error ? (err.stack ?? err.message) : err); + console.error( + "[openclaw] Relay failed:", + err instanceof Error ? (err.stack ?? err.message) : err, + ); process.exit(1); }); diff --git a/src/markdown/frontmatter.test.ts b/src/markdown/frontmatter.test.ts index d7c5d1a502..462fcb28f5 100644 --- a/src/markdown/frontmatter.test.ts +++ b/src/markdown/frontmatter.test.ts @@ -22,7 +22,7 @@ description: | name: session-memory metadata: { - "moltbot": + "openclaw": { "emoji": "disk", "events": ["command:new"], @@ -33,18 +33,18 @@ metadata: const result = parseFrontmatterBlock(content); expect(result.metadata).toBeDefined(); - const parsed = JSON5.parse(result.metadata ?? "") as { moltbot?: { emoji?: string } }; - expect(parsed.moltbot?.emoji).toBe("disk"); + const parsed = JSON5.parse(result.metadata ?? "") as { openclaw?: { emoji?: string } }; + expect(parsed.openclaw?.emoji).toBe("disk"); }); it("preserves inline JSON values", () => { const content = `--- name: inline-json -metadata: {"moltbot": {"events": ["test"]}} +metadata: {"openclaw": {"events": ["test"]}} --- `; const result = parseFrontmatterBlock(content); - expect(result.metadata).toBe('{"moltbot": {"events": ["test"]}}'); + expect(result.metadata).toBe('{"openclaw": {"events": ["test"]}}'); }); it("stringifies YAML objects and arrays", () => { @@ -56,7 +56,7 @@ tags: - alpha - beta metadata: - moltbot: + openclaw: events: - command:new --- @@ -65,8 +65,8 @@ metadata: expect(result.enabled).toBe("true"); expect(result.retries).toBe("3"); expect(JSON.parse(result.tags ?? "[]")).toEqual(["alpha", "beta"]); - const parsed = JSON5.parse(result.metadata ?? "") as { moltbot?: { events?: string[] } }; - expect(parsed.moltbot?.events).toEqual(["command:new"]); + const parsed = JSON5.parse(result.metadata ?? "") as { openclaw?: { events?: string[] } }; + expect(parsed.openclaw?.events).toEqual(["command:new"]); }); it("returns empty when frontmatter is missing", () => { diff --git a/src/media-understanding/apply.test.ts b/src/media-understanding/apply.test.ts index 7a4d681367..a1f470258e 100644 --- a/src/media-understanding/apply.test.ts +++ b/src/media-understanding/apply.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { resolveApiKeyForProvider } from "../agents/model-auth.js"; import { fetchRemoteMedia } from "../media/fetch.js"; @@ -49,7 +49,7 @@ describe("applyMediaUnderstanding", () => { it("sets Transcript and replaces Body when audio transcription succeeds", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPath = path.join(dir, "note.ogg"); await fs.writeFile(audioPath, Buffer.from([0, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8])); @@ -58,7 +58,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: audioPath, MediaType: "audio/ogg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -92,7 +92,7 @@ describe("applyMediaUnderstanding", () => { it("keeps caption for command parsing when audio has user text", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPath = path.join(dir, "note.ogg"); await fs.writeFile(audioPath, Buffer.from([0, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8])); @@ -101,7 +101,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: audioPath, MediaType: "audio/ogg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -140,7 +140,7 @@ describe("applyMediaUnderstanding", () => { MediaType: "audio/ogg", ChatType: "dm", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -174,7 +174,7 @@ describe("applyMediaUnderstanding", () => { it("skips audio transcription when attachment exceeds maxBytes", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPath = path.join(dir, "large.wav"); await fs.writeFile(audioPath, Buffer.from([0, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); @@ -184,7 +184,7 @@ describe("applyMediaUnderstanding", () => { MediaType: "audio/wav", }; const transcribeAudio = vi.fn(async () => ({ text: "should-not-run" })); - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -209,7 +209,7 @@ describe("applyMediaUnderstanding", () => { it("falls back to CLI model when provider fails", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPath = path.join(dir, "note.ogg"); await fs.writeFile(audioPath, Buffer.from([0, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8])); @@ -218,7 +218,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: audioPath, MediaType: "audio/ogg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -262,7 +262,7 @@ describe("applyMediaUnderstanding", () => { it("uses CLI image understanding and preserves caption for commands", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const imagePath = path.join(dir, "photo.jpg"); await fs.writeFile(imagePath, "image-bytes"); @@ -271,7 +271,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: imagePath, MediaType: "image/jpeg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { image: { @@ -309,7 +309,7 @@ describe("applyMediaUnderstanding", () => { it("uses shared media models list when capability config is missing", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const imagePath = path.join(dir, "shared.jpg"); await fs.writeFile(imagePath, "image-bytes"); @@ -318,7 +318,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: imagePath, MediaType: "image/jpeg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { models: [ @@ -350,7 +350,7 @@ describe("applyMediaUnderstanding", () => { it("uses active model when enabled and models are missing", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPath = path.join(dir, "fallback.ogg"); await fs.writeFile(audioPath, Buffer.from([0, 255, 0, 1, 2, 3, 4, 5, 6])); @@ -359,7 +359,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: audioPath, MediaType: "audio/ogg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -387,7 +387,7 @@ describe("applyMediaUnderstanding", () => { it("handles multiple audio attachments when attachment mode is all", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const audioPathA = path.join(dir, "note-a.ogg"); const audioPathB = path.join(dir, "note-b.ogg"); await fs.writeFile(audioPathA, Buffer.from([200, 201, 202, 203, 204, 205, 206, 207, 208])); @@ -398,7 +398,7 @@ describe("applyMediaUnderstanding", () => { MediaPaths: [audioPathA, audioPathB], MediaTypes: ["audio/ogg", "audio/ogg"], }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { @@ -430,7 +430,7 @@ describe("applyMediaUnderstanding", () => { it("orders mixed media outputs as image, audio, video", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const imagePath = path.join(dir, "photo.jpg"); const audioPath = path.join(dir, "note.ogg"); const videoPath = path.join(dir, "clip.mp4"); @@ -443,7 +443,7 @@ describe("applyMediaUnderstanding", () => { MediaPaths: [imagePath, audioPath, videoPath], MediaTypes: ["image/jpeg", "audio/ogg", "video/mp4"], }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { image: { enabled: true, models: [{ provider: "openai", model: "gpt-5.2" }] }, @@ -490,7 +490,7 @@ describe("applyMediaUnderstanding", () => { it("treats text-like audio attachments as CSV (comma wins over tabs)", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const csvPath = path.join(dir, "data.mp3"); const csvText = '"a","b"\t"c"\n"1","2"\t"3"'; const csvBuffer = Buffer.concat([Buffer.from([0xff, 0xfe]), Buffer.from(csvText, "utf16le")]); @@ -501,7 +501,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: csvPath, MediaType: "audio/mpeg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, @@ -520,7 +520,7 @@ describe("applyMediaUnderstanding", () => { it("infers TSV when tabs are present without commas", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const tsvPath = path.join(dir, "report.mp3"); const tsvText = "a\tb\tc\n1\t2\t3"; await fs.writeFile(tsvPath, tsvText); @@ -530,7 +530,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: tsvPath, MediaType: "audio/mpeg", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, @@ -549,7 +549,7 @@ describe("applyMediaUnderstanding", () => { it("escapes XML special characters in filenames to prevent injection", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); // Use & in filename — valid on all platforms (including Windows, which // forbids < and > in NTFS filenames) and still requires XML escaping. // Note: The sanitizeFilename in store.ts would strip most dangerous chars, @@ -562,7 +562,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: filePath, MediaType: "text/plain", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, @@ -583,7 +583,7 @@ describe("applyMediaUnderstanding", () => { it("normalizes MIME types to prevent attribute injection", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const filePath = path.join(dir, "data.txt"); await fs.writeFile(filePath, "test content"); @@ -593,7 +593,7 @@ describe("applyMediaUnderstanding", () => { // Attempt to inject via MIME type with quotes - normalization should strip this MediaType: 'text/plain" onclick="alert(1)', }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, @@ -615,7 +615,7 @@ describe("applyMediaUnderstanding", () => { it("handles path traversal attempts in filenames safely", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); // Even if a file somehow got a path-like name, it should be handled safely const filePath = path.join(dir, "normal.txt"); await fs.writeFile(filePath, "legitimate content"); @@ -625,7 +625,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: filePath, MediaType: "text/plain", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, @@ -646,7 +646,7 @@ describe("applyMediaUnderstanding", () => { it("handles files with non-ASCII Unicode filenames", async () => { const { applyMediaUnderstanding } = await loadApply(); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-")); const filePath = path.join(dir, "文档.txt"); await fs.writeFile(filePath, "中文内容"); @@ -655,7 +655,7 @@ describe("applyMediaUnderstanding", () => { MediaPath: filePath, MediaType: "text/plain", }; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: false }, diff --git a/src/media-understanding/apply.ts b/src/media-understanding/apply.ts index 7c2a18006a..f3f31f667b 100644 --- a/src/media-understanding/apply.ts +++ b/src/media-understanding/apply.ts @@ -1,6 +1,6 @@ import path from "node:path"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js"; import { logVerbose, shouldLogVerbose } from "../globals.js"; @@ -90,7 +90,7 @@ function xmlEscapeAttr(value: string): string { return value.replace(/[<>&"']/g, (char) => XML_ESCAPE_MAP[char] ?? char); } -function resolveFileLimits(cfg: MoltbotConfig) { +function resolveFileLimits(cfg: OpenClawConfig) { const files = cfg.gateway?.http?.endpoints?.responses?.files; return { allowUrl: files?.allowUrl ?? true, @@ -321,7 +321,7 @@ async function extractFileBlocks(params: { export async function applyMediaUnderstanding(params: { ctx: MsgContext; - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; providers?: Record; activeModel?: ActiveMediaModel; diff --git a/src/media-understanding/attachments.ts b/src/media-understanding/attachments.ts index fe9b1b7930..96ffef97a0 100644 --- a/src/media-understanding/attachments.ts +++ b/src/media-understanding/attachments.ts @@ -326,7 +326,7 @@ export class MediaAttachmentCache { timeoutMs: params.timeoutMs, }); const extension = path.extname(bufferResult.fileName || "") || ""; - const tmpPath = path.join(os.tmpdir(), `moltbot-media-${crypto.randomUUID()}${extension}`); + const tmpPath = path.join(os.tmpdir(), `openclaw-media-${crypto.randomUUID()}${extension}`); await fs.writeFile(tmpPath, bufferResult.buffer); entry.tempPath = tmpPath; entry.tempCleanup = async () => { diff --git a/src/media-understanding/providers/deepgram/audio.live.test.ts b/src/media-understanding/providers/deepgram/audio.live.test.ts index ad8bc020e6..140c949e86 100644 --- a/src/media-understanding/providers/deepgram/audio.live.test.ts +++ b/src/media-understanding/providers/deepgram/audio.live.test.ts @@ -12,7 +12,7 @@ const SAMPLE_URL = const LIVE = isTruthyEnvValue(process.env.DEEPGRAM_LIVE_TEST) || isTruthyEnvValue(process.env.LIVE) || - isTruthyEnvValue(process.env.CLAWDBOT_LIVE_TEST); + isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST); const describeLive = LIVE && DEEPGRAM_KEY ? describe : describe.skip; diff --git a/src/media-understanding/providers/image.ts b/src/media-understanding/providers/image.ts index 0f5ea1756d..d996c75834 100644 --- a/src/media-understanding/providers/image.ts +++ b/src/media-understanding/providers/image.ts @@ -3,7 +3,7 @@ import { complete } from "@mariozechner/pi-ai"; import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent"; import { getApiKeyForModel, requireApiKey } from "../../agents/model-auth.js"; -import { ensureMoltbotModelsJson } from "../../agents/models-config.js"; +import { ensureOpenClawModelsJson } from "../../agents/models-config.js"; import { minimaxUnderstandImage } from "../../agents/minimax-vlm.js"; import { coerceImageAssistantText } from "../../agents/tools/image-tool.helpers.js"; import type { ImageDescriptionRequest, ImageDescriptionResult } from "../types.js"; @@ -11,7 +11,7 @@ import type { ImageDescriptionRequest, ImageDescriptionResult } from "../types.j export async function describeImageWithModel( params: ImageDescriptionRequest, ): Promise { - await ensureMoltbotModelsJson(params.cfg, params.agentDir); + await ensureOpenClawModelsJson(params.cfg, params.agentDir); const authStorage = discoverAuthStorage(params.agentDir); const modelRegistry = discoverModels(authStorage, params.agentDir); const model = modelRegistry.find(params.provider, params.model) as Model | null; diff --git a/src/media-understanding/resolve.test.ts b/src/media-understanding/resolve.test.ts index d617d48ea9..d06a777f87 100644 --- a/src/media-understanding/resolve.test.ts +++ b/src/media-understanding/resolve.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveEntriesWithActiveFallback, resolveModelEntries } from "./resolve.js"; const providerRegistry = new Map([ @@ -10,7 +10,7 @@ const providerRegistry = new Map([ describe("resolveModelEntries", () => { it("uses provider capabilities for shared entries without explicit caps", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { models: [{ provider: "openai", model: "gpt-5.2" }], @@ -34,7 +34,7 @@ describe("resolveModelEntries", () => { }); it("keeps per-capability entries even without explicit caps", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { image: { @@ -54,7 +54,7 @@ describe("resolveModelEntries", () => { }); it("skips shared CLI entries without capabilities", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { models: [{ type: "cli", command: "gemini", args: ["--file", "{{MediaPath}}"] }], @@ -73,7 +73,7 @@ describe("resolveModelEntries", () => { describe("resolveEntriesWithActiveFallback", () => { it("uses active model when enabled and no models are configured", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: true }, @@ -93,7 +93,7 @@ describe("resolveEntriesWithActiveFallback", () => { }); it("ignores active model when configured entries exist", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { audio: { enabled: true, models: [{ provider: "openai", model: "whisper-1" }] }, @@ -113,7 +113,7 @@ describe("resolveEntriesWithActiveFallback", () => { }); it("skips active model when provider lacks capability", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { media: { video: { enabled: true }, diff --git a/src/media-understanding/resolve.ts b/src/media-understanding/resolve.ts index 97a355bbcf..f3f5d57182 100644 --- a/src/media-understanding/resolve.ts +++ b/src/media-understanding/resolve.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import type { MediaUnderstandingConfig, @@ -34,7 +34,7 @@ export function resolvePrompt( export function resolveMaxChars(params: { capability: MediaUnderstandingCapability; entry: MediaUnderstandingModelConfig; - cfg: MoltbotConfig; + cfg: OpenClawConfig; config?: MediaUnderstandingConfig; }): number | undefined { const { capability, entry, cfg } = params; @@ -47,7 +47,7 @@ export function resolveMaxChars(params: { export function resolveMaxBytes(params: { capability: MediaUnderstandingCapability; entry: MediaUnderstandingModelConfig; - cfg: MoltbotConfig; + cfg: OpenClawConfig; config?: MediaUnderstandingConfig; }): number { const configured = @@ -59,7 +59,7 @@ export function resolveMaxBytes(params: { } export function resolveCapabilityConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, capability: MediaUnderstandingCapability, ): MediaUnderstandingConfig | undefined { return cfg.tools?.media?.[capability]; @@ -89,7 +89,7 @@ function resolveEntryCapabilities(params: { } export function resolveModelEntries(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; capability: MediaUnderstandingCapability; config?: MediaUnderstandingConfig; providerRegistry: Map; @@ -126,7 +126,7 @@ export function resolveModelEntries(params: { .map(({ entry }) => entry); } -export function resolveConcurrency(cfg: MoltbotConfig): number { +export function resolveConcurrency(cfg: OpenClawConfig): number { const configured = cfg.tools?.media?.concurrency; if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) { return Math.floor(configured); @@ -135,7 +135,7 @@ export function resolveConcurrency(cfg: MoltbotConfig): number { } export function resolveEntriesWithActiveFallback(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; capability: MediaUnderstandingCapability; config?: MediaUnderstandingConfig; providerRegistry: Map; diff --git a/src/media-understanding/runner.auto-audio.test.ts b/src/media-understanding/runner.auto-audio.test.ts index 8ddda59e69..a28e7b73e5 100644 --- a/src/media-understanding/runner.auto-audio.test.ts +++ b/src/media-understanding/runner.auto-audio.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { buildProviderRegistry, @@ -17,7 +17,7 @@ describe("runCapability auto audio entries", () => { it("uses provider keys to auto-enable audio transcription", async () => { const originalPath = process.env.PATH; process.env.PATH = "/usr/bin:/bin"; - const tmpPath = path.join(os.tmpdir(), `moltbot-auto-audio-${Date.now()}.wav`); + const tmpPath = path.join(os.tmpdir(), `openclaw-auto-audio-${Date.now()}.wav`); await fs.writeFile(tmpPath, Buffer.from("RIFF")); const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" }; const media = normalizeMediaAttachments(ctx); @@ -44,7 +44,7 @@ describe("runCapability auto audio entries", () => { }, }, }, - } as unknown as MoltbotConfig; + } as unknown as OpenClawConfig; try { const result = await runCapability({ @@ -68,7 +68,7 @@ describe("runCapability auto audio entries", () => { it("skips auto audio when disabled", async () => { const originalPath = process.env.PATH; process.env.PATH = "/usr/bin:/bin"; - const tmpPath = path.join(os.tmpdir(), `moltbot-auto-audio-${Date.now()}.wav`); + const tmpPath = path.join(os.tmpdir(), `openclaw-auto-audio-${Date.now()}.wav`); await fs.writeFile(tmpPath, Buffer.from("RIFF")); const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" }; const media = normalizeMediaAttachments(ctx); @@ -98,7 +98,7 @@ describe("runCapability auto audio entries", () => { }, }, }, - } as unknown as MoltbotConfig; + } as unknown as OpenClawConfig; try { const result = await runCapability({ diff --git a/src/media-understanding/runner.deepgram.test.ts b/src/media-understanding/runner.deepgram.test.ts index f4b5983fce..460e808356 100644 --- a/src/media-understanding/runner.deepgram.test.ts +++ b/src/media-understanding/runner.deepgram.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MsgContext } from "../auto-reply/templating.js"; import { buildProviderRegistry, @@ -15,7 +15,7 @@ import { describe("runCapability deepgram provider options", () => { it("merges provider options, headers, and baseUrl overrides", async () => { - const tmpPath = path.join(os.tmpdir(), `moltbot-deepgram-${Date.now()}.wav`); + const tmpPath = path.join(os.tmpdir(), `openclaw-deepgram-${Date.now()}.wav`); await fs.writeFile(tmpPath, Buffer.from("RIFF")); const ctx: MsgContext = { MediaPath: tmpPath, MediaType: "audio/wav" }; const media = normalizeMediaAttachments(ctx); @@ -80,7 +80,7 @@ describe("runCapability deepgram provider options", () => { }, }, }, - } as unknown as MoltbotConfig; + } as unknown as OpenClawConfig; try { const result = await runCapability({ diff --git a/src/media-understanding/runner.ts b/src/media-understanding/runner.ts index ffc6e4d64e..8fbfe5b047 100644 --- a/src/media-understanding/runner.ts +++ b/src/media-understanding/runner.ts @@ -3,7 +3,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { findModelInCatalog, loadModelCatalog, @@ -329,7 +329,7 @@ async function resolveGeminiCliEntry( } async function resolveKeyEntry(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; providerRegistry: ProviderRegistry; capability: MediaUnderstandingCapability; @@ -393,7 +393,7 @@ async function resolveKeyEntry(params: { } async function resolveAutoEntries(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; providerRegistry: ProviderRegistry; capability: MediaUnderstandingCapability; @@ -413,7 +413,7 @@ async function resolveAutoEntries(params: { } export async function resolveAutoImageModel(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; activeModel?: ActiveMediaModel; }): Promise { @@ -446,7 +446,7 @@ export async function resolveAutoImageModel(params: { } async function resolveActiveModelEntry(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; providerRegistry: ProviderRegistry; capability: MediaUnderstandingCapability; @@ -663,7 +663,7 @@ function formatDecisionSummary(decision: MediaUnderstandingDecision): string { async function runProviderEntry(params: { capability: MediaUnderstandingCapability; entry: MediaUnderstandingModelConfig; - cfg: MoltbotConfig; + cfg: OpenClawConfig; ctx: MsgContext; attachmentIndex: number; cache: MediaAttachmentCache; @@ -847,7 +847,7 @@ async function runProviderEntry(params: { async function runCliEntry(params: { capability: MediaUnderstandingCapability; entry: MediaUnderstandingModelConfig; - cfg: MoltbotConfig; + cfg: OpenClawConfig; ctx: MsgContext; attachmentIndex: number; cache: MediaAttachmentCache; @@ -877,7 +877,7 @@ async function runCliEntry(params: { maxBytes, timeoutMs, }); - const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-media-cli-")); + const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-media-cli-")); const mediaPath = pathResult.path; const outputBase = path.join(outputDir, path.parse(mediaPath).name); @@ -923,7 +923,7 @@ async function runCliEntry(params: { async function runAttachmentEntries(params: { capability: MediaUnderstandingCapability; - cfg: MoltbotConfig; + cfg: OpenClawConfig; ctx: MsgContext; attachmentIndex: number; agentDir?: string; @@ -1006,7 +1006,7 @@ async function runAttachmentEntries(params: { export async function runCapability(params: { capability: MediaUnderstandingCapability; - cfg: MoltbotConfig; + cfg: OpenClawConfig; ctx: MsgContext; attachments: MediaAttachmentCache; media: MediaAttachment[]; diff --git a/src/media-understanding/runner.vision-skip.test.ts b/src/media-understanding/runner.vision-skip.test.ts index bbc4e1edcc..0859cc1072 100644 --- a/src/media-understanding/runner.vision-skip.test.ts +++ b/src/media-understanding/runner.vision-skip.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; import type { MsgContext } from "../auto-reply/templating.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { buildProviderRegistry, createMediaAttachmentCache, @@ -33,7 +33,7 @@ describe("runCapability image skip", () => { const ctx: MsgContext = { MediaPath: "/tmp/image.png", MediaType: "image/png" }; const media = normalizeMediaAttachments(ctx); const cache = createMediaAttachmentCache(media); - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; try { const result = await runCapability({ diff --git a/src/media-understanding/types.ts b/src/media-understanding/types.ts index 2c8bccd2d6..252559a7a4 100644 --- a/src/media-understanding/types.ts +++ b/src/media-understanding/types.ts @@ -97,7 +97,7 @@ export type ImageDescriptionRequest = { profile?: string; preferredProfile?: string; agentDir: string; - cfg: import("../config/config.js").MoltbotConfig; + cfg: import("../config/config.js").OpenClawConfig; }; export type ImageDescriptionResult = { diff --git a/src/media/host.ts b/src/media/host.ts index 6c774ba741..f4a21ba04e 100644 --- a/src/media/host.ts +++ b/src/media/host.ts @@ -37,7 +37,7 @@ export async function ensureMediaHosted( if (needsServerStart && !opts.startServer) { await fs.rm(saved.path).catch(() => {}); throw new Error( - `Media hosting requires the webhook/Funnel server. Start \`${formatCliCommand("moltbot webhook")}\`/\`${formatCliCommand("moltbot up")}\` or re-run with --serve-media.`, + `Media hosting requires the webhook/Funnel server. Start \`${formatCliCommand("openclaw webhook")}\`/\`${formatCliCommand("openclaw up")}\` or re-run with --serve-media.`, ); } if (needsServerStart && opts.startServer) { diff --git a/src/media/image-ops.ts b/src/media/image-ops.ts index 9b07b69f44..821b3bc7a5 100644 --- a/src/media/image-ops.ts +++ b/src/media/image-ops.ts @@ -17,8 +17,8 @@ function isBun(): boolean { function prefersSips(): boolean { return ( - process.env.CLAWDBOT_IMAGE_BACKEND === "sips" || - (process.env.CLAWDBOT_IMAGE_BACKEND !== "sharp" && isBun() && process.platform === "darwin") + process.env.OPENCLAW_IMAGE_BACKEND === "sips" || + (process.env.OPENCLAW_IMAGE_BACKEND !== "sharp" && isBun() && process.platform === "darwin") ); } @@ -120,7 +120,7 @@ function readJpegExifOrientation(buffer: Buffer): number | null { } async function withTempDir(fn: (dir: string) => Promise): Promise { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-img-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-img-")); try { return await fn(dir); } finally { diff --git a/src/media/input-files.ts b/src/media/input-files.ts index 0adcfc076e..9cc9738c2f 100644 --- a/src/media/input-files.ts +++ b/src/media/input-files.ts @@ -165,7 +165,7 @@ export async function fetchWithGuard(params: { try { const response = await fetch(parsedUrl, { signal: controller.signal, - headers: { "User-Agent": "Moltbot-Gateway/1.0" }, + headers: { "User-Agent": "OpenClaw-Gateway/1.0" }, redirect: "manual", dispatcher, } as RequestInit & { dispatcher: Dispatcher }); diff --git a/src/media/store.header-ext.test.ts b/src/media/store.header-ext.test.ts index 23f033dba5..7cfa99e24e 100644 --- a/src/media/store.header-ext.test.ts +++ b/src/media/store.header-ext.test.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; const realOs = await vi.importActual("node:os"); -const HOME = path.join(realOs.tmpdir(), "moltbot-home-header-ext-test"); +const HOME = path.join(realOs.tmpdir(), "openclaw-home-header-ext-test"); vi.mock("node:os", () => ({ default: { homedir: () => HOME, tmpdir: () => realOs.tmpdir() }, diff --git a/src/media/store.redirect.test.ts b/src/media/store.redirect.test.ts index d33e773d05..0cab264e56 100644 --- a/src/media/store.redirect.test.ts +++ b/src/media/store.redirect.test.ts @@ -6,7 +6,7 @@ import JSZip from "jszip"; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const realOs = await vi.importActual("node:os"); -const HOME = path.join(realOs.tmpdir(), "moltbot-home-redirect"); +const HOME = path.join(realOs.tmpdir(), "openclaw-home-redirect"); const mockRequest = vi.fn(); vi.doMock("node:os", () => ({ diff --git a/src/media/store.test.ts b/src/media/store.test.ts index b2ecf56f23..852941bb25 100644 --- a/src/media/store.test.ts +++ b/src/media/store.test.ts @@ -13,7 +13,7 @@ describe("media store", () => { const envSnapshot: Record = {}; const snapshotEnv = () => { - for (const key of ["HOME", "USERPROFILE", "HOMEDRIVE", "HOMEPATH", "CLAWDBOT_STATE_DIR"]) { + for (const key of ["HOME", "USERPROFILE", "HOMEDRIVE", "HOMEPATH", "OPENCLAW_STATE_DIR"]) { envSnapshot[key] = process.env[key]; } }; @@ -27,10 +27,10 @@ describe("media store", () => { beforeAll(async () => { snapshotEnv(); - home = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-test-home-")); + home = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-home-")); process.env.HOME = home; process.env.USERPROFILE = home; - process.env.CLAWDBOT_STATE_DIR = path.join(home, ".clawdbot"); + process.env.OPENCLAW_STATE_DIR = path.join(home, ".openclaw"); if (process.platform === "win32") { const match = home.match(/^([A-Za-z]:)(.*)$/); if (match) { @@ -38,7 +38,7 @@ describe("media store", () => { process.env.HOMEPATH = match[2] || "\\"; } } - await fs.mkdir(path.join(home, ".clawdbot"), { recursive: true }); + await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); store = await import("./store.js"); }); @@ -61,7 +61,7 @@ describe("media store", () => { await withTempStore(async (store, home) => { const dir = await store.ensureMediaDir(); expect(isPathWithinBase(home, dir)).toBe(true); - expect(path.normalize(dir)).toContain(`${path.sep}.clawdbot${path.sep}media`); + expect(path.normalize(dir)).toContain(`${path.sep}.openclaw${path.sep}media`); const stat = await fs.stat(dir); expect(stat.isDirectory()).toBe(true); }); diff --git a/src/memory/batch-gemini.ts b/src/memory/batch-gemini.ts index 516b88fe7e..034bdda841 100644 --- a/src/memory/batch-gemini.ts +++ b/src/memory/batch-gemini.ts @@ -34,7 +34,7 @@ export type GeminiBatchOutputLine = { }; const GEMINI_BATCH_MAX_REQUESTS = 50000; -const debugEmbeddings = isTruthyEnvValue(process.env.CLAWDBOT_DEBUG_MEMORY_EMBEDDINGS); +const debugEmbeddings = isTruthyEnvValue(process.env.OPENCLAW_DEBUG_MEMORY_EMBEDDINGS); const log = createSubsystemLogger("memory/embeddings"); const debugLog = (message: string, meta?: Record) => { @@ -83,7 +83,7 @@ function buildGeminiUploadBody(params: { jsonl: string; displayName: string }): body: Blob; contentType: string; } { - const boundary = `moltbot-${hashText(params.displayName)}`; + const boundary = `openclaw-${hashText(params.displayName)}`; const jsonPart = JSON.stringify({ file: { displayName: params.displayName, diff --git a/src/memory/batch-openai.ts b/src/memory/batch-openai.ts index 0fa90b2359..e49716fe66 100644 --- a/src/memory/batch-openai.ts +++ b/src/memory/batch-openai.ts @@ -103,7 +103,7 @@ async function submitOpenAiBatch(params: { endpoint: OPENAI_BATCH_ENDPOINT, completion_window: OPENAI_BATCH_COMPLETION_WINDOW, metadata: { - source: "moltbot-memory", + source: "openclaw-memory", agent: params.agentId, }, }), diff --git a/src/memory/embeddings-gemini.ts b/src/memory/embeddings-gemini.ts index 244384df64..2a8ef1a7d3 100644 --- a/src/memory/embeddings-gemini.ts +++ b/src/memory/embeddings-gemini.ts @@ -12,7 +12,7 @@ export type GeminiEmbeddingClient = { const DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta"; export const DEFAULT_GEMINI_EMBEDDING_MODEL = "gemini-embedding-001"; -const debugEmbeddings = isTruthyEnvValue(process.env.CLAWDBOT_DEBUG_MEMORY_EMBEDDINGS); +const debugEmbeddings = isTruthyEnvValue(process.env.OPENCLAW_DEBUG_MEMORY_EMBEDDINGS); const log = createSubsystemLogger("memory/embeddings"); const debugLog = (message: string, meta?: Record) => { diff --git a/src/memory/embeddings.ts b/src/memory/embeddings.ts index 98de1ab42b..993fe81241 100644 --- a/src/memory/embeddings.ts +++ b/src/memory/embeddings.ts @@ -1,7 +1,7 @@ import fsSync from "node:fs"; import type { Llama, LlamaEmbeddingContext, LlamaModel } from "node-llama-cpp"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveUserPath } from "../utils.js"; import { createGeminiEmbeddingProvider, type GeminiEmbeddingClient } from "./embeddings-gemini.js"; import { createOpenAiEmbeddingProvider, type OpenAiEmbeddingClient } from "./embeddings-openai.js"; @@ -27,7 +27,7 @@ export type EmbeddingProviderResult = { }; export type EmbeddingProviderOptions = { - config: MoltbotConfig; + config: OpenClawConfig; agentDir?: string; provider: "openai" | "local" | "gemini" | "auto"; remote?: { @@ -216,7 +216,7 @@ function formatLocalSetupError(err: unknown): string { "To enable local embeddings:", "1) Use Node 22 LTS (recommended for installs/updates)", missing - ? "2) Reinstall Moltbot (this should install node-llama-cpp): npm i -g moltbot@latest" + ? "2) Reinstall OpenClaw (this should install node-llama-cpp): npm i -g openclaw@latest" : null, "3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp", 'Or set agents.defaults.memorySearch.provider = "openai" (remote).', diff --git a/src/memory/index.test.ts b/src/memory/index.test.ts index cccd1fa499..5768895993 100644 --- a/src/memory/index.test.ts +++ b/src/memory/index.test.ts @@ -43,7 +43,7 @@ describe("memory index", () => { beforeEach(async () => { embedBatchCalls = 0; failEmbeddings = false; - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); await fs.writeFile( diff --git a/src/memory/manager.async-search.test.ts b/src/memory/manager.async-search.test.ts index 4d5ac61ddd..3537ded05f 100644 --- a/src/memory/manager.async-search.test.ts +++ b/src/memory/manager.async-search.test.ts @@ -32,7 +32,7 @@ describe("memory search async sync", () => { let manager: MemoryIndexManager | null = null; beforeEach(async () => { - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-async-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-async-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); await fs.writeFile(path.join(workspaceDir, "memory", "2026-01-07.md"), "hello\n"); diff --git a/src/memory/manager.atomic-reindex.test.ts b/src/memory/manager.atomic-reindex.test.ts index 76147cb2bd..2fde5f5158 100644 --- a/src/memory/manager.atomic-reindex.test.ts +++ b/src/memory/manager.atomic-reindex.test.ts @@ -43,7 +43,7 @@ describe("memory manager atomic reindex", () => { beforeEach(async () => { shouldFail = false; - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "Hello memory."); diff --git a/src/memory/manager.batch.test.ts b/src/memory/manager.batch.test.ts index 31327cbc80..d7b8181b02 100644 --- a/src/memory/manager.batch.test.ts +++ b/src/memory/manager.batch.test.ts @@ -50,7 +50,7 @@ describe("memory indexing with OpenAI batches", () => { } return realSetTimeout(handler, delay, ...args); }) as typeof setTimeout); - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-batch-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-batch-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); }); diff --git a/src/memory/manager.embedding-batches.test.ts b/src/memory/manager.embedding-batches.test.ts index a7d4084245..b28ce84bd2 100644 --- a/src/memory/manager.embedding-batches.test.ts +++ b/src/memory/manager.embedding-batches.test.ts @@ -29,7 +29,7 @@ describe("memory embedding batches", () => { beforeEach(async () => { embedBatch.mockClear(); embedQuery.mockClear(); - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); }); diff --git a/src/memory/manager.sync-errors-do-not-crash.test.ts b/src/memory/manager.sync-errors-do-not-crash.test.ts index 7f7e3c270e..38c0859997 100644 --- a/src/memory/manager.sync-errors-do-not-crash.test.ts +++ b/src/memory/manager.sync-errors-do-not-crash.test.ts @@ -38,7 +38,7 @@ describe("memory manager sync failures", () => { beforeEach(async () => { vi.useFakeTimers(); - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "Hello"); diff --git a/src/memory/manager.ts b/src/memory/manager.ts index a799a5e0f3..aa3cb317db 100644 --- a/src/memory/manager.ts +++ b/src/memory/manager.ts @@ -9,7 +9,7 @@ import chokidar, { type FSWatcher } from "chokidar"; import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js"; import type { ResolvedMemorySearchConfig } from "../agents/memory-search.js"; import { resolveMemorySearchConfig } from "../agents/memory-search.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveSessionTranscriptsDirForAgent } from "../config/sessions/paths.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { onSessionTranscriptUpdate } from "../sessions/transcript-events.js"; @@ -118,7 +118,7 @@ const vectorToBlob = (embedding: number[]): Buffer => export class MemoryIndexManager { private readonly cacheKey: string; - private readonly cfg: MoltbotConfig; + private readonly cfg: OpenClawConfig; private readonly agentId: string; private readonly workspaceDir: string; private readonly settings: ResolvedMemorySearchConfig; @@ -174,7 +174,7 @@ export class MemoryIndexManager { private syncing: Promise | null = null; static async get(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId: string; }): Promise { const { cfg, agentId } = params; @@ -207,7 +207,7 @@ export class MemoryIndexManager { private constructor(params: { cacheKey: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId: string; workspaceDir: string; settings: ResolvedMemorySearchConfig; diff --git a/src/memory/manager.vector-dedupe.test.ts b/src/memory/manager.vector-dedupe.test.ts index d0872e4923..b867d0f740 100644 --- a/src/memory/manager.vector-dedupe.test.ts +++ b/src/memory/manager.vector-dedupe.test.ts @@ -27,7 +27,7 @@ describe("memory vector dedupe", () => { let manager: MemoryIndexManager | null = null; beforeEach(async () => { - workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-mem-")); + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-mem-")); indexPath = path.join(workspaceDir, "index.sqlite"); await fs.mkdir(path.join(workspaceDir, "memory")); await fs.writeFile(path.join(workspaceDir, "MEMORY.md"), "Hello memory."); diff --git a/src/memory/search-manager.ts b/src/memory/search-manager.ts index 9bcd529f32..c4eed3229b 100644 --- a/src/memory/search-manager.ts +++ b/src/memory/search-manager.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { MemoryIndexManager } from "./manager.js"; export type MemorySearchManagerResult = { @@ -7,7 +7,7 @@ export type MemorySearchManagerResult = { }; export async function getMemorySearchManager(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId: string; }): Promise { try { diff --git a/src/node-host/runner.ts b/src/node-host/runner.ts index e31ad3de3c..51439e38a8 100644 --- a/src/node-host/runner.ts +++ b/src/node-host/runner.ts @@ -41,7 +41,7 @@ import { import { createBrowserRouteDispatcher } from "../browser/routes/dispatcher.js"; import { detectMime } from "../media/mime.js"; import { resolveAgentConfig } from "../agents/agent-scope.js"; -import { ensureMoltbotCliOnPath } from "../infra/path-env.js"; +import { ensureOpenClawCliOnPath } from "../infra/path-env.js"; import { VERSION } from "../version.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; @@ -151,9 +151,9 @@ const OUTPUT_EVENT_TAIL = 20_000; const DEFAULT_NODE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; const BROWSER_PROXY_MAX_FILE_BYTES = 10 * 1024 * 1024; -const execHostEnforced = process.env.CLAWDBOT_NODE_EXEC_HOST?.trim().toLowerCase() === "app"; +const execHostEnforced = process.env.OPENCLAW_NODE_EXEC_HOST?.trim().toLowerCase() === "app"; const execHostFallbackAllowed = - process.env.CLAWDBOT_NODE_EXEC_FALLBACK?.trim().toLowerCase() !== "0"; + process.env.OPENCLAW_NODE_EXEC_FALLBACK?.trim().toLowerCase() !== "0"; const blockedEnvKeys = new Set([ "NODE_OPTIONS", @@ -435,7 +435,7 @@ function resolveEnvPath(env?: Record): string[] { } function ensureNodePathEnv(): string { - ensureMoltbotCliOnPath({ pathEnv: process.env.PATH ?? "" }); + ensureOpenClawCliOnPath({ pathEnv: process.env.PATH ?? "" }); const current = process.env.PATH ?? ""; if (current.trim()) return current; process.env.PATH = DEFAULT_NODE_PATH; @@ -513,10 +513,10 @@ export async function runNodeHost(opts: NodeHostRunOptions): Promise { const browserProxyEnabled = browserProxy.enabled && resolvedBrowser.enabled; const isRemoteMode = cfg.gateway?.mode === "remote"; const token = - process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || + process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || (isRemoteMode ? cfg.gateway?.remote?.token : cfg.gateway?.auth?.token); const password = - process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || + process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || (isRemoteMode ? cfg.gateway?.remote?.password : cfg.gateway?.auth?.password); const host = gateway.host ?? "127.0.0.1"; diff --git a/src/pairing/pairing-messages.test.ts b/src/pairing/pairing-messages.test.ts index 9884ac2f69..30586ee8a0 100644 --- a/src/pairing/pairing-messages.test.ts +++ b/src/pairing/pairing-messages.test.ts @@ -6,16 +6,16 @@ describe("buildPairingReply", () => { let previousProfile: string | undefined; beforeEach(() => { - previousProfile = process.env.CLAWDBOT_PROFILE; - process.env.CLAWDBOT_PROFILE = "isolated"; + previousProfile = process.env.OPENCLAW_PROFILE; + process.env.OPENCLAW_PROFILE = "isolated"; }); afterEach(() => { if (previousProfile === undefined) { - delete process.env.CLAWDBOT_PROFILE; + delete process.env.OPENCLAW_PROFILE; return; } - process.env.CLAWDBOT_PROFILE = previousProfile; + process.env.OPENCLAW_PROFILE = previousProfile; }); const cases = [ @@ -51,9 +51,9 @@ describe("buildPairingReply", () => { const text = buildPairingReply(testCase); expect(text).toContain(testCase.idLine); expect(text).toContain(`Pairing code: ${testCase.code}`); - // CLI commands should respect CLAWDBOT_PROFILE when set (most tests run with isolated profile) + // CLI commands should respect OPENCLAW_PROFILE when set (most tests run with isolated profile) const commandRe = new RegExp( - `(?:moltbot|moltbot) --profile isolated pairing approve ${testCase.channel} `, + `(?:openclaw|openclaw) --profile isolated pairing approve ${testCase.channel} `, ); expect(text).toMatch(commandRe); }); diff --git a/src/pairing/pairing-messages.ts b/src/pairing/pairing-messages.ts index 926c196128..7055145cfe 100644 --- a/src/pairing/pairing-messages.ts +++ b/src/pairing/pairing-messages.ts @@ -8,13 +8,13 @@ export function buildPairingReply(params: { }): string { const { channel, idLine, code } = params; return [ - "Moltbot: access not configured.", + "OpenClaw: access not configured.", "", idLine, "", `Pairing code: ${code}`, "", "Ask the bot owner to approve with:", - formatCliCommand(`moltbot pairing approve ${channel} `), + formatCliCommand(`openclaw pairing approve ${channel} `), ].join("\n"); } diff --git a/src/pairing/pairing-store.test.ts b/src/pairing/pairing-store.test.ts index a72264e161..8c0c98fc62 100644 --- a/src/pairing/pairing-store.test.ts +++ b/src/pairing/pairing-store.test.ts @@ -9,14 +9,14 @@ import { resolveOAuthDir } from "../config/paths.js"; import { listChannelPairingRequests, upsertChannelPairingRequest } from "./pairing-store.js"; async function withTempStateDir(fn: (stateDir: string) => Promise) { - const previous = process.env.CLAWDBOT_STATE_DIR; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-pairing-")); - process.env.CLAWDBOT_STATE_DIR = dir; + const previous = process.env.OPENCLAW_STATE_DIR; + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pairing-")); + process.env.OPENCLAW_STATE_DIR = dir; try { return await fn(dir); } finally { - if (previous === undefined) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = previous; + if (previous === undefined) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = previous; await fs.rm(dir, { recursive: true, force: true }); } } diff --git a/src/plugin-sdk/index.ts b/src/plugin-sdk/index.ts index 0813caefd6..5eb5cbfbe2 100644 --- a/src/plugin-sdk/index.ts +++ b/src/plugin-sdk/index.ts @@ -59,9 +59,9 @@ export type { } from "../channels/plugins/types.js"; export type { ChannelConfigSchema, ChannelPlugin } from "../channels/plugins/types.plugin.js"; export type { - MoltbotPluginApi, - MoltbotPluginService, - MoltbotPluginServiceContext, + OpenClawPluginApi, + OpenClawPluginService, + OpenClawPluginServiceContext, } from "../plugins/types.js"; export type { GatewayRequestHandler, @@ -72,7 +72,7 @@ export type { PluginRuntime } from "../plugins/runtime/types.js"; export { normalizePluginHttpPath } from "../plugins/http-path.js"; export { registerPluginHttpRoute } from "../plugins/http-registry.js"; export { emptyPluginConfigSchema } from "../plugins/config-schema.js"; -export type { MoltbotConfig } from "../config/config.js"; +export type { OpenClawConfig } from "../config/config.js"; export type { ChannelDock } from "../channels/dock.js"; export { getChatChannelMeta } from "../channels/registry.js"; export type { diff --git a/src/plugins/bundled-dir.ts b/src/plugins/bundled-dir.ts index 33524c36f4..72c4e18980 100644 --- a/src/plugins/bundled-dir.ts +++ b/src/plugins/bundled-dir.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; export function resolveBundledPluginsDir(): string | undefined { - const override = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR?.trim(); + const override = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR?.trim(); if (override) return override; // bun --compile: ship a sibling `extensions/` next to the executable. diff --git a/src/plugins/cli.test.ts b/src/plugins/cli.test.ts index d21302c95c..cbe8c1996e 100644 --- a/src/plugins/cli.test.ts +++ b/src/plugins/cli.test.ts @@ -7,7 +7,7 @@ const mocks = vi.hoisted(() => ({ })); vi.mock("./loader.js", () => ({ - loadMoltbotPlugins: () => ({ + loadOpenClawPlugins: () => ({ cliRegistrars: [ { pluginId: "memory-core", diff --git a/src/plugins/cli.ts b/src/plugins/cli.ts index cad44c9502..16a5c8d0da 100644 --- a/src/plugins/cli.ts +++ b/src/plugins/cli.ts @@ -1,15 +1,15 @@ import type { Command } from "commander"; import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; -import { loadMoltbotPlugins } from "./loader.js"; +import { loadOpenClawPlugins } from "./loader.js"; import type { PluginLogger } from "./types.js"; const log = createSubsystemLogger("plugins"); -export function registerPluginCliCommands(program: Command, cfg?: MoltbotConfig) { +export function registerPluginCliCommands(program: Command, cfg?: OpenClawConfig) { const config = cfg ?? loadConfig(); const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)); const logger: PluginLogger = { @@ -18,7 +18,7 @@ export function registerPluginCliCommands(program: Command, cfg?: MoltbotConfig) error: (msg: string) => log.error(msg), debug: (msg: string) => log.debug(msg), }; - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ config, workspaceDir, logger, diff --git a/src/plugins/commands.ts b/src/plugins/commands.ts index 128ad2b8cc..2fd5d9e039 100644 --- a/src/plugins/commands.ts +++ b/src/plugins/commands.ts @@ -5,15 +5,15 @@ * These commands are processed before built-in commands and before agent invocation. */ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { - MoltbotPluginCommandDefinition, + OpenClawPluginCommandDefinition, PluginCommandContext, PluginCommandResult, } from "./types.js"; import { logVerbose } from "../globals.js"; -type RegisteredPluginCommand = MoltbotPluginCommandDefinition & { +type RegisteredPluginCommand = OpenClawPluginCommandDefinition & { pluginId: string; }; @@ -104,7 +104,7 @@ export type CommandRegistrationResult = { */ export function registerPluginCommand( pluginId: string, - command: MoltbotPluginCommandDefinition, + command: OpenClawPluginCommandDefinition, ): CommandRegistrationResult { // Prevent registration while commands are being processed if (registryLocked) { @@ -221,7 +221,7 @@ export async function executePluginCommand(params: { channel: string; isAuthorizedSender: boolean; commandBody: string; - config: MoltbotConfig; + config: OpenClawConfig; }): Promise { const { command, args, senderId, channel, isAuthorizedSender, commandBody, config } = params; diff --git a/src/plugins/config-schema.ts b/src/plugins/config-schema.ts index 1fb9c502c5..f040e4b801 100644 --- a/src/plugins/config-schema.ts +++ b/src/plugins/config-schema.ts @@ -1,4 +1,4 @@ -import type { MoltbotPluginConfigSchema } from "./types.js"; +import type { OpenClawPluginConfigSchema } from "./types.js"; type Issue = { path: Array; message: string }; @@ -10,7 +10,7 @@ function error(message: string): SafeParseResult { return { success: false, error: { issues: [{ path: [], message }] } }; } -export function emptyPluginConfigSchema(): MoltbotPluginConfigSchema { +export function emptyPluginConfigSchema(): OpenClawPluginConfigSchema { return { safeParse(value: unknown): SafeParseResult { if (value === undefined) return { success: true, data: undefined }; diff --git a/src/plugins/config-state.ts b/src/plugins/config-state.ts index 5bfff7dbc7..01eadd4f9d 100644 --- a/src/plugins/config-state.ts +++ b/src/plugins/config-state.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { defaultSlotIdForKey } from "./slots.js"; import type { PluginRecord } from "./registry.js"; @@ -49,7 +49,7 @@ const normalizePluginEntries = (entries: unknown): NormalizedPluginsConfig["entr }; export const normalizePluginsConfig = ( - config?: MoltbotConfig["plugins"], + config?: OpenClawConfig["plugins"], ): NormalizedPluginsConfig => { const memorySlot = normalizeSlotValue(config?.slots?.memory); return { diff --git a/src/plugins/discovery.test.ts b/src/plugins/discovery.test.ts index a5c40ceb1f..54d046699e 100644 --- a/src/plugins/discovery.test.ts +++ b/src/plugins/discovery.test.ts @@ -7,30 +7,30 @@ import { afterEach, describe, expect, it, vi } from "vitest"; const tempDirs: string[] = []; function makeTempDir() { - const dir = path.join(os.tmpdir(), `moltbot-plugins-${randomUUID()}`); + const dir = path.join(os.tmpdir(), `openclaw-plugins-${randomUUID()}`); fs.mkdirSync(dir, { recursive: true }); tempDirs.push(dir); return dir; } async function withStateDir(stateDir: string, fn: () => Promise) { - const prev = process.env.CLAWDBOT_STATE_DIR; - const prevBundled = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR; - process.env.CLAWDBOT_STATE_DIR = stateDir; - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + const prev = process.env.OPENCLAW_STATE_DIR; + const prevBundled = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR; + process.env.OPENCLAW_STATE_DIR = stateDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; vi.resetModules(); try { return await fn(); } finally { if (prev === undefined) { - delete process.env.CLAWDBOT_STATE_DIR; + delete process.env.OPENCLAW_STATE_DIR; } else { - process.env.CLAWDBOT_STATE_DIR = prev; + process.env.OPENCLAW_STATE_DIR = prev; } if (prevBundled === undefined) { - delete process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR; + delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR; } else { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = prevBundled; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = prevBundled; } vi.resetModules(); } @@ -46,7 +46,7 @@ afterEach(() => { } }); -describe("discoverMoltbotPlugins", () => { +describe("discoverOpenClawPlugins", () => { it("discovers global and workspace extensions", async () => { const stateDir = makeTempDir(); const workspaceDir = path.join(stateDir, "workspace"); @@ -55,13 +55,13 @@ describe("discoverMoltbotPlugins", () => { fs.mkdirSync(globalExt, { recursive: true }); fs.writeFileSync(path.join(globalExt, "alpha.ts"), "export default function () {}", "utf-8"); - const workspaceExt = path.join(workspaceDir, ".clawdbot", "extensions"); + const workspaceExt = path.join(workspaceDir, ".openclaw", "extensions"); fs.mkdirSync(workspaceExt, { recursive: true }); fs.writeFileSync(path.join(workspaceExt, "beta.ts"), "export default function () {}", "utf-8"); const { candidates } = await withStateDir(stateDir, async () => { - const { discoverMoltbotPlugins } = await import("./discovery.js"); - return discoverMoltbotPlugins({ workspaceDir }); + const { discoverOpenClawPlugins } = await import("./discovery.js"); + return discoverOpenClawPlugins({ workspaceDir }); }); const ids = candidates.map((c) => c.idHint); @@ -78,7 +78,7 @@ describe("discoverMoltbotPlugins", () => { path.join(globalExt, "package.json"), JSON.stringify({ name: "pack", - moltbot: { extensions: ["./src/one.ts", "./src/two.ts"] }, + openclaw: { extensions: ["./src/one.ts", "./src/two.ts"] }, }), "utf-8", ); @@ -94,8 +94,8 @@ describe("discoverMoltbotPlugins", () => { ); const { candidates } = await withStateDir(stateDir, async () => { - const { discoverMoltbotPlugins } = await import("./discovery.js"); - return discoverMoltbotPlugins({}); + const { discoverOpenClawPlugins } = await import("./discovery.js"); + return discoverOpenClawPlugins({}); }); const ids = candidates.map((c) => c.idHint); @@ -111,8 +111,8 @@ describe("discoverMoltbotPlugins", () => { fs.writeFileSync( path.join(globalExt, "package.json"), JSON.stringify({ - name: "@moltbot/voice-call", - moltbot: { extensions: ["./src/index.ts"] }, + name: "@openclaw/voice-call", + openclaw: { extensions: ["./src/index.ts"] }, }), "utf-8", ); @@ -123,8 +123,8 @@ describe("discoverMoltbotPlugins", () => { ); const { candidates } = await withStateDir(stateDir, async () => { - const { discoverMoltbotPlugins } = await import("./discovery.js"); - return discoverMoltbotPlugins({}); + const { discoverOpenClawPlugins } = await import("./discovery.js"); + return discoverOpenClawPlugins({}); }); const ids = candidates.map((c) => c.idHint); @@ -139,16 +139,16 @@ describe("discoverMoltbotPlugins", () => { fs.writeFileSync( path.join(packDir, "package.json"), JSON.stringify({ - name: "@moltbot/demo-plugin-dir", - moltbot: { extensions: ["./index.js"] }, + name: "@openclaw/demo-plugin-dir", + openclaw: { extensions: ["./index.js"] }, }), "utf-8", ); fs.writeFileSync(path.join(packDir, "index.js"), "module.exports = {}", "utf-8"); const { candidates } = await withStateDir(stateDir, async () => { - const { discoverMoltbotPlugins } = await import("./discovery.js"); - return discoverMoltbotPlugins({ extraPaths: [packDir] }); + const { discoverOpenClawPlugins } = await import("./discovery.js"); + return discoverOpenClawPlugins({ extraPaths: [packDir] }); }); const ids = candidates.map((c) => c.idHint); diff --git a/src/plugins/discovery.ts b/src/plugins/discovery.ts index a03e4f38b2..d44c478a78 100644 --- a/src/plugins/discovery.ts +++ b/src/plugins/discovery.ts @@ -5,7 +5,7 @@ import { resolveConfigDir, resolveUserPath } from "../utils.js"; import { resolveBundledPluginsDir } from "./bundled-dir.js"; import { getPackageManifestMetadata, - type MoltbotPackageManifest, + type OpenClawPackageManifest, type PackageManifest, } from "./manifest.js"; import type { PluginDiagnostic, PluginOrigin } from "./types.js"; @@ -22,7 +22,7 @@ export type PluginCandidate = { packageVersion?: string; packageDescription?: string; packageDir?: string; - packageMoltbot?: MoltbotPackageManifest; + packageManifest?: OpenClawPackageManifest; }; export type PluginDiscoveryResult = { @@ -63,7 +63,7 @@ function deriveIdHint(params: { if (!rawPackageName) return base; // Prefer the unscoped name so config keys stay stable even when the npm - // package is scoped (example: @moltbot/voice-call -> voice-call). + // package is scoped (example: @openclaw/voice-call -> voice-call). const unscoped = rawPackageName.includes("/") ? (rawPackageName.split("/").pop() ?? rawPackageName) : rawPackageName; @@ -97,7 +97,7 @@ function addCandidate(params: { packageVersion: manifest?.version?.trim() || undefined, packageDescription: manifest?.description?.trim() || undefined, packageDir: params.packageDir, - packageMoltbot: getPackageManifestMetadata(manifest ?? undefined), + packageManifest: getPackageManifestMetadata(manifest ?? undefined), }); } @@ -281,7 +281,7 @@ function discoverFromPath(params: { } } -export function discoverMoltbotPlugins(params: { +export function discoverOpenClawPlugins(params: { workspaceDir?: string; extraPaths?: string[]; }): PluginDiscoveryResult { @@ -306,15 +306,17 @@ export function discoverMoltbotPlugins(params: { } if (workspaceDir) { const workspaceRoot = resolveUserPath(workspaceDir); - const workspaceExt = path.join(workspaceRoot, ".clawdbot", "extensions"); - discoverInDirectory({ - dir: workspaceExt, - origin: "workspace", - workspaceDir: workspaceRoot, - candidates, - diagnostics, - seen, - }); + const workspaceExtDirs = [path.join(workspaceRoot, ".openclaw", "extensions")]; + for (const dir of workspaceExtDirs) { + discoverInDirectory({ + dir, + origin: "workspace", + workspaceDir: workspaceRoot, + candidates, + diagnostics, + seen, + }); + } } const globalDir = path.join(resolveConfigDir(), "extensions"); diff --git a/src/plugins/enable.ts b/src/plugins/enable.ts index 38bfd314d0..f3833c5542 100644 --- a/src/plugins/enable.ts +++ b/src/plugins/enable.ts @@ -1,12 +1,12 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; export type PluginEnableResult = { - config: MoltbotConfig; + config: OpenClawConfig; enabled: boolean; reason?: string; }; -function ensureAllowlisted(cfg: MoltbotConfig, pluginId: string): MoltbotConfig { +function ensureAllowlisted(cfg: OpenClawConfig, pluginId: string): OpenClawConfig { const allow = cfg.plugins?.allow; if (!Array.isArray(allow) || allow.includes(pluginId)) return cfg; return { @@ -18,7 +18,7 @@ function ensureAllowlisted(cfg: MoltbotConfig, pluginId: string): MoltbotConfig }; } -export function enablePluginInConfig(cfg: MoltbotConfig, pluginId: string): PluginEnableResult { +export function enablePluginInConfig(cfg: OpenClawConfig, pluginId: string): PluginEnableResult { if (cfg.plugins?.enabled === false) { return { config: cfg, enabled: false, reason: "plugins disabled" }; } @@ -33,7 +33,7 @@ export function enablePluginInConfig(cfg: MoltbotConfig, pluginId: string): Plug enabled: true, }, }; - let next: MoltbotConfig = { + let next: OpenClawConfig = { ...cfg, plugins: { ...cfg.plugins, diff --git a/src/plugins/install.test.ts b/src/plugins/install.test.ts index 8299100d6b..a20baab747 100644 --- a/src/plugins/install.test.ts +++ b/src/plugins/install.test.ts @@ -9,7 +9,7 @@ import { afterEach, describe, expect, it } from "vitest"; const tempDirs: string[] = []; function makeTempDir() { - const dir = path.join(os.tmpdir(), `moltbot-plugin-install-${randomUUID()}`); + const dir = path.join(os.tmpdir(), `openclaw-plugin-install-${randomUUID()}`); fs.mkdirSync(dir, { recursive: true }); tempDirs.push(dir); return dir; @@ -88,7 +88,7 @@ afterEach(() => { }); describe("installPluginFromArchive", () => { - it("installs into ~/.clawdbot/extensions and uses unscoped id", async () => { + it("installs into ~/.openclaw/extensions and uses unscoped id", async () => { const stateDir = makeTempDir(); const workDir = makeTempDir(); const pkgDir = path.join(workDir, "package"); @@ -96,9 +96,9 @@ describe("installPluginFromArchive", () => { fs.writeFileSync( path.join(pkgDir, "package.json"), JSON.stringify({ - name: "@moltbot/voice-call", + name: "@openclaw/voice-call", version: "0.0.1", - moltbot: { extensions: ["./dist/index.js"] }, + openclaw: { extensions: ["./dist/index.js"] }, }), "utf-8", ); @@ -129,9 +129,9 @@ describe("installPluginFromArchive", () => { fs.writeFileSync( path.join(pkgDir, "package.json"), JSON.stringify({ - name: "@moltbot/voice-call", + name: "@openclaw/voice-call", version: "0.0.1", - moltbot: { extensions: ["./dist/index.js"] }, + openclaw: { extensions: ["./dist/index.js"] }, }), "utf-8", ); @@ -163,9 +163,9 @@ describe("installPluginFromArchive", () => { zip.file( "package/package.json", JSON.stringify({ - name: "@moltbot/zipper", + name: "@openclaw/zipper", version: "0.0.1", - moltbot: { extensions: ["./dist/index.js"] }, + openclaw: { extensions: ["./dist/index.js"] }, }), ); zip.file("package/dist/index.js", "export {};"); @@ -192,9 +192,9 @@ describe("installPluginFromArchive", () => { fs.writeFileSync( path.join(pkgDir, "package.json"), JSON.stringify({ - name: "@moltbot/voice-call", + name: "@openclaw/voice-call", version: "0.0.1", - moltbot: { extensions: ["./dist/index.js"] }, + openclaw: { extensions: ["./dist/index.js"] }, }), "utf-8", ); @@ -210,9 +210,9 @@ describe("installPluginFromArchive", () => { fs.writeFileSync( path.join(pkgDir, "package.json"), JSON.stringify({ - name: "@moltbot/voice-call", + name: "@openclaw/voice-call", version: "0.0.2", - moltbot: { extensions: ["./dist/index.js"] }, + openclaw: { extensions: ["./dist/index.js"] }, }), "utf-8", ); @@ -244,14 +244,14 @@ describe("installPluginFromArchive", () => { expect(manifest.version).toBe("0.0.2"); }); - it("rejects packages without moltbot.extensions", async () => { + it("rejects packages without openclaw.extensions", async () => { const stateDir = makeTempDir(); const workDir = makeTempDir(); const pkgDir = path.join(workDir, "package"); fs.mkdirSync(pkgDir, { recursive: true }); fs.writeFileSync( path.join(pkgDir, "package.json"), - JSON.stringify({ name: "@moltbot/nope", version: "0.0.1" }), + JSON.stringify({ name: "@openclaw/nope", version: "0.0.1" }), "utf-8", ); @@ -266,6 +266,6 @@ describe("installPluginFromArchive", () => { const result = await installPluginFromArchive({ archivePath, extensionsDir }); expect(result.ok).toBe(false); if (result.ok) return; - expect(result.error).toContain("moltbot.extensions"); + expect(result.error).toContain("openclaw.extensions"); }); }); diff --git a/src/plugins/install.ts b/src/plugins/install.ts index c66db9667b..c5a11d028f 100644 --- a/src/plugins/install.ts +++ b/src/plugins/install.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { LEGACY_MANIFEST_KEY } from "../compat/legacy-names.js"; +import { MANIFEST_KEY } from "../compat/legacy-names.js"; import { runCommandWithTimeout } from "../process/exec.js"; import { CONFIG_DIR, resolveUserPath } from "../utils.js"; import { @@ -21,9 +21,7 @@ type PackageManifest = { name?: string; version?: string; dependencies?: Record; - moltbot?: { extensions?: string[] }; - [LEGACY_MANIFEST_KEY]?: { extensions?: string[] }; -}; +} & Partial>; export type InstallPluginResult = | { @@ -54,14 +52,14 @@ function safeFileName(input: string): string { return safeDirName(input); } -async function ensureMoltbotExtensions(manifest: PackageManifest) { - const extensions = manifest.moltbot?.extensions ?? manifest[LEGACY_MANIFEST_KEY]?.extensions; +async function ensureOpenClawExtensions(manifest: PackageManifest) { + const extensions = manifest[MANIFEST_KEY]?.extensions; if (!Array.isArray(extensions)) { - throw new Error("package.json missing moltbot.extensions"); + throw new Error("package.json missing openclaw.extensions"); } const list = extensions.map((e) => (typeof e === "string" ? e.trim() : "")).filter(Boolean); if (list.length === 0) { - throw new Error("package.json moltbot.extensions is empty"); + throw new Error("package.json openclaw.extensions is empty"); } return list; } @@ -101,7 +99,7 @@ async function installPluginFromPackageDir(params: { let extensions: string[]; try { - extensions = await ensureMoltbotExtensions(manifest); + extensions = await ensureOpenClawExtensions(manifest); } catch (err) { return { ok: false, error: String(err) }; } @@ -219,7 +217,7 @@ export async function installPluginFromArchive(params: { return { ok: false, error: `unsupported archive: ${archivePath}` }; } - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-plugin-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-plugin-")); const extractDir = path.join(tmpDir, "extract"); await fs.mkdir(extractDir, { recursive: true }); @@ -352,7 +350,7 @@ export async function installPluginFromNpmSpec(params: { const spec = params.spec.trim(); if (!spec) return { ok: false, error: "missing npm spec" }; - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-npm-pack-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-npm-pack-")); logger.info?.(`Downloading ${spec}…`); const res = await runCommandWithTimeout(["npm", "pack", spec], { timeoutMs: Math.max(timeoutMs, 300_000), diff --git a/src/plugins/installs.ts b/src/plugins/installs.ts index 7cc026076e..45a9fa8556 100644 --- a/src/plugins/installs.ts +++ b/src/plugins/installs.ts @@ -1,12 +1,12 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { PluginInstallRecord } from "../config/types.plugins.js"; export type PluginInstallUpdate = PluginInstallRecord & { pluginId: string }; export function recordPluginInstall( - cfg: MoltbotConfig, + cfg: OpenClawConfig, update: PluginInstallUpdate, -): MoltbotConfig { +): OpenClawConfig { const { pluginId, ...record } = update; const installs = { ...cfg.plugins?.installs, diff --git a/src/plugins/loader.test.ts b/src/plugins/loader.test.ts index 7e9316171d..8610a4b495 100644 --- a/src/plugins/loader.test.ts +++ b/src/plugins/loader.test.ts @@ -4,16 +4,16 @@ import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { loadMoltbotPlugins } from "./loader.js"; +import { loadOpenClawPlugins } from "./loader.js"; type TempPlugin = { dir: string; file: string; id: string }; const tempDirs: string[] = []; -const prevBundledDir = process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR; +const prevBundledDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR; const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} }; function makeTempDir() { - const dir = path.join(os.tmpdir(), `moltbot-plugin-${randomUUID()}`); + const dir = path.join(os.tmpdir(), `openclaw-plugin-${randomUUID()}`); fs.mkdirSync(dir, { recursive: true }); tempDirs.push(dir); return dir; @@ -30,7 +30,7 @@ function writePlugin(params: { const file = path.join(dir, filename); fs.writeFileSync(file, params.body, "utf-8"); fs.writeFileSync( - path.join(dir, "moltbot.plugin.json"), + path.join(dir, "openclaw.plugin.json"), JSON.stringify( { id: params.id, @@ -53,13 +53,13 @@ afterEach(() => { } } if (prevBundledDir === undefined) { - delete process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR; + delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR; } else { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = prevBundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = prevBundledDir; } }); -describe("loadMoltbotPlugins", () => { +describe("loadOpenClawPlugins", () => { it("disables bundled plugins by default", () => { const bundledDir = makeTempDir(); writePlugin({ @@ -68,9 +68,9 @@ describe("loadMoltbotPlugins", () => { dir: bundledDir, filename: "bundled.ts", }); - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir; - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -82,7 +82,7 @@ describe("loadMoltbotPlugins", () => { const bundled = registry.plugins.find((entry) => entry.id === "bundled"); expect(bundled?.status).toBe("disabled"); - const enabledRegistry = loadMoltbotPlugins({ + const enabledRegistry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -125,9 +125,9 @@ describe("loadMoltbotPlugins", () => { dir: bundledDir, filename: "telegram.ts", }); - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir; - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -152,9 +152,9 @@ describe("loadMoltbotPlugins", () => { dir: bundledDir, filename: "memory-core.ts", }); - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir; - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -177,10 +177,10 @@ describe("loadMoltbotPlugins", () => { fs.writeFileSync( path.join(pluginDir, "package.json"), JSON.stringify({ - name: "@moltbot/memory-core", + name: "@openclaw/memory-core", version: "1.2.3", description: "Memory plugin package", - moltbot: { extensions: ["./index.ts"] }, + openclaw: { extensions: ["./index.ts"] }, }), "utf-8", ); @@ -191,9 +191,9 @@ describe("loadMoltbotPlugins", () => { filename: "index.ts", }); - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir; - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -211,13 +211,13 @@ describe("loadMoltbotPlugins", () => { expect(memory?.version).toBe("1.2.3"); }); it("loads plugins from config paths", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "allowed", body: `export default { id: "allowed", register(api) { api.registerGatewayMethod("allowed.ping", ({ respond }) => respond(true, { ok: true })); } };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -234,13 +234,13 @@ describe("loadMoltbotPlugins", () => { }); it("denylist disables plugins even if allowed", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "blocked", body: `export default { id: "blocked", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -257,13 +257,13 @@ describe("loadMoltbotPlugins", () => { }); it("fails fast on invalid plugin config", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "configurable", body: `export default { id: "configurable", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -284,7 +284,7 @@ describe("loadMoltbotPlugins", () => { }); it("registers channel plugins", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "channel-demo", body: `export default { id: "channel-demo", register(api) { @@ -309,7 +309,7 @@ describe("loadMoltbotPlugins", () => { } };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -325,7 +325,7 @@ describe("loadMoltbotPlugins", () => { }); it("registers http handlers", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "http-demo", body: `export default { id: "http-demo", register(api) { @@ -333,7 +333,7 @@ describe("loadMoltbotPlugins", () => { } };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -351,7 +351,7 @@ describe("loadMoltbotPlugins", () => { }); it("registers http routes", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "http-route-demo", body: `export default { id: "http-route-demo", register(api) { @@ -359,7 +359,7 @@ describe("loadMoltbotPlugins", () => { } };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, workspaceDir: plugin.dir, config: { @@ -378,13 +378,13 @@ describe("loadMoltbotPlugins", () => { }); it("respects explicit disable in config", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const plugin = writePlugin({ id: "config-disable", body: `export default { id: "config-disable", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -401,7 +401,7 @@ describe("loadMoltbotPlugins", () => { }); it("enforces memory slot selection", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const memoryA = writePlugin({ id: "memory-a", body: `export default { id: "memory-a", kind: "memory", register() {} };`, @@ -411,7 +411,7 @@ describe("loadMoltbotPlugins", () => { body: `export default { id: "memory-b", kind: "memory", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -428,13 +428,13 @@ describe("loadMoltbotPlugins", () => { }); it("disables memory plugins when slot is none", () => { - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins"; const memory = writePlugin({ id: "memory-off", body: `export default { id: "memory-off", kind: "memory", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { @@ -456,14 +456,14 @@ describe("loadMoltbotPlugins", () => { dir: bundledDir, filename: "shadow.js", }); - process.env.CLAWDBOT_BUNDLED_PLUGINS_DIR = bundledDir; + process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = bundledDir; const override = writePlugin({ id: "shadow", body: `export default { id: "shadow", register() {} };`, }); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ cache: false, config: { plugins: { diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts index 79c785f27a..5062082c43 100644 --- a/src/plugins/loader.ts +++ b/src/plugins/loader.ts @@ -3,14 +3,13 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { createJiti } from "jiti"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { resolveUserPath } from "../utils.js"; -import { discoverMoltbotPlugins } from "./discovery.js"; +import { discoverOpenClawPlugins } from "./discovery.js"; import { loadPluginManifestRegistry } from "./manifest-registry.js"; import { - applyTestPluginDefaults, normalizePluginsConfig, resolveEnableState, resolveMemorySlotDecision, @@ -23,8 +22,8 @@ import { createPluginRuntime } from "./runtime/index.js"; import { setActivePluginRegistry } from "./runtime.js"; import { validateJsonSchemaValue } from "./schema-validator.js"; import type { - MoltbotPluginDefinition, - MoltbotPluginModule, + OpenClawPluginDefinition, + OpenClawPluginModule, PluginDiagnostic, PluginLogger, } from "./types.js"; @@ -32,7 +31,7 @@ import type { export type PluginLoadResult = PluginRegistry; export type PluginLoadOptions = { - config?: MoltbotConfig; + config?: OpenClawConfig; workspaceDir?: string; logger?: PluginLogger; coreGatewayHandlers?: Record; @@ -99,8 +98,8 @@ function validatePluginConfig(params: { } function resolvePluginModuleExport(moduleExport: unknown): { - definition?: MoltbotPluginDefinition; - register?: MoltbotPluginDefinition["register"]; + definition?: OpenClawPluginDefinition; + register?: OpenClawPluginDefinition["register"]; } { const resolved = moduleExport && @@ -110,11 +109,11 @@ function resolvePluginModuleExport(moduleExport: unknown): { : moduleExport; if (typeof resolved === "function") { return { - register: resolved as MoltbotPluginDefinition["register"], + register: resolved as OpenClawPluginDefinition["register"], }; } if (resolved && typeof resolved === "object") { - const def = resolved as MoltbotPluginDefinition; + const def = resolved as OpenClawPluginDefinition; const register = def.register ?? def.activate; return { definition: def, register }; } @@ -162,8 +161,8 @@ function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnost diagnostics.push(...append); } -export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegistry { - const cfg = applyTestPluginDefaults(options.config ?? {}); +export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegistry { + const cfg = options.config ?? {}; const logger = options.logger ?? defaultLogger(); const validateOnly = options.mode === "validate"; const normalized = normalizePluginsConfig(cfg.plugins); @@ -190,7 +189,7 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis coreGatewayHandlers: options.coreGatewayHandlers as Record, }); - const discovery = discoverMoltbotPlugins({ + const discovery = discoverOpenClawPlugins({ workspaceDir: options.workspaceDir, extraPaths: normalized.loadPaths, }); @@ -209,10 +208,7 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"], ...(pluginSdkAlias ? { - alias: { - "clawdbot/plugin-sdk": pluginSdkAlias, - "moltbot/plugin-sdk": pluginSdkAlias, - }, + alias: { "openclaw/plugin-sdk": pluginSdkAlias }, } : {}), }); @@ -290,9 +286,9 @@ export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegis continue; } - let mod: MoltbotPluginModule | null = null; + let mod: OpenClawPluginModule | null = null; try { - mod = jiti(candidate.source) as MoltbotPluginModule; + mod = jiti(candidate.source) as OpenClawPluginModule; } catch (err) { logger.error(`[plugins] ${record.id} failed to load from ${record.source}: ${String(err)}`); record.status = "error"; diff --git a/src/plugins/manifest-registry.ts b/src/plugins/manifest-registry.ts index 9a53c9d70b..d785c018a3 100644 --- a/src/plugins/manifest-registry.ts +++ b/src/plugins/manifest-registry.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveUserPath } from "../utils.js"; import { normalizePluginsConfig, type NormalizedPluginsConfig } from "./config-state.js"; -import { discoverMoltbotPlugins, type PluginCandidate } from "./discovery.js"; +import { discoverOpenClawPlugins, type PluginCandidate } from "./discovery.js"; import { loadPluginManifest, type PluginManifest } from "./manifest.js"; import type { PluginConfigUiHint, PluginDiagnostic, PluginKind, PluginOrigin } from "./types.js"; @@ -36,7 +36,7 @@ const registryCache = new Map 0; } @@ -100,7 +100,7 @@ function buildRecord(params: { } export function loadPluginManifestRegistry(params: { - config?: MoltbotConfig; + config?: OpenClawConfig; workspaceDir?: string; cache?: boolean; env?: NodeJS.ProcessEnv; @@ -122,7 +122,7 @@ export function loadPluginManifestRegistry(params: { candidates: params.candidates, diagnostics: params.diagnostics ?? [], } - : discoverMoltbotPlugins({ + : discoverOpenClawPlugins({ workspaceDir: params.workspaceDir, extraPaths: normalized.loadPaths, }); diff --git a/src/plugins/manifest.ts b/src/plugins/manifest.ts index 1d86338476..470804d2c6 100644 --- a/src/plugins/manifest.ts +++ b/src/plugins/manifest.ts @@ -1,14 +1,11 @@ import fs from "node:fs"; import path from "node:path"; -import { LEGACY_MANIFEST_KEY, LEGACY_PLUGIN_MANIFEST_FILENAME } from "../compat/legacy-names.js"; +import { MANIFEST_KEY } from "../compat/legacy-names.js"; import type { PluginConfigUiHint, PluginKind } from "./types.js"; -export const PLUGIN_MANIFEST_FILENAME = "moltbot.plugin.json"; -export const PLUGIN_MANIFEST_FILENAMES = [ - PLUGIN_MANIFEST_FILENAME, - LEGACY_PLUGIN_MANIFEST_FILENAME, -] as const; +export const PLUGIN_MANIFEST_FILENAME = "openclaw.plugin.json"; +export const PLUGIN_MANIFEST_FILENAMES = [PLUGIN_MANIFEST_FILENAME] as const; export type PluginManifest = { id: string; @@ -102,7 +99,7 @@ export function loadPluginManifest(rootDir: string): PluginManifestLoadResult { }; } -// package.json "moltbot" metadata (used for onboarding/catalog) +// package.json "openclaw" metadata (used for onboarding/catalog) export type PluginPackageChannel = { id?: string; label?: string; @@ -130,23 +127,23 @@ export type PluginPackageInstall = { defaultChoice?: "npm" | "local"; }; -export type MoltbotPackageManifest = { +export type OpenClawPackageManifest = { extensions?: string[]; channel?: PluginPackageChannel; install?: PluginPackageInstall; }; +export type ManifestKey = typeof MANIFEST_KEY; + export type PackageManifest = { name?: string; version?: string; description?: string; - moltbot?: MoltbotPackageManifest; - [LEGACY_MANIFEST_KEY]?: MoltbotPackageManifest; -}; +} & Partial>; export function getPackageManifestMetadata( manifest: PackageManifest | undefined, -): MoltbotPackageManifest | undefined { +): OpenClawPackageManifest | undefined { if (!manifest) return undefined; - return manifest.moltbot ?? manifest[LEGACY_MANIFEST_KEY]; + return manifest[MANIFEST_KEY]; } diff --git a/src/plugins/providers.ts b/src/plugins/providers.ts index 88d1688361..7ab2d1848e 100644 --- a/src/plugins/providers.ts +++ b/src/plugins/providers.ts @@ -1,5 +1,5 @@ import { createSubsystemLogger } from "../logging/subsystem.js"; -import { loadMoltbotPlugins, type PluginLoadOptions } from "./loader.js"; +import { loadOpenClawPlugins, type PluginLoadOptions } from "./loader.js"; import type { ProviderPlugin } from "./types.js"; const log = createSubsystemLogger("plugins"); @@ -8,7 +8,7 @@ export function resolvePluginProviders(params: { config?: PluginLoadOptions["config"]; workspaceDir?: string; }): ProviderPlugin[] { - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ config: params.config, workspaceDir: params.workspaceDir, logger: { diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index 226f6e4968..e7d4e3a8b9 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -8,17 +8,17 @@ import type { import { registerInternalHook } from "../hooks/internal-hooks.js"; import { resolveUserPath } from "../utils.js"; import type { - MoltbotPluginApi, - MoltbotPluginChannelRegistration, - MoltbotPluginCliRegistrar, - MoltbotPluginCommandDefinition, - MoltbotPluginHttpHandler, - MoltbotPluginHttpRouteHandler, - MoltbotPluginHookOptions, + OpenClawPluginApi, + OpenClawPluginChannelRegistration, + OpenClawPluginCliRegistrar, + OpenClawPluginCommandDefinition, + OpenClawPluginHttpHandler, + OpenClawPluginHttpRouteHandler, + OpenClawPluginHookOptions, ProviderPlugin, - MoltbotPluginService, - MoltbotPluginToolContext, - MoltbotPluginToolFactory, + OpenClawPluginService, + OpenClawPluginToolContext, + OpenClawPluginToolFactory, PluginConfigUiHint, PluginDiagnostic, PluginLogger, @@ -36,7 +36,7 @@ import { normalizePluginHttpPath } from "./http-path.js"; export type PluginToolRegistration = { pluginId: string; - factory: MoltbotPluginToolFactory; + factory: OpenClawPluginToolFactory; names: string[]; optional: boolean; source: string; @@ -44,21 +44,21 @@ export type PluginToolRegistration = { export type PluginCliRegistration = { pluginId: string; - register: MoltbotPluginCliRegistrar; + register: OpenClawPluginCliRegistrar; commands: string[]; source: string; }; export type PluginHttpRegistration = { pluginId: string; - handler: MoltbotPluginHttpHandler; + handler: OpenClawPluginHttpHandler; source: string; }; export type PluginHttpRouteRegistration = { pluginId?: string; path: string; - handler: MoltbotPluginHttpRouteHandler; + handler: OpenClawPluginHttpRouteHandler; source?: string; }; @@ -84,13 +84,13 @@ export type PluginHookRegistration = { export type PluginServiceRegistration = { pluginId: string; - service: MoltbotPluginService; + service: OpenClawPluginService; source: string; }; export type PluginCommandRegistration = { pluginId: string; - command: MoltbotPluginCommandDefinition; + command: OpenClawPluginCommandDefinition; source: string; }; @@ -167,13 +167,13 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const registerTool = ( record: PluginRecord, - tool: AnyAgentTool | MoltbotPluginToolFactory, + tool: AnyAgentTool | OpenClawPluginToolFactory, opts?: { name?: string; names?: string[]; optional?: boolean }, ) => { const names = opts?.names ?? (opts?.name ? [opts.name] : []); const optional = opts?.optional === true; - const factory: MoltbotPluginToolFactory = - typeof tool === "function" ? tool : (_ctx: MoltbotPluginToolContext) => tool; + const factory: OpenClawPluginToolFactory = + typeof tool === "function" ? tool : (_ctx: OpenClawPluginToolContext) => tool; if (typeof tool !== "function") { names.push(tool.name); @@ -196,8 +196,8 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { record: PluginRecord, events: string | string[], handler: Parameters[1], - opts: MoltbotPluginHookOptions | undefined, - config: MoltbotPluginApi["config"], + opts: OpenClawPluginHookOptions | undefined, + config: OpenClawPluginApi["config"], ) => { const eventList = Array.isArray(events) ? events : [events]; const normalizedEvents = eventList.map((event) => event.trim()).filter(Boolean); @@ -221,7 +221,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { ...entry.hook, name, description, - source: "moltbot-plugin", + source: "openclaw-plugin", pluginId: record.id, }, metadata: { @@ -233,7 +233,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { hook: { name, description, - source: "moltbot-plugin", + source: "openclaw-plugin", pluginId: record.id, filePath: record.source, baseDir: path.dirname(record.source), @@ -282,7 +282,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { record.gatewayMethods.push(trimmed); }; - const registerHttpHandler = (record: PluginRecord, handler: MoltbotPluginHttpHandler) => { + const registerHttpHandler = (record: PluginRecord, handler: OpenClawPluginHttpHandler) => { record.httpHandlers += 1; registry.httpHandlers.push({ pluginId: record.id, @@ -293,7 +293,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const registerHttpRoute = ( record: PluginRecord, - params: { path: string; handler: MoltbotPluginHttpRouteHandler }, + params: { path: string; handler: OpenClawPluginHttpRouteHandler }, ) => { const normalizedPath = normalizePluginHttpPath(params.path); if (!normalizedPath) { @@ -325,11 +325,11 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const registerChannel = ( record: PluginRecord, - registration: MoltbotPluginChannelRegistration | ChannelPlugin, + registration: OpenClawPluginChannelRegistration | ChannelPlugin, ) => { const normalized = - typeof (registration as MoltbotPluginChannelRegistration).plugin === "object" - ? (registration as MoltbotPluginChannelRegistration) + typeof (registration as OpenClawPluginChannelRegistration).plugin === "object" + ? (registration as OpenClawPluginChannelRegistration) : { plugin: registration as ChannelPlugin }; const plugin = normalized.plugin; const id = typeof plugin?.id === "string" ? plugin.id.trim() : String(plugin?.id ?? "").trim(); @@ -382,7 +382,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const registerCli = ( record: PluginRecord, - registrar: MoltbotPluginCliRegistrar, + registrar: OpenClawPluginCliRegistrar, opts?: { commands?: string[] }, ) => { const commands = (opts?.commands ?? []).map((cmd) => cmd.trim()).filter(Boolean); @@ -395,7 +395,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { }); }; - const registerService = (record: PluginRecord, service: MoltbotPluginService) => { + const registerService = (record: PluginRecord, service: OpenClawPluginService) => { const id = service.id.trim(); if (!id) return; record.services.push(id); @@ -406,7 +406,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { }); }; - const registerCommand = (record: PluginRecord, command: MoltbotPluginCommandDefinition) => { + const registerCommand = (record: PluginRecord, command: OpenClawPluginCommandDefinition) => { const name = command.name.trim(); if (!name) { pushDiagnostic({ @@ -464,10 +464,10 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const createApi = ( record: PluginRecord, params: { - config: MoltbotPluginApi["config"]; + config: OpenClawPluginApi["config"]; pluginConfig?: Record; }, - ): MoltbotPluginApi => { + ): OpenClawPluginApi => { return { id: record.id, name: record.name, diff --git a/src/plugins/runtime.ts b/src/plugins/runtime.ts index 70e958b5ae..33be2d85c1 100644 --- a/src/plugins/runtime.ts +++ b/src/plugins/runtime.ts @@ -16,7 +16,7 @@ const createEmptyRegistry = (): PluginRegistry => ({ diagnostics: [], }); -const REGISTRY_STATE = Symbol.for("moltbot.pluginRegistryState"); +const REGISTRY_STATE = Symbol.for("openclaw.pluginRegistryState"); type RegistryState = { registry: PluginRegistry | null; diff --git a/src/plugins/services.ts b/src/plugins/services.ts index 8f1f5f8ba2..201d7ad655 100644 --- a/src/plugins/services.ts +++ b/src/plugins/services.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { STATE_DIR } from "../config/paths.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import type { PluginRegistry } from "./registry.js"; @@ -11,7 +11,7 @@ export type PluginServicesHandle = { export async function startPluginServices(params: { registry: PluginRegistry; - config: MoltbotConfig; + config: OpenClawConfig; workspaceDir?: string; }): Promise { const running: Array<{ diff --git a/src/plugins/slots.test.ts b/src/plugins/slots.test.ts index ae0cf4d6a6..6fc1a2c838 100644 --- a/src/plugins/slots.test.ts +++ b/src/plugins/slots.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { applyExclusiveSlotSelection } from "./slots.js"; describe("applyExclusiveSlotSelection", () => { it("selects the slot and disables other entries for the same kind", () => { - const config: MoltbotConfig = { + const config: OpenClawConfig = { plugins: { slots: { memory: "memory-core" }, entries: { @@ -37,7 +37,7 @@ describe("applyExclusiveSlotSelection", () => { }); it("does nothing when the slot already matches", () => { - const config: MoltbotConfig = { + const config: OpenClawConfig = { plugins: { slots: { memory: "memory" }, entries: { @@ -59,7 +59,7 @@ describe("applyExclusiveSlotSelection", () => { }); it("warns when the slot falls back to a default", () => { - const config: MoltbotConfig = { + const config: OpenClawConfig = { plugins: { entries: { memory: { enabled: true }, @@ -81,7 +81,7 @@ describe("applyExclusiveSlotSelection", () => { }); it("skips changes when no exclusive slot applies", () => { - const config: MoltbotConfig = {}; + const config: OpenClawConfig = {}; const result = applyExclusiveSlotSelection({ config, selectedId: "custom", diff --git a/src/plugins/slots.ts b/src/plugins/slots.ts index 07c99c3e30..785bccbadd 100644 --- a/src/plugins/slots.ts +++ b/src/plugins/slots.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { PluginSlotsConfig } from "../config/types.plugins.js"; import type { PluginKind } from "./types.js"; @@ -27,13 +27,13 @@ export function defaultSlotIdForKey(slotKey: PluginSlotKey): string { } export type SlotSelectionResult = { - config: MoltbotConfig; + config: OpenClawConfig; warnings: string[]; changed: boolean; }; export function applyExclusiveSlotSelection(params: { - config: MoltbotConfig; + config: OpenClawConfig; selectedId: string; selectedKind?: PluginKind; registry?: { plugins: SlotPluginRecord[] }; diff --git a/src/plugins/status.ts b/src/plugins/status.ts index 3de6435f83..b5d444cc3b 100644 --- a/src/plugins/status.ts +++ b/src/plugins/status.ts @@ -2,7 +2,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js"; import { loadConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; -import { loadMoltbotPlugins } from "./loader.js"; +import { loadOpenClawPlugins } from "./loader.js"; import type { PluginRegistry } from "./registry.js"; export type PluginStatusReport = PluginRegistry & { @@ -21,7 +21,7 @@ export function buildPluginStatusReport(params?: { : (resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ?? resolveDefaultAgentWorkspaceDir()); - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ config, workspaceDir, logger: { diff --git a/src/plugins/tools.optional.test.ts b/src/plugins/tools.optional.test.ts index e596288b6c..53efdc1d0c 100644 --- a/src/plugins/tools.optional.test.ts +++ b/src/plugins/tools.optional.test.ts @@ -13,7 +13,7 @@ const tempDirs: string[] = []; const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} }; function makeTempDir() { - const dir = path.join(os.tmpdir(), `moltbot-plugin-tools-${randomUUID()}`); + const dir = path.join(os.tmpdir(), `openclaw-plugin-tools-${randomUUID()}`); fs.mkdirSync(dir, { recursive: true }); tempDirs.push(dir); return dir; @@ -24,7 +24,7 @@ function writePlugin(params: { id: string; body: string }): TempPlugin { const file = path.join(dir, `${params.id}.js`); fs.writeFileSync(file, params.body, "utf-8"); fs.writeFileSync( - path.join(dir, "moltbot.plugin.json"), + path.join(dir, "openclaw.plugin.json"), JSON.stringify( { id: params.id, diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index 09e4af8bce..2556d538b5 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -1,8 +1,8 @@ import type { AnyAgentTool } from "../agents/tools/common.js"; import { normalizeToolName } from "../agents/tool-policy.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; -import { loadMoltbotPlugins } from "./loader.js"; -import type { MoltbotPluginToolContext } from "./types.js"; +import { loadOpenClawPlugins } from "./loader.js"; +import type { OpenClawPluginToolContext } from "./types.js"; const log = createSubsystemLogger("plugins"); @@ -35,11 +35,11 @@ function isOptionalToolAllowed(params: { } export function resolvePluginTools(params: { - context: MoltbotPluginToolContext; + context: OpenClawPluginToolContext; existingToolNames?: Set; toolAllowlist?: string[]; }): AnyAgentTool[] { - const registry = loadMoltbotPlugins({ + const registry = loadOpenClawPlugins({ config: params.context.config, workspaceDir: params.context.workspaceDir, logger: { diff --git a/src/plugins/types.ts b/src/plugins/types.ts index f9aaa5709f..8bc887068b 100644 --- a/src/plugins/types.ts +++ b/src/plugins/types.ts @@ -7,7 +7,7 @@ import type { AuthProfileCredential, OAuthCredential } from "../agents/auth-prof import type { AnyAgentTool } from "../agents/tools/common.js"; import type { ChannelDock } from "../channels/dock.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { InternalHookHandler } from "../hooks/internal-hooks.js"; import type { HookEntry } from "../hooks/types.js"; import type { ModelProviderConfig } from "../config/types.js"; @@ -41,7 +41,7 @@ export type PluginConfigValidation = | { ok: true; value?: unknown } | { ok: false; errors: string[] }; -export type MoltbotPluginConfigSchema = { +export type OpenClawPluginConfigSchema = { safeParse?: (value: unknown) => { success: boolean; data?: unknown; @@ -55,8 +55,8 @@ export type MoltbotPluginConfigSchema = { jsonSchema?: Record; }; -export type MoltbotPluginToolContext = { - config?: MoltbotConfig; +export type OpenClawPluginToolContext = { + config?: OpenClawConfig; workspaceDir?: string; agentDir?: string; agentId?: string; @@ -66,17 +66,17 @@ export type MoltbotPluginToolContext = { sandboxed?: boolean; }; -export type MoltbotPluginToolFactory = ( - ctx: MoltbotPluginToolContext, +export type OpenClawPluginToolFactory = ( + ctx: OpenClawPluginToolContext, ) => AnyAgentTool | AnyAgentTool[] | null | undefined; -export type MoltbotPluginToolOptions = { +export type OpenClawPluginToolOptions = { name?: string; names?: string[]; optional?: boolean; }; -export type MoltbotPluginHookOptions = { +export type OpenClawPluginHookOptions = { entry?: HookEntry; name?: string; description?: string; @@ -87,13 +87,13 @@ export type ProviderAuthKind = "oauth" | "api_key" | "token" | "device_code" | " export type ProviderAuthResult = { profiles: Array<{ profileId: string; credential: AuthProfileCredential }>; - configPatch?: Partial; + configPatch?: Partial; defaultModel?: string; notes?: string[]; }; export type ProviderAuthContext = { - config: MoltbotConfig; + config: OpenClawConfig; agentDir?: string; workspaceDir?: string; prompter: WizardPrompter; @@ -125,7 +125,7 @@ export type ProviderPlugin = { refreshOAuth?: (cred: OAuthCredential) => Promise; }; -export type MoltbotPluginGatewayMethod = { +export type OpenClawPluginGatewayMethod = { method: string; handler: GatewayRequestHandler; }; @@ -148,8 +148,8 @@ export type PluginCommandContext = { args?: string; /** The full normalized command body */ commandBody: string; - /** Current moltbot configuration */ - config: MoltbotConfig; + /** Current OpenClaw configuration */ + config: OpenClawConfig; }; /** @@ -167,7 +167,7 @@ export type PluginCommandHandler = ( /** * Definition for a plugin-registered command. */ -export type MoltbotPluginCommandDefinition = { +export type OpenClawPluginCommandDefinition = { /** Command name without leading slash (e.g., "tts") */ name: string; /** Description shown in /help and command menus */ @@ -180,90 +180,90 @@ export type MoltbotPluginCommandDefinition = { handler: PluginCommandHandler; }; -export type MoltbotPluginHttpHandler = ( +export type OpenClawPluginHttpHandler = ( req: IncomingMessage, res: ServerResponse, ) => Promise | boolean; -export type MoltbotPluginHttpRouteHandler = ( +export type OpenClawPluginHttpRouteHandler = ( req: IncomingMessage, res: ServerResponse, ) => Promise | void; -export type MoltbotPluginCliContext = { +export type OpenClawPluginCliContext = { program: Command; - config: MoltbotConfig; + config: OpenClawConfig; workspaceDir?: string; logger: PluginLogger; }; -export type MoltbotPluginCliRegistrar = (ctx: MoltbotPluginCliContext) => void | Promise; +export type OpenClawPluginCliRegistrar = (ctx: OpenClawPluginCliContext) => void | Promise; -export type MoltbotPluginServiceContext = { - config: MoltbotConfig; +export type OpenClawPluginServiceContext = { + config: OpenClawConfig; workspaceDir?: string; stateDir: string; logger: PluginLogger; }; -export type MoltbotPluginService = { +export type OpenClawPluginService = { id: string; - start: (ctx: MoltbotPluginServiceContext) => void | Promise; - stop?: (ctx: MoltbotPluginServiceContext) => void | Promise; + start: (ctx: OpenClawPluginServiceContext) => void | Promise; + stop?: (ctx: OpenClawPluginServiceContext) => void | Promise; }; -export type MoltbotPluginChannelRegistration = { +export type OpenClawPluginChannelRegistration = { plugin: ChannelPlugin; dock?: ChannelDock; }; -export type MoltbotPluginDefinition = { +export type OpenClawPluginDefinition = { id?: string; name?: string; description?: string; version?: string; kind?: PluginKind; - configSchema?: MoltbotPluginConfigSchema; - register?: (api: MoltbotPluginApi) => void | Promise; - activate?: (api: MoltbotPluginApi) => void | Promise; + configSchema?: OpenClawPluginConfigSchema; + register?: (api: OpenClawPluginApi) => void | Promise; + activate?: (api: OpenClawPluginApi) => void | Promise; }; -export type MoltbotPluginModule = - | MoltbotPluginDefinition - | ((api: MoltbotPluginApi) => void | Promise); +export type OpenClawPluginModule = + | OpenClawPluginDefinition + | ((api: OpenClawPluginApi) => void | Promise); -export type MoltbotPluginApi = { +export type OpenClawPluginApi = { id: string; name: string; version?: string; description?: string; source: string; - config: MoltbotConfig; + config: OpenClawConfig; pluginConfig?: Record; runtime: PluginRuntime; logger: PluginLogger; registerTool: ( - tool: AnyAgentTool | MoltbotPluginToolFactory, - opts?: MoltbotPluginToolOptions, + tool: AnyAgentTool | OpenClawPluginToolFactory, + opts?: OpenClawPluginToolOptions, ) => void; registerHook: ( events: string | string[], handler: InternalHookHandler, - opts?: MoltbotPluginHookOptions, + opts?: OpenClawPluginHookOptions, ) => void; - registerHttpHandler: (handler: MoltbotPluginHttpHandler) => void; - registerHttpRoute: (params: { path: string; handler: MoltbotPluginHttpRouteHandler }) => void; - registerChannel: (registration: MoltbotPluginChannelRegistration | ChannelPlugin) => void; + registerHttpHandler: (handler: OpenClawPluginHttpHandler) => void; + registerHttpRoute: (params: { path: string; handler: OpenClawPluginHttpRouteHandler }) => void; + registerChannel: (registration: OpenClawPluginChannelRegistration | ChannelPlugin) => void; registerGatewayMethod: (method: string, handler: GatewayRequestHandler) => void; - registerCli: (registrar: MoltbotPluginCliRegistrar, opts?: { commands?: string[] }) => void; - registerService: (service: MoltbotPluginService) => void; + registerCli: (registrar: OpenClawPluginCliRegistrar, opts?: { commands?: string[] }) => void; + registerService: (service: OpenClawPluginService) => void; registerProvider: (provider: ProviderPlugin) => void; /** * Register a custom command that bypasses the LLM agent. * Plugin commands are processed before built-in commands and before agent invocation. * Use this for simple state-toggling or status commands that don't need AI reasoning. */ - registerCommand: (command: MoltbotPluginCommandDefinition) => void; + registerCommand: (command: OpenClawPluginCommandDefinition) => void; resolvePath: (input: string) => string; /** Register a lifecycle hook handler */ on: ( diff --git a/src/plugins/update.ts b/src/plugins/update.ts index 67ca694c51..caa9630744 100644 --- a/src/plugins/update.ts +++ b/src/plugins/update.ts @@ -1,9 +1,9 @@ import fs from "node:fs/promises"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { UpdateChannel } from "../infra/update-channels.js"; import { resolveUserPath } from "../utils.js"; -import { discoverMoltbotPlugins } from "./discovery.js"; +import { discoverOpenClawPlugins } from "./discovery.js"; import { installPluginFromNpmSpec, resolvePluginInstallDir } from "./install.js"; import { recordPluginInstall } from "./installs.js"; import { loadPluginManifest } from "./manifest.js"; @@ -25,7 +25,7 @@ export type PluginUpdateOutcome = { }; export type PluginUpdateSummary = { - config: MoltbotConfig; + config: OpenClawConfig; changed: boolean; outcomes: PluginUpdateOutcome[]; }; @@ -38,7 +38,7 @@ export type PluginChannelSyncSummary = { }; export type PluginChannelSyncResult = { - config: MoltbotConfig; + config: OpenClawConfig; changed: boolean; summary: PluginChannelSyncSummary; }; @@ -62,7 +62,7 @@ async function readInstalledPackageVersion(dir: string): Promise { - const discovery = discoverMoltbotPlugins({ workspaceDir: params.workspaceDir }); + const discovery = discoverOpenClawPlugins({ workspaceDir: params.workspaceDir }); const bundled = new Map(); for (const candidate of discovery.candidates) { @@ -73,7 +73,7 @@ function resolveBundledPluginSources(params: { if (bundled.has(pluginId)) continue; const npmSpec = - candidate.packageMoltbot?.install?.npmSpec?.trim() || + candidate.packageManifest?.install?.npmSpec?.trim() || candidate.packageName?.trim() || undefined; @@ -127,7 +127,7 @@ function buildLoadPathHelpers(existing: string[]) { } export async function updateNpmInstalledPlugins(params: { - config: MoltbotConfig; + config: OpenClawConfig; logger?: PluginUpdateLogger; pluginIds?: string[]; skipIds?: Set; @@ -290,7 +290,7 @@ export async function updateNpmInstalledPlugins(params: { } export async function syncPluginsForUpdateChannel(params: { - config: MoltbotConfig; + config: OpenClawConfig; channel: UpdateChannel; workspaceDir?: string; logger?: PluginUpdateLogger; diff --git a/src/postinstall-patcher.test.ts b/src/postinstall-patcher.test.ts index 3e46e23652..9e6a2df856 100644 --- a/src/postinstall-patcher.test.ts +++ b/src/postinstall-patcher.test.ts @@ -10,7 +10,7 @@ import { } from "../scripts/postinstall.js"; function makeTempDir() { - return fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-patch-")); + return fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-patch-")); } describe("postinstall patcher", () => { diff --git a/src/process/exec.test.ts b/src/process/exec.test.ts index eeb7cc7a75..7515f60d40 100644 --- a/src/process/exec.test.ts +++ b/src/process/exec.test.ts @@ -5,10 +5,10 @@ import { runCommandWithTimeout } from "./exec.js"; describe("runCommandWithTimeout", () => { it("passes env overrides to child", async () => { const result = await runCommandWithTimeout( - [process.execPath, "-e", 'process.stdout.write(process.env.CLAWDBOT_TEST_ENV ?? "")'], + [process.execPath, "-e", 'process.stdout.write(process.env.OPENCLAW_TEST_ENV ?? "")'], { timeoutMs: 5_000, - env: { CLAWDBOT_TEST_ENV: "ok" }, + env: { OPENCLAW_TEST_ENV: "ok" }, }, ); @@ -17,18 +17,18 @@ describe("runCommandWithTimeout", () => { }); it("merges custom env with process.env", async () => { - const previous = process.env.CLAWDBOT_BASE_ENV; - process.env.CLAWDBOT_BASE_ENV = "base"; + const previous = process.env.OPENCLAW_BASE_ENV; + process.env.OPENCLAW_BASE_ENV = "base"; try { const result = await runCommandWithTimeout( [ process.execPath, "-e", - 'process.stdout.write((process.env.CLAWDBOT_BASE_ENV ?? "") + "|" + (process.env.CLAWDBOT_TEST_ENV ?? ""))', + 'process.stdout.write((process.env.OPENCLAW_BASE_ENV ?? "") + "|" + (process.env.OPENCLAW_TEST_ENV ?? ""))', ], { timeoutMs: 5_000, - env: { CLAWDBOT_TEST_ENV: "ok" }, + env: { OPENCLAW_TEST_ENV: "ok" }, }, ); @@ -36,9 +36,9 @@ describe("runCommandWithTimeout", () => { expect(result.stdout).toBe("base|ok"); } finally { if (previous === undefined) { - delete process.env.CLAWDBOT_BASE_ENV; + delete process.env.OPENCLAW_BASE_ENV; } else { - process.env.CLAWDBOT_BASE_ENV = previous; + process.env.OPENCLAW_BASE_ENV = previous; } } }); diff --git a/src/providers/github-copilot-token.test.ts b/src/providers/github-copilot-token.test.ts index 5ef8acc5e3..04c32c1b65 100644 --- a/src/providers/github-copilot-token.test.ts +++ b/src/providers/github-copilot-token.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const loadJsonFile = vi.fn(); const saveJsonFile = vi.fn(); -const resolveStateDir = vi.fn().mockReturnValue("/tmp/moltbot-state"); +const resolveStateDir = vi.fn().mockReturnValue("/tmp/openclaw-state"); vi.mock("../infra/json-file.js", () => ({ loadJsonFile, @@ -19,7 +19,7 @@ describe("github-copilot token", () => { loadJsonFile.mockReset(); saveJsonFile.mockReset(); resolveStateDir.mockReset(); - resolveStateDir.mockReturnValue("/tmp/moltbot-state"); + resolveStateDir.mockReturnValue("/tmp/openclaw-state"); }); it("derives baseUrl from token", async () => { diff --git a/src/providers/qwen-portal-oauth.ts b/src/providers/qwen-portal-oauth.ts index 9926be289e..bbed888c9f 100644 --- a/src/providers/qwen-portal-oauth.ts +++ b/src/providers/qwen-portal-oauth.ts @@ -29,7 +29,7 @@ export async function refreshQwenPortalCredentials( const text = await response.text(); if (response.status === 400) { throw new Error( - `Qwen OAuth refresh token expired or invalid. Re-authenticate with \`${formatCliCommand("moltbot models auth login --provider qwen-portal")}\`.`, + `Qwen OAuth refresh token expired or invalid. Re-authenticate with \`${formatCliCommand("openclaw models auth login --provider qwen-portal")}\`.`, ); } throw new Error(`Qwen OAuth refresh failed: ${text || response.statusText}`); diff --git a/src/routing/bindings.ts b/src/routing/bindings.ts index 48517528c4..873786b1cd 100644 --- a/src/routing/bindings.ts +++ b/src/routing/bindings.ts @@ -1,6 +1,6 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { normalizeChatChannelId } from "../channels/registry.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { AgentBinding } from "../config/types.agents.js"; import { normalizeAccountId, normalizeAgentId } from "./session-key.js"; @@ -11,11 +11,11 @@ function normalizeBindingChannelId(raw?: string | null): string | null { return fallback || null; } -export function listBindings(cfg: MoltbotConfig): AgentBinding[] { +export function listBindings(cfg: OpenClawConfig): AgentBinding[] { return Array.isArray(cfg.bindings) ? cfg.bindings : []; } -export function listBoundAccountIds(cfg: MoltbotConfig, channelId: string): string[] { +export function listBoundAccountIds(cfg: OpenClawConfig, channelId: string): string[] { const normalizedChannel = normalizeBindingChannelId(channelId); if (!normalizedChannel) return []; const ids = new Set(); @@ -33,7 +33,7 @@ export function listBoundAccountIds(cfg: MoltbotConfig, channelId: string): stri } export function resolveDefaultAgentBoundAccountId( - cfg: MoltbotConfig, + cfg: OpenClawConfig, channelId: string, ): string | null { const normalizedChannel = normalizeBindingChannelId(channelId); @@ -53,7 +53,7 @@ export function resolveDefaultAgentBoundAccountId( return null; } -export function buildChannelAccountBindings(cfg: MoltbotConfig) { +export function buildChannelAccountBindings(cfg: OpenClawConfig) { const map = new Map>(); for (const binding of listBindings(cfg)) { if (!binding || typeof binding !== "object") continue; diff --git a/src/routing/resolve-route.test.ts b/src/routing/resolve-route.test.ts index aed0fa755f..51094e1257 100644 --- a/src/routing/resolve-route.test.ts +++ b/src/routing/resolve-route.test.ts @@ -1,11 +1,11 @@ import { describe, expect, test } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveAgentRoute } from "./resolve-route.js"; describe("resolveAgentRoute", () => { test("defaults to main/default when no bindings exist", () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const route = resolveAgentRoute({ cfg, channel: "whatsapp", @@ -19,7 +19,7 @@ describe("resolveAgentRoute", () => { }); test("dmScope=per-peer isolates DM sessions by sender id", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-peer" }, }; const route = resolveAgentRoute({ @@ -32,7 +32,7 @@ describe("resolveAgentRoute", () => { }); test("dmScope=per-channel-peer isolates DM sessions per channel and sender", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-channel-peer" }, }; const route = resolveAgentRoute({ @@ -45,7 +45,7 @@ describe("resolveAgentRoute", () => { }); test("identityLinks collapses per-peer DM sessions across providers", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-peer", identityLinks: { @@ -63,7 +63,7 @@ describe("resolveAgentRoute", () => { }); test("identityLinks applies to per-channel-peer DM sessions", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-channel-peer", identityLinks: { @@ -81,7 +81,7 @@ describe("resolveAgentRoute", () => { }); test("peer binding wins over account binding", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { bindings: [ { agentId: "a", @@ -109,7 +109,7 @@ describe("resolveAgentRoute", () => { }); test("discord channel peer binding wins over guild binding", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { bindings: [ { agentId: "chan", @@ -142,7 +142,7 @@ describe("resolveAgentRoute", () => { }); test("guild binding wins over account binding when peer not bound", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { bindings: [ { agentId: "guild", @@ -170,7 +170,7 @@ describe("resolveAgentRoute", () => { }); test("missing accountId in binding matches default account only", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { bindings: [{ agentId: "defaultAcct", match: { channel: "whatsapp" } }], }; @@ -193,7 +193,7 @@ describe("resolveAgentRoute", () => { }); test("accountId=* matches any account as a channel fallback", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { bindings: [ { agentId: "any", @@ -212,9 +212,9 @@ describe("resolveAgentRoute", () => { }); test("defaultAgentId is used when no binding matches", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { - list: [{ id: "home", default: true, workspace: "~/clawd-home" }], + list: [{ id: "home", default: true, workspace: "~/openclaw-home" }], }, }; const route = resolveAgentRoute({ @@ -229,7 +229,7 @@ describe("resolveAgentRoute", () => { }); test("dmScope=per-account-channel-peer isolates DM sessions per account, channel and sender", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-account-channel-peer" }, }; const route = resolveAgentRoute({ @@ -242,7 +242,7 @@ test("dmScope=per-account-channel-peer isolates DM sessions per account, channel }); test("dmScope=per-account-channel-peer uses default accountId when not provided", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { session: { dmScope: "per-account-channel-peer" }, }; const route = resolveAgentRoute({ diff --git a/src/routing/resolve-route.ts b/src/routing/resolve-route.ts index 0c63f77c8d..f93e834586 100644 --- a/src/routing/resolve-route.ts +++ b/src/routing/resolve-route.ts @@ -1,5 +1,5 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { listBindings } from "./bindings.js"; import { buildAgentMainSessionKey, @@ -18,7 +18,7 @@ export type RoutePeer = { }; export type ResolveAgentRouteInput = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: string; accountId?: string | null; peer?: RoutePeer | null; @@ -89,12 +89,12 @@ export function buildAgentSessionKey(params: { }); } -function listAgents(cfg: MoltbotConfig) { +function listAgents(cfg: OpenClawConfig) { const agents = cfg.agents?.list; return Array.isArray(agents) ? agents : []; } -function pickFirstExistingAgentId(cfg: MoltbotConfig, agentId: string): string { +function pickFirstExistingAgentId(cfg: OpenClawConfig, agentId: string): string { const trimmed = (agentId ?? "").trim(); if (!trimmed) return sanitizeAgentId(resolveDefaultAgentId(cfg)); const normalized = normalizeAgentId(trimmed); diff --git a/src/scripts/canvas-a2ui-copy.test.ts b/src/scripts/canvas-a2ui-copy.test.ts index a981f81aaf..abf277f67d 100644 --- a/src/scripts/canvas-a2ui-copy.test.ts +++ b/src/scripts/canvas-a2ui-copy.test.ts @@ -8,7 +8,7 @@ import { copyA2uiAssets } from "../../scripts/canvas-a2ui-copy.js"; describe("canvas a2ui copy", () => { it("throws a helpful error when assets are missing", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-a2ui-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-a2ui-")); try { await expect(copyA2uiAssets({ srcDir: dir, outDir: path.join(dir, "out") })).rejects.toThrow( @@ -20,7 +20,7 @@ describe("canvas a2ui copy", () => { }); it("copies bundled assets to dist", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-a2ui-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-a2ui-")); const srcDir = path.join(dir, "src"); const outDir = path.join(dir, "dist"); diff --git a/src/security/audit-extra.ts b/src/security/audit-extra.ts index 3a92a30a8e..05c4ad872e 100644 --- a/src/security/audit-extra.ts +++ b/src/security/audit-extra.ts @@ -3,7 +3,7 @@ import path from "node:path"; import JSON5 from "json5"; -import type { MoltbotConfig, ConfigFileSnapshot } from "../config/config.js"; +import type { OpenClawConfig, ConfigFileSnapshot } from "../config/config.js"; import { createConfigIO } from "../config/config.js"; import { resolveNativeSkillsEnabled } from "../config/commands.js"; import { resolveOAuthDir } from "../config/paths.js"; @@ -48,7 +48,7 @@ function expandTilde(p: string, env: NodeJS.ProcessEnv): string | null { return null; } -function summarizeGroupPolicy(cfg: MoltbotConfig): { +function summarizeGroupPolicy(cfg: OpenClawConfig): { open: number; allowlist: number; other: number; @@ -69,7 +69,7 @@ function summarizeGroupPolicy(cfg: MoltbotConfig): { return { open, allowlist, other }; } -export function collectAttackSurfaceSummaryFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +export function collectAttackSurfaceSummaryFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const group = summarizeGroupPolicy(cfg); const elevated = cfg.tools?.elevated?.enabled !== false; const hooksEnabled = cfg.hooks?.enabled === true; @@ -116,7 +116,7 @@ export function collectSyncedFolderFindings(params: { severity: "warn", title: "State/config path looks like a synced folder", detail: `stateDir=${params.stateDir}, configPath=${params.configPath}. Synced folders (iCloud/Dropbox/OneDrive/Google Drive) can leak tokens and transcripts onto other devices.`, - remediation: `Keep CLAWDBOT_STATE_DIR on a local-only volume and re-run "${formatCliCommand("moltbot security audit --fix")}".`, + remediation: `Keep OPENCLAW_STATE_DIR on a local-only volume and re-run "${formatCliCommand("openclaw security audit --fix")}".`, }); } return findings; @@ -127,7 +127,7 @@ function looksLikeEnvRef(value: string): boolean { return v.startsWith("${") && v.endsWith("}"); } -export function collectSecretsInConfigFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +export function collectSecretsInConfigFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; const password = typeof cfg.gateway?.auth?.password === "string" ? cfg.gateway.auth.password.trim() : ""; @@ -139,7 +139,7 @@ export function collectSecretsInConfigFindings(cfg: MoltbotConfig): SecurityAudi detail: "gateway.auth.password is set in the config file; prefer environment variables for secrets when possible.", remediation: - "Prefer CLAWDBOT_GATEWAY_PASSWORD (env) and remove gateway.auth.password from disk.", + "Prefer OPENCLAW_GATEWAY_PASSWORD (env) and remove gateway.auth.password from disk.", }); } @@ -157,7 +157,7 @@ export function collectSecretsInConfigFindings(cfg: MoltbotConfig): SecurityAudi return findings; } -export function collectHooksHardeningFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +export function collectHooksHardeningFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; if (cfg.hooks?.enabled !== true) return findings; @@ -215,7 +215,7 @@ function addModel(models: ModelRef[], raw: unknown, source: string) { models.push({ id, source }); } -function collectModels(cfg: MoltbotConfig): ModelRef[] { +function collectModels(cfg: OpenClawConfig): ModelRef[] { const out: ModelRef[] = []; addModel(out, cfg.agents?.defaults?.model?.primary, "agents.defaults.model.primary"); for (const f of cfg.agents?.defaults?.model?.fallbacks ?? []) @@ -286,7 +286,7 @@ function isClaude45OrHigher(id: string): boolean { return /\bclaude-[^\s/]*?(?:-4-?5\b|4\.5\b)/i.test(id); } -export function collectModelHygieneFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +export function collectModelHygieneFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; const models = collectModels(cfg); if (models.length === 0) return findings; @@ -381,7 +381,7 @@ function pickToolPolicy(config?: { allow?: string[]; deny?: string[] }): Sandbox } function resolveToolPolicies(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentTools?: AgentToolsConfig; sandboxMode?: "off" | "non-main" | "all"; agentId?: string | null; @@ -405,7 +405,7 @@ function resolveToolPolicies(params: { return policies; } -function hasWebSearchKey(cfg: MoltbotConfig, env: NodeJS.ProcessEnv): boolean { +function hasWebSearchKey(cfg: OpenClawConfig, env: NodeJS.ProcessEnv): boolean { const search = cfg.tools?.web?.search; return Boolean( search?.apiKey || @@ -416,20 +416,20 @@ function hasWebSearchKey(cfg: MoltbotConfig, env: NodeJS.ProcessEnv): boolean { ); } -function isWebSearchEnabled(cfg: MoltbotConfig, env: NodeJS.ProcessEnv): boolean { +function isWebSearchEnabled(cfg: OpenClawConfig, env: NodeJS.ProcessEnv): boolean { const enabled = cfg.tools?.web?.search?.enabled; if (enabled === false) return false; if (enabled === true) return true; return hasWebSearchKey(cfg, env); } -function isWebFetchEnabled(cfg: MoltbotConfig): boolean { +function isWebFetchEnabled(cfg: OpenClawConfig): boolean { const enabled = cfg.tools?.web?.fetch?.enabled; if (enabled === false) return false; return true; } -function isBrowserEnabled(cfg: MoltbotConfig): boolean { +function isBrowserEnabled(cfg: OpenClawConfig): boolean { try { return resolveBrowserConfig(cfg.browser, cfg).enabled; } catch { @@ -438,7 +438,7 @@ function isBrowserEnabled(cfg: MoltbotConfig): boolean { } export function collectSmallModelRiskFindings(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env: NodeJS.ProcessEnv; }): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; @@ -517,7 +517,7 @@ export function collectSmallModelRiskFindings(params: { } export async function collectPluginsTrustFindings(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; stateDir: string; }): Promise { const findings: SecurityAuditFinding[] = []; @@ -750,7 +750,7 @@ export async function collectIncludeFilePermFindings(params: { } export async function collectStateDeepFilesystemFindings(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env: NodeJS.ProcessEnv; stateDir: string; platform?: NodeJS.Platform; @@ -905,7 +905,7 @@ export async function collectStateDeepFilesystemFindings(params: { return findings; } -function listGroupPolicyOpen(cfg: MoltbotConfig): string[] { +function listGroupPolicyOpen(cfg: OpenClawConfig): string[] { const out: string[] = []; const channels = cfg.channels as Record | undefined; if (!channels || typeof channels !== "object") return out; @@ -926,7 +926,7 @@ function listGroupPolicyOpen(cfg: MoltbotConfig): string[] { return out; } -export function collectExposureMatrixFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +export function collectExposureMatrixFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; const openGroups = listGroupPolicyOpen(cfg); if (openGroups.length === 0) return findings; diff --git a/src/security/audit.test.ts b/src/security/audit.test.ts index 40124d39a3..0896e2a4f4 100644 --- a/src/security/audit.test.ts +++ b/src/security/audit.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; import { runSecurityAudit } from "./audit.js"; import { discordPlugin } from "../../extensions/discord/src/channel.js"; @@ -14,7 +14,7 @@ const isWindows = process.platform === "win32"; describe("security audit", () => { it("includes an attack surface summary (info)", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { whatsapp: { groupPolicy: "open" }, telegram: { groupPolicy: "allowlist" } }, tools: { elevated: { enabled: true, allowFrom: { whatsapp: ["+1"] } } }, hooks: { enabled: true }, @@ -35,7 +35,7 @@ describe("security audit", () => { }); it("flags non-loopback bind without auth as critical", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { bind: "lan", auth: {}, @@ -55,7 +55,7 @@ describe("security audit", () => { }); it("warns when loopback control UI lacks trusted proxies", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { bind: "loopback", controlUi: { enabled: true }, @@ -79,7 +79,7 @@ describe("security audit", () => { }); it("flags loopback control UI without auth as critical", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { bind: "loopback", controlUi: { enabled: true }, @@ -105,7 +105,7 @@ describe("security audit", () => { }); it("flags logging.redactSensitive=off", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { logging: { redactSensitive: "off" }, }; @@ -123,10 +123,10 @@ describe("security audit", () => { }); it("treats Windows ACL-only perms as secure", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-win-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-win-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile(configPath, "{}\n", "utf-8"); const user = "DESKTOP-TEST\\Tester"; @@ -160,10 +160,10 @@ describe("security audit", () => { }); it("flags Windows ACLs when Users can read the state dir", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-win-open-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-win-open-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile(configPath, "{}\n", "utf-8"); const user = "DESKTOP-TEST\\Tester"; @@ -200,7 +200,7 @@ describe("security audit", () => { }); it("warns when small models are paired with web/browser tools", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { model: { primary: "ollama/mistral-8b" } } }, tools: { web: { @@ -226,7 +226,7 @@ describe("security audit", () => { }); it("treats small models as safe when sandbox is on and web tools are disabled", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { model: { primary: "ollama/mistral-8b" }, sandbox: { mode: "all" } } }, tools: { web: { @@ -250,7 +250,7 @@ describe("security audit", () => { }); it("flags tools.elevated allowFrom wildcard as critical", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { elevated: { allowFrom: { whatsapp: ["*"] }, @@ -275,7 +275,7 @@ describe("security audit", () => { }); it("warns when remote CDP uses HTTP", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { browser: { profiles: { remote: { cdpUrl: "http://example.com:9222", color: "#0066CC" }, @@ -297,7 +297,7 @@ describe("security audit", () => { }); it("warns when control UI allows insecure auth", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { controlUi: { allowInsecureAuth: true }, }, @@ -320,7 +320,7 @@ describe("security audit", () => { }); it("warns when control UI device auth is disabled", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { controlUi: { dangerouslyDisableDeviceAuth: true }, }, @@ -343,7 +343,7 @@ describe("security audit", () => { }); it("warns when multiple DM senders share the main session", async () => { - const cfg: MoltbotConfig = { session: { dmScope: "main" } }; + const cfg: OpenClawConfig = { session: { dmScope: "main" } }; const plugins: ChannelPlugin[] = [ { id: "whatsapp", @@ -391,12 +391,12 @@ describe("security audit", () => { }); it("flags Discord native commands without a guild user allowlist", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-discord-")); - process.env.CLAWDBOT_STATE_DIR = tmp; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-discord-")); + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { discord: { enabled: true, @@ -429,20 +429,20 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("does not flag Discord slash commands when dm.allowFrom includes a Discord snowflake id", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; const tmp = await fs.mkdtemp( - path.join(os.tmpdir(), "moltbot-security-audit-discord-allowfrom-snowflake-"), + path.join(os.tmpdir(), "openclaw-security-audit-discord-allowfrom-snowflake-"), ); - process.env.CLAWDBOT_STATE_DIR = tmp; + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { discord: { enabled: true, @@ -475,18 +475,18 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("flags Discord slash commands when access-group enforcement is disabled and no users allowlist exists", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-discord-open-")); - process.env.CLAWDBOT_STATE_DIR = tmp; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-discord-open-")); + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { commands: { useAccessGroups: false }, channels: { discord: { @@ -520,18 +520,18 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("flags Slack slash commands without a channel users allowlist", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-slack-")); - process.env.CLAWDBOT_STATE_DIR = tmp; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-slack-")); + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { slack: { enabled: true, @@ -559,18 +559,18 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("flags Slack slash commands when access-group enforcement is disabled", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-slack-open-")); - process.env.CLAWDBOT_STATE_DIR = tmp; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-slack-open-")); + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { commands: { useAccessGroups: false }, channels: { slack: { @@ -599,18 +599,18 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("flags Telegram group commands without a sender allowlist", async () => { - const prevStateDir = process.env.CLAWDBOT_STATE_DIR; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-telegram-")); - process.env.CLAWDBOT_STATE_DIR = tmp; + const prevStateDir = process.env.OPENCLAW_STATE_DIR; + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-telegram-")); + process.env.OPENCLAW_STATE_DIR = tmp; await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { enabled: true, @@ -637,13 +637,13 @@ describe("security audit", () => { ]), ); } finally { - if (prevStateDir == null) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = prevStateDir; + if (prevStateDir == null) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = prevStateDir; } }); it("adds a warning when deep probe fails", async () => { - const cfg: MoltbotConfig = { gateway: { mode: "local" } }; + const cfg: OpenClawConfig = { gateway: { mode: "local" } }; const res = await runSecurityAudit({ config: cfg, @@ -672,7 +672,7 @@ describe("security audit", () => { }); it("adds a warning when deep probe throws", async () => { - const cfg: MoltbotConfig = { gateway: { mode: "local" } }; + const cfg: OpenClawConfig = { gateway: { mode: "local" } }; const res = await runSecurityAudit({ config: cfg, @@ -695,7 +695,7 @@ describe("security audit", () => { }); it("warns on legacy model configuration", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { model: { primary: "openai/gpt-3.5-turbo" } } }, }; @@ -713,7 +713,7 @@ describe("security audit", () => { }); it("warns on weak model tiers", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { model: { primary: "anthropic/claude-haiku-4-5" } } }, }; @@ -732,7 +732,7 @@ describe("security audit", () => { it("does not warn on Venice-style opus-45 model names", async () => { // Venice uses "claude-opus-45" format (no dash between 4 and 5) - const cfg: ClawdbotConfig = { + const cfg: OpenClawConfig = { agents: { defaults: { model: { primary: "venice/claude-opus-45" } } }, }; @@ -748,7 +748,7 @@ describe("security audit", () => { }); it("warns when hooks token looks short", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { hooks: { enabled: true, token: "short" }, }; @@ -766,9 +766,9 @@ describe("security audit", () => { }); it("warns when hooks token reuses the gateway env token", async () => { - const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - process.env.CLAWDBOT_GATEWAY_TOKEN = "shared-gateway-token-1234567890"; - const cfg: MoltbotConfig = { + const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN; + process.env.OPENCLAW_GATEWAY_TOKEN = "shared-gateway-token-1234567890"; + const cfg: OpenClawConfig = { hooks: { enabled: true, token: "shared-gateway-token-1234567890" }, }; @@ -785,20 +785,20 @@ describe("security audit", () => { ]), ); } finally { - if (prevToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; + if (prevToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = prevToken; } }); it("warns when state/config look like a synced folder", async () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const res = await runSecurityAudit({ config: cfg, includeFilesystem: false, includeChannelSecurity: false, - stateDir: "/Users/test/Dropbox/.clawdbot", - configPath: "/Users/test/Dropbox/.clawdbot/moltbot.json", + stateDir: "/Users/test/Dropbox/.openclaw", + configPath: "/Users/test/Dropbox/.openclaw/openclaw.json", }); expect(res.findings).toEqual( @@ -809,7 +809,7 @@ describe("security audit", () => { }); it("flags group/world-readable config include files", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true, mode: 0o700 }); @@ -823,12 +823,12 @@ describe("security audit", () => { await fs.chmod(includePath, 0o644); } - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile(configPath, `{ "$include": "./extra.json5" }\n`, "utf-8"); await fs.chmod(configPath, 0o600); try { - const cfg: MoltbotConfig = { logging: { redactSensitive: "off" } }; + const cfg: OpenClawConfig = { logging: { redactSensitive: "off" } }; const user = "DESKTOP-TEST\\Tester"; const execIcacls = isWindows ? async (_cmd: string, args: string[]) => { @@ -882,7 +882,7 @@ describe("security audit", () => { delete process.env.TELEGRAM_BOT_TOKEN; delete process.env.SLACK_BOT_TOKEN; delete process.env.SLACK_APP_TOKEN; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(path.join(stateDir, "extensions", "some-plugin"), { recursive: true, @@ -890,13 +890,13 @@ describe("security audit", () => { }); try { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; const res = await runSecurityAudit({ config: cfg, includeFilesystem: true, includeChannelSecurity: false, stateDir, - configPath: path.join(stateDir, "moltbot.json"), + configPath: path.join(stateDir, "openclaw.json"), }); expect(res.findings).toEqual( @@ -919,7 +919,7 @@ describe("security audit", () => { it("flags unallowlisted extensions as critical when native skill commands are exposed", async () => { const prevDiscordToken = process.env.DISCORD_BOT_TOKEN; delete process.env.DISCORD_BOT_TOKEN; - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-audit-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(path.join(stateDir, "extensions", "some-plugin"), { recursive: true, @@ -927,7 +927,7 @@ describe("security audit", () => { }); try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { discord: { enabled: true, token: "t" }, }, @@ -937,7 +937,7 @@ describe("security audit", () => { includeFilesystem: true, includeChannelSecurity: false, stateDir, - configPath: path.join(stateDir, "moltbot.json"), + configPath: path.join(stateDir, "openclaw.json"), }); expect(res.findings).toEqual( @@ -955,7 +955,7 @@ describe("security audit", () => { }); it("flags open groupPolicy when tools.elevated is enabled", async () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { tools: { elevated: { enabled: true, allowFrom: { whatsapp: ["+1"] } } }, channels: { whatsapp: { groupPolicy: "open" } }, }; @@ -977,30 +977,30 @@ describe("security audit", () => { }); describe("maybeProbeGateway auth selection", () => { - const originalEnvToken = process.env.CLAWDBOT_GATEWAY_TOKEN; - const originalEnvPassword = process.env.CLAWDBOT_GATEWAY_PASSWORD; + const originalEnvToken = process.env.OPENCLAW_GATEWAY_TOKEN; + const originalEnvPassword = process.env.OPENCLAW_GATEWAY_PASSWORD; beforeEach(() => { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; - delete process.env.CLAWDBOT_GATEWAY_PASSWORD; + delete process.env.OPENCLAW_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_PASSWORD; }); afterEach(() => { if (originalEnvToken == null) { - delete process.env.CLAWDBOT_GATEWAY_TOKEN; + delete process.env.OPENCLAW_GATEWAY_TOKEN; } else { - process.env.CLAWDBOT_GATEWAY_TOKEN = originalEnvToken; + process.env.OPENCLAW_GATEWAY_TOKEN = originalEnvToken; } if (originalEnvPassword == null) { - delete process.env.CLAWDBOT_GATEWAY_PASSWORD; + delete process.env.OPENCLAW_GATEWAY_PASSWORD; } else { - process.env.CLAWDBOT_GATEWAY_PASSWORD = originalEnvPassword; + process.env.OPENCLAW_GATEWAY_PASSWORD = originalEnvPassword; } }); it("uses local auth when gateway.mode is local", async () => { let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "local", auth: { token: "local-token-abc123" }, @@ -1033,9 +1033,9 @@ describe("security audit", () => { }); it("prefers env token over local config token", async () => { - process.env.CLAWDBOT_GATEWAY_TOKEN = "env-token"; + process.env.OPENCLAW_GATEWAY_TOKEN = "env-token"; let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "local", auth: { token: "local-token" }, @@ -1069,7 +1069,7 @@ describe("security audit", () => { it("uses local auth when gateway.mode is undefined (default)", async () => { let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { auth: { token: "default-local-token" }, }, @@ -1102,7 +1102,7 @@ describe("security audit", () => { it("uses remote auth when gateway.mode is remote with URL", async () => { let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "remote", auth: { token: "local-token-should-not-use" }, @@ -1139,9 +1139,9 @@ describe("security audit", () => { }); it("ignores env token when gateway.mode is remote", async () => { - process.env.CLAWDBOT_GATEWAY_TOKEN = "env-token"; + process.env.OPENCLAW_GATEWAY_TOKEN = "env-token"; let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "remote", auth: { token: "local-token-should-not-use" }, @@ -1179,7 +1179,7 @@ describe("security audit", () => { it("uses remote password when env is unset", async () => { let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "remote", remote: { @@ -1215,9 +1215,9 @@ describe("security audit", () => { }); it("prefers env password over remote password", async () => { - process.env.CLAWDBOT_GATEWAY_PASSWORD = "env-pass"; + process.env.OPENCLAW_GATEWAY_PASSWORD = "env-pass"; let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "remote", remote: { @@ -1254,7 +1254,7 @@ describe("security audit", () => { it("falls back to local auth when gateway.mode is remote but URL is missing", async () => { let capturedAuth: { token?: string; password?: string } | undefined; - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { gateway: { mode: "remote", auth: { token: "fallback-local-token" }, diff --git a/src/security/audit.ts b/src/security/audit.ts index 681d14c1d4..e983301e61 100644 --- a/src/security/audit.ts +++ b/src/security/audit.ts @@ -1,7 +1,7 @@ import { listChannelPlugins } from "../channels/plugins/index.js"; import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js"; import type { ChannelId } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveBrowserConfig, resolveProfile } from "../browser/config.js"; import { resolveConfigPath, resolveStateDir } from "../config/paths.js"; import { resolveGatewayAuth } from "../gateway/auth.js"; @@ -62,7 +62,7 @@ export type SecurityAuditReport = { }; export type SecurityAuditOptions = { - config: MoltbotConfig; + config: OpenClawConfig; env?: NodeJS.ProcessEnv; platform?: NodeJS.Platform; deep?: boolean; @@ -145,7 +145,7 @@ async function collectFilesystemFindings(params: { checkId: "fs.state_dir.perms_world_writable", severity: "critical", title: "State dir is world-writable", - detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your Moltbot state.`, + detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your OpenClaw state.`, remediation: formatPermissionRemediation({ targetPath: params.stateDir, perms: stateDirPerms, @@ -159,7 +159,7 @@ async function collectFilesystemFindings(params: { checkId: "fs.state_dir.perms_group_writable", severity: "warn", title: "State dir is group-writable", - detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your Moltbot state.`, + detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your OpenClaw state.`, remediation: formatPermissionRemediation({ targetPath: params.stateDir, perms: stateDirPerms, @@ -248,7 +248,7 @@ async function collectFilesystemFindings(params: { } function collectGatewayConfigFindings( - cfg: MoltbotConfig, + cfg: OpenClawConfig, env: NodeJS.ProcessEnv, ): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; @@ -356,7 +356,7 @@ function collectGatewayConfigFindings( return findings; } -function collectBrowserControlFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +function collectBrowserControlFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; let resolved: ReturnType; @@ -368,7 +368,7 @@ function collectBrowserControlFindings(cfg: MoltbotConfig): SecurityAuditFinding severity: "warn", title: "Browser control config looks invalid", detail: String(err), - remediation: `Fix browser.cdpUrl in ${resolveConfigPath()} and re-run "${formatCliCommand("moltbot security audit --deep")}".`, + remediation: `Fix browser.cdpUrl in ${resolveConfigPath()} and re-run "${formatCliCommand("openclaw security audit --deep")}".`, }); return findings; } @@ -398,7 +398,7 @@ function collectBrowserControlFindings(cfg: MoltbotConfig): SecurityAuditFinding return findings; } -function collectLoggingFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +function collectLoggingFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const redact = cfg.logging?.redactSensitive; if (redact !== "off") return []; return [ @@ -412,7 +412,7 @@ function collectLoggingFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { ]; } -function collectElevatedFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { +function collectElevatedFindings(cfg: OpenClawConfig): SecurityAuditFinding[] { const findings: SecurityAuditFinding[] = []; const enabled = cfg.tools?.elevated?.enabled; const allowFrom = cfg.tools?.elevated?.allowFrom ?? {}; @@ -444,7 +444,7 @@ function collectElevatedFindings(cfg: MoltbotConfig): SecurityAuditFinding[] { } async function collectChannelSecurityFindings(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; plugins: ReturnType; }): Promise { const findings: SecurityAuditFinding[] = []; @@ -798,7 +798,7 @@ async function collectChannelSecurityFindings(params: { } async function maybeProbeGateway(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; timeoutMs: number; probe: typeof probeGateway; }): Promise { @@ -818,10 +818,10 @@ async function maybeProbeGateway(params: { ? typeof remote?.token === "string" && remote.token.trim() ? remote.token.trim() : undefined - : process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || + : process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || (typeof authToken === "string" && authToken.trim() ? authToken.trim() : undefined); const password = - process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || + process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || (mode === "remote" ? typeof remote?.password === "string" && remote.password.trim() ? remote.password.trim() @@ -924,7 +924,7 @@ export async function runSecurityAudit(opts: SecurityAuditOptions): Promise { describe("security fix", () => { it("tightens groupPolicy + filesystem perms", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-fix-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-fix-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); await fs.chmod(stateDir, 0o755); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile( configPath, `${JSON.stringify( @@ -54,8 +54,8 @@ describe("security fix", () => { const env = { ...process.env, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_CONFIG_PATH: "", + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_CONFIG_PATH: "", }; const res = await fixSecurityFootguns({ env }); @@ -90,11 +90,11 @@ describe("security fix", () => { }); it("applies allowlist per-account and seeds WhatsApp groupAllowFrom from store", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-fix-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-fix-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile( configPath, `${JSON.stringify( @@ -123,8 +123,8 @@ describe("security fix", () => { const env = { ...process.env, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_CONFIG_PATH: "", + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_CONFIG_PATH: "", }; const res = await fixSecurityFootguns({ env }); @@ -140,11 +140,11 @@ describe("security fix", () => { }); it("does not seed WhatsApp groupAllowFrom if allowFrom is set", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-fix-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-fix-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile( configPath, `${JSON.stringify( @@ -169,8 +169,8 @@ describe("security fix", () => { const env = { ...process.env, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_CONFIG_PATH: "", + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_CONFIG_PATH: "", }; const res = await fixSecurityFootguns({ env }); @@ -183,19 +183,19 @@ describe("security fix", () => { }); it("returns ok=false for invalid config but still tightens perms", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-fix-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-fix-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); await fs.chmod(stateDir, 0o755); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile(configPath, "{ this is not json }\n", "utf-8"); await fs.chmod(configPath, 0o644); const env = { ...process.env, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_CONFIG_PATH: "", + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_CONFIG_PATH: "", }; const res = await fixSecurityFootguns({ env }); @@ -209,7 +209,7 @@ describe("security fix", () => { }); it("tightens perms for credentials + agent auth/sessions + include files", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-security-fix-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-fix-")); const stateDir = path.join(tmp, "state"); await fs.mkdir(stateDir, { recursive: true }); @@ -219,7 +219,7 @@ describe("security fix", () => { await fs.writeFile(includePath, "{ logging: { redactSensitive: 'off' } }\n", "utf-8"); await fs.chmod(includePath, 0o644); - const configPath = path.join(stateDir, "moltbot.json"); + const configPath = path.join(stateDir, "openclaw.json"); await fs.writeFile( configPath, `{ "$include": "./includes/extra.json5", channels: { whatsapp: { groupPolicy: "open" } } }\n`, @@ -251,8 +251,8 @@ describe("security fix", () => { const env = { ...process.env, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_CONFIG_PATH: "", + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_CONFIG_PATH: "", }; const res = await fixSecurityFootguns({ env }); diff --git a/src/security/fix.ts b/src/security/fix.ts index 6f7ab00224..3febd89547 100644 --- a/src/security/fix.ts +++ b/src/security/fix.ts @@ -3,7 +3,7 @@ import path from "node:path"; import JSON5 from "json5"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { createConfigIO } from "../config/config.js"; import { resolveConfigPath, resolveOAuthDir, resolveStateDir } from "../config/paths.js"; import { resolveDefaultAgentId } from "../agents/agent-scope.js"; @@ -187,13 +187,13 @@ async function safeAclReset(params: { } function setGroupPolicyAllowlist(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel: string; changes: string[]; policyFlips: Set; }): void { if (!params.cfg.channels) return; - const section = params.cfg.channels[params.channel as keyof MoltbotConfig["channels"]] as + const section = params.cfg.channels[params.channel as keyof OpenClawConfig["channels"]] as | Record | undefined; if (!section || typeof section !== "object") return; @@ -222,7 +222,7 @@ function setGroupPolicyAllowlist(params: { } function setWhatsAppGroupAllowFromFromStore(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; storeAllowFrom: string[]; changes: string[]; policyFlips: Set; @@ -252,8 +252,8 @@ function setWhatsAppGroupAllowFromFromStore(params: { } } -function applyConfigFixes(params: { cfg: MoltbotConfig; env: NodeJS.ProcessEnv }): { - cfg: MoltbotConfig; +function applyConfigFixes(params: { cfg: OpenClawConfig; env: NodeJS.ProcessEnv }): { + cfg: OpenClawConfig; changes: string[]; policyFlips: Set; } { @@ -349,7 +349,7 @@ async function collectIncludePathsRecursive(params: { async function chmodCredentialsAndAgentState(params: { env: NodeJS.ProcessEnv; stateDir: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; actions: SecurityFixAction[]; applyPerms: (params: { path: string; diff --git a/src/sessions/send-policy.test.ts b/src/sessions/send-policy.test.ts index 2778e450f9..ed01e2d532 100644 --- a/src/sessions/send-policy.test.ts +++ b/src/sessions/send-policy.test.ts @@ -1,18 +1,18 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { resolveSendPolicy } from "./send-policy.js"; describe("resolveSendPolicy", () => { it("defaults to allow", () => { - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; expect(resolveSendPolicy({ cfg })).toBe("allow"); }); it("entry override wins", () => { const cfg = { session: { sendPolicy: { default: "allow" } }, - } as MoltbotConfig; + } as OpenClawConfig; const entry: SessionEntry = { sessionId: "s", updatedAt: 0, @@ -34,7 +34,7 @@ describe("resolveSendPolicy", () => { ], }, }, - } as MoltbotConfig; + } as OpenClawConfig; const entry: SessionEntry = { sessionId: "s", updatedAt: 0, @@ -52,7 +52,7 @@ describe("resolveSendPolicy", () => { rules: [{ action: "deny", match: { keyPrefix: "cron:" } }], }, }, - } as MoltbotConfig; + } as OpenClawConfig; expect(resolveSendPolicy({ cfg, sessionKey: "cron:job-1" })).toBe("deny"); }); }); diff --git a/src/sessions/send-policy.ts b/src/sessions/send-policy.ts index fcaf2250f7..a71e890c4f 100644 --- a/src/sessions/send-policy.ts +++ b/src/sessions/send-policy.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SessionChatType, SessionEntry } from "../config/sessions.js"; import { normalizeChatType } from "../channels/chat-type.js"; @@ -33,7 +33,7 @@ function deriveChatTypeFromKey(key?: string): SessionChatType | undefined { } export function resolveSendPolicy(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; entry?: SessionEntry; sessionKey?: string; channel?: string; diff --git a/src/signal/accounts.ts b/src/signal/accounts.ts index f17d51735a..08f6f37476 100644 --- a/src/signal/accounts.ts +++ b/src/signal/accounts.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SignalAccountConfig } from "../config/types.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; @@ -11,26 +11,26 @@ export type ResolvedSignalAccount = { config: SignalAccountConfig; }; -function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { +function listConfiguredAccountIds(cfg: OpenClawConfig): string[] { const accounts = cfg.channels?.signal?.accounts; if (!accounts || typeof accounts !== "object") return []; return Object.keys(accounts).filter(Boolean); } -export function listSignalAccountIds(cfg: MoltbotConfig): string[] { +export function listSignalAccountIds(cfg: OpenClawConfig): string[] { const ids = listConfiguredAccountIds(cfg); if (ids.length === 0) return [DEFAULT_ACCOUNT_ID]; return ids.sort((a, b) => a.localeCompare(b)); } -export function resolveDefaultSignalAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultSignalAccountId(cfg: OpenClawConfig): string { const ids = listSignalAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID; return ids[0] ?? DEFAULT_ACCOUNT_ID; } function resolveAccountConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId: string, ): SignalAccountConfig | undefined { const accounts = cfg.channels?.signal?.accounts; @@ -38,7 +38,7 @@ function resolveAccountConfig( return accounts[accountId] as SignalAccountConfig | undefined; } -function mergeSignalAccountConfig(cfg: MoltbotConfig, accountId: string): SignalAccountConfig { +function mergeSignalAccountConfig(cfg: OpenClawConfig, accountId: string): SignalAccountConfig { const { accounts: _ignored, ...base } = (cfg.channels?.signal ?? {}) as SignalAccountConfig & { accounts?: unknown; }; @@ -47,7 +47,7 @@ function mergeSignalAccountConfig(cfg: MoltbotConfig, accountId: string): Signal } export function resolveSignalAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): ResolvedSignalAccount { const accountId = normalizeAccountId(params.accountId); @@ -76,7 +76,7 @@ export function resolveSignalAccount(params: { }; } -export function listEnabledSignalAccounts(cfg: MoltbotConfig): ResolvedSignalAccount[] { +export function listEnabledSignalAccounts(cfg: OpenClawConfig): ResolvedSignalAccount[] { return listSignalAccountIds(cfg) .map((accountId) => resolveSignalAccount({ cfg, accountId })) .filter((account) => account.enabled); diff --git a/src/signal/monitor.event-handler.sender-prefix.test.ts b/src/signal/monitor.event-handler.sender-prefix.test.ts index bf8ee71365..c53340918f 100644 --- a/src/signal/monitor.event-handler.sender-prefix.test.ts +++ b/src/signal/monitor.event-handler.sender-prefix.test.ts @@ -39,7 +39,7 @@ describe("signal event handler sender prefix", () => { }, }, cfg: { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { signal: {} }, } as never, baseUrl: "http://localhost", diff --git a/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts b/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts index 68b3eebe73..489b6a8670 100644 --- a/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts +++ b/src/signal/monitor.tool-result.pairs-uuid-only-senders-uuid-allowlist-entry.test.ts @@ -35,7 +35,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), readSessionUpdatedAt: vi.fn(() => undefined), recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined), diff --git a/src/signal/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts b/src/signal/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts index 5d27605136..a8d55db668 100644 --- a/src/signal/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts +++ b/src/signal/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { peekSystemEvents, resetSystemEventsForTest } from "../infra/system-events.js"; import { resolveAgentRoute } from "../routing/resolve-route.js"; import { normalizeE164 } from "../utils.js"; @@ -39,7 +39,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), readSessionUpdatedAt: vi.fn(() => undefined), recordSessionMetaFromInbound: vi.fn().mockResolvedValue(undefined), @@ -412,7 +412,7 @@ describe("monitorSignalProvider tool results", () => { await flush(); const route = resolveAgentRoute({ - cfg: config as MoltbotConfig, + cfg: config as OpenClawConfig, channel: "signal", accountId: "default", peer: { kind: "dm", id: normalizeE164("+15550001111") }, @@ -468,7 +468,7 @@ describe("monitorSignalProvider tool results", () => { await flush(); const route = resolveAgentRoute({ - cfg: config as MoltbotConfig, + cfg: config as OpenClawConfig, channel: "signal", accountId: "default", peer: { kind: "dm", id: normalizeE164("+15550001111") }, diff --git a/src/signal/monitor.ts b/src/signal/monitor.ts index e143fdac6d..fee510d022 100644 --- a/src/signal/monitor.ts +++ b/src/signal/monitor.ts @@ -1,7 +1,7 @@ import { chunkTextWithMode, resolveChunkMode, resolveTextChunkLimit } from "../auto-reply/chunk.js"; import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "../auto-reply/reply/history.js"; import type { ReplyPayload } from "../auto-reply/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import type { SignalReactionNotificationMode } from "../config/types.js"; import { saveMediaBuffer } from "../media/store.js"; @@ -40,7 +40,7 @@ export type MonitorSignalOpts = { abortSignal?: AbortSignal; account?: string; accountId?: string; - config?: MoltbotConfig; + config?: OpenClawConfig; baseUrl?: string; autoStart?: boolean; startupTimeoutMs?: number; diff --git a/src/signal/monitor/event-handler.types.ts b/src/signal/monitor/event-handler.types.ts index 1ee0a039ee..34b26d876d 100644 --- a/src/signal/monitor/event-handler.types.ts +++ b/src/signal/monitor/event-handler.types.ts @@ -1,6 +1,6 @@ import type { HistoryEntry } from "../../auto-reply/reply/history.js"; import type { ReplyPayload } from "../../auto-reply/types.js"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import type { DmPolicy, GroupPolicy, SignalReactionNotificationMode } from "../../config/types.js"; import type { RuntimeEnv } from "../../runtime.js"; import type { SignalSender } from "../identity.js"; @@ -60,7 +60,7 @@ export type SignalReceivePayload = { export type SignalEventHandlerDeps = { runtime: RuntimeEnv; - cfg: MoltbotConfig; + cfg: OpenClawConfig; baseUrl: string; account?: string; accountId: string; diff --git a/src/signal/reaction-level.ts b/src/signal/reaction-level.ts index 5cc6aac830..5aa14b3749 100644 --- a/src/signal/reaction-level.ts +++ b/src/signal/reaction-level.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveSignalAccount } from "./accounts.js"; export type SignalReactionLevel = "off" | "ack" | "minimal" | "extensive"; @@ -23,7 +23,7 @@ export type ResolvedSignalReactionLevel = { * - "extensive": Agent can react liberally */ export function resolveSignalReactionLevel(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string; }): ResolvedSignalReactionLevel { const account = resolveSignalAccount({ diff --git a/src/slack/accounts.ts b/src/slack/accounts.ts index 1ae42b5aaa..a2696a0641 100644 --- a/src/slack/accounts.ts +++ b/src/slack/accounts.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SlackAccountConfig } from "../config/types.js"; import { normalizeChatType } from "../channels/chat-type.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; @@ -28,26 +28,26 @@ export type ResolvedSlackAccount = { channels?: SlackAccountConfig["channels"]; }; -function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { +function listConfiguredAccountIds(cfg: OpenClawConfig): string[] { const accounts = cfg.channels?.slack?.accounts; if (!accounts || typeof accounts !== "object") return []; return Object.keys(accounts).filter(Boolean); } -export function listSlackAccountIds(cfg: MoltbotConfig): string[] { +export function listSlackAccountIds(cfg: OpenClawConfig): string[] { const ids = listConfiguredAccountIds(cfg); if (ids.length === 0) return [DEFAULT_ACCOUNT_ID]; return ids.sort((a, b) => a.localeCompare(b)); } -export function resolveDefaultSlackAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultSlackAccountId(cfg: OpenClawConfig): string { const ids = listSlackAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID; return ids[0] ?? DEFAULT_ACCOUNT_ID; } function resolveAccountConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId: string, ): SlackAccountConfig | undefined { const accounts = cfg.channels?.slack?.accounts; @@ -55,7 +55,7 @@ function resolveAccountConfig( return accounts[accountId] as SlackAccountConfig | undefined; } -function mergeSlackAccountConfig(cfg: MoltbotConfig, accountId: string): SlackAccountConfig { +function mergeSlackAccountConfig(cfg: OpenClawConfig, accountId: string): SlackAccountConfig { const { accounts: _ignored, ...base } = (cfg.channels?.slack ?? {}) as SlackAccountConfig & { accounts?: unknown; }; @@ -64,7 +64,7 @@ function mergeSlackAccountConfig(cfg: MoltbotConfig, accountId: string): SlackAc } export function resolveSlackAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): ResolvedSlackAccount { const accountId = normalizeAccountId(params.accountId); @@ -105,7 +105,7 @@ export function resolveSlackAccount(params: { }; } -export function listEnabledSlackAccounts(cfg: MoltbotConfig): ResolvedSlackAccount[] { +export function listEnabledSlackAccounts(cfg: OpenClawConfig): ResolvedSlackAccount[] { return listSlackAccountIds(cfg) .map((accountId) => resolveSlackAccount({ cfg, accountId })) .filter((account) => account.enabled); diff --git a/src/slack/channel-migration.ts b/src/slack/channel-migration.ts index c277696112..78bc510f5c 100644 --- a/src/slack/channel-migration.ts +++ b/src/slack/channel-migration.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { SlackChannelConfig } from "../config/types.slack.js"; import { normalizeAccountId } from "../routing/session-key.js"; @@ -13,7 +13,7 @@ export type SlackChannelMigrationResult = { }; function resolveAccountChannels( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId?: string | null, ): { channels?: SlackChannels } { if (!accountId) return {}; @@ -43,7 +43,7 @@ export function migrateSlackChannelsInPlace( } export function migrateSlackChannelConfig(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; oldChannelId: string; newChannelId: string; diff --git a/src/slack/monitor.test-helpers.ts b/src/slack/monitor.test-helpers.ts index b81e80b12a..8d37bd9363 100644 --- a/src/slack/monitor.test-helpers.ts +++ b/src/slack/monitor.test-helpers.ts @@ -94,7 +94,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => slackTestState.updateLastRouteMock(...args), resolveSessionKey: vi.fn(), readSessionUpdatedAt: vi.fn(() => undefined), diff --git a/src/slack/monitor.test.ts b/src/slack/monitor.test.ts index e4aa581920..58d3353493 100644 --- a/src/slack/monitor.test.ts +++ b/src/slack/monitor.test.ts @@ -159,16 +159,16 @@ describe("resolveSlackThreadTs", () => { describe("buildSlackSlashCommandMatcher", () => { it("matches with or without a leading slash", () => { - const matcher = buildSlackSlashCommandMatcher("clawd"); + const matcher = buildSlackSlashCommandMatcher("openclaw"); - expect(matcher.test("clawd")).toBe(true); - expect(matcher.test("/clawd")).toBe(true); + expect(matcher.test("openclaw")).toBe(true); + expect(matcher.test("/openclaw")).toBe(true); }); it("does not match similar names", () => { - const matcher = buildSlackSlashCommandMatcher("clawd"); + const matcher = buildSlackSlashCommandMatcher("openclaw"); - expect(matcher.test("/clawd-bot")).toBe(false); - expect(matcher.test("clawd-bot")).toBe(false); + expect(matcher.test("/openclaw-bot")).toBe(false); + expect(matcher.test("openclaw-bot")).toBe(false); }); }); diff --git a/src/slack/monitor.threading.missing-thread-ts.test.ts b/src/slack/monitor.threading.missing-thread-ts.test.ts index de75b993e8..8c0454b3ae 100644 --- a/src/slack/monitor.threading.missing-thread-ts.test.ts +++ b/src/slack/monitor.threading.missing-thread-ts.test.ts @@ -51,7 +51,7 @@ vi.mock("../pairing/pairing-store.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/moltbot-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), resolveSessionKey: vi.fn(), readSessionUpdatedAt: vi.fn(() => undefined), diff --git a/src/slack/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts b/src/slack/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts index 4481d75898..4bcaa9e35c 100644 --- a/src/slack/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts +++ b/src/slack/monitor.tool-result.sends-tool-summaries-responseprefix.test.ts @@ -351,7 +351,7 @@ describe("monitorSlackProvider tool results", () => { slackTestState.config = { messages: { responsePrefix: "PFX", - groupChat: { mentionPatterns: ["\\bclawd\\b"] }, + groupChat: { mentionPatterns: ["\\bopenclaw\\b"] }, }, channels: { slack: { @@ -377,7 +377,7 @@ describe("monitorSlackProvider tool results", () => { event: { type: "message", user: "U1", - text: "clawd: hello", + text: "openclaw: hello", ts: "123", channel: "C1", channel_type: "channel", @@ -396,7 +396,7 @@ describe("monitorSlackProvider tool results", () => { slackTestState.config = { messages: { responsePrefix: "PFX", - groupChat: { mentionPatterns: ["\\bclawd\\b"] }, + groupChat: { mentionPatterns: ["\\bopenclaw\\b"] }, }, channels: { slack: { @@ -422,7 +422,7 @@ describe("monitorSlackProvider tool results", () => { event: { type: "message", user: "U1", - text: "clawd: hello <@U2>", + text: "openclaw: hello <@U2>", ts: "123", channel: "C1", channel_type: "channel", diff --git a/src/slack/monitor/commands.ts b/src/slack/monitor/commands.ts index 8c738410eb..f26be177d1 100644 --- a/src/slack/monitor/commands.ts +++ b/src/slack/monitor/commands.ts @@ -7,8 +7,8 @@ export function normalizeSlackSlashCommandName(raw: string) { export function resolveSlackSlashCommandConfig( raw?: SlackSlashCommandConfig, ): Required { - const normalizedName = normalizeSlackSlashCommandName(raw?.name?.trim() || "clawd"); - const name = normalizedName || "clawd"; + const normalizedName = normalizeSlackSlashCommandName(raw?.name?.trim() || "openclaw"); + const name = normalizedName || "openclaw"; return { enabled: raw?.enabled === true, name, @@ -18,6 +18,7 @@ export function resolveSlackSlashCommandConfig( } export function buildSlackSlashCommandMatcher(name: string) { - const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const normalized = normalizeSlackSlashCommandName(name); + const escaped = normalized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return new RegExp(`^/?${escaped}$`); } diff --git a/src/slack/monitor/context.test.ts b/src/slack/monitor/context.test.ts index 1d6f5ec62d..87b1fe425e 100644 --- a/src/slack/monitor/context.test.ts +++ b/src/slack/monitor/context.test.ts @@ -1,12 +1,12 @@ import type { App } from "@slack/bolt"; import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import type { RuntimeEnv } from "../../runtime.js"; import { createSlackMonitorContext, normalizeSlackChannelType } from "./context.js"; const baseParams = () => ({ - cfg: {} as MoltbotConfig, + cfg: {} as OpenClawConfig, accountId: "default", botToken: "token", app: { client: {} } as App, @@ -30,7 +30,7 @@ const baseParams = () => ({ replyToMode: "off" as const, slashCommand: { enabled: false, - name: "clawd", + name: "openclaw", sessionPrefix: "slack:slash", ephemeral: true, }, diff --git a/src/slack/monitor/context.ts b/src/slack/monitor/context.ts index 876c22ae66..f74592a106 100644 --- a/src/slack/monitor/context.ts +++ b/src/slack/monitor/context.ts @@ -1,6 +1,6 @@ import type { App } from "@slack/bolt"; import type { HistoryEntry } from "../../auto-reply/reply/history.js"; -import type { MoltbotConfig, SlackReactionNotificationMode } from "../../config/config.js"; +import type { OpenClawConfig, SlackReactionNotificationMode } from "../../config/config.js"; import { resolveSessionKey, type SessionScope } from "../../config/sessions.js"; import type { DmPolicy, GroupPolicy } from "../../config/types.js"; import { logVerbose } from "../../globals.js"; @@ -42,7 +42,7 @@ export function normalizeSlackChannelType( } export type SlackMonitorContext = { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId: string; botToken: string; app: App; @@ -115,7 +115,7 @@ export type SlackMonitorContext = { }; export function createSlackMonitorContext(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId: string; botToken: string; app: App; diff --git a/src/slack/monitor/message-handler/prepare.inbound-contract.test.ts b/src/slack/monitor/message-handler/prepare.inbound-contract.test.ts index 7141dec72c..1a614d6c58 100644 --- a/src/slack/monitor/message-handler/prepare.inbound-contract.test.ts +++ b/src/slack/monitor/message-handler/prepare.inbound-contract.test.ts @@ -1,7 +1,7 @@ import type { App } from "@slack/bolt"; import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/config.js"; import type { RuntimeEnv } from "../../../runtime.js"; import { expectInboundContextContract } from "../../../../test/helpers/inbound-contract.js"; import type { ResolvedSlackAccount } from "../../accounts.js"; @@ -14,7 +14,7 @@ describe("slack prepareSlackMessage inbound contract", () => { const slackCtx = createSlackMonitorContext({ cfg: { channels: { slack: { enabled: true } }, - } as MoltbotConfig, + } as OpenClawConfig, accountId: "default", botToken: "token", app: { client: {} } as App, @@ -40,7 +40,7 @@ describe("slack prepareSlackMessage inbound contract", () => { threadInheritParent: false, slashCommand: { enabled: false, - name: "clawd", + name: "openclaw", sessionPrefix: "slack:slash", ephemeral: true, }, @@ -82,7 +82,7 @@ describe("slack prepareSlackMessage inbound contract", () => { const slackCtx = createSlackMonitorContext({ cfg: { channels: { slack: { enabled: true, replyToMode: "all" } }, - } as MoltbotConfig, + } as OpenClawConfig, accountId: "default", botToken: "token", app: { client: {} } as App, @@ -108,7 +108,7 @@ describe("slack prepareSlackMessage inbound contract", () => { threadInheritParent: false, slashCommand: { enabled: false, - name: "clawd", + name: "openclaw", sessionPrefix: "slack:slash", ephemeral: true, }, diff --git a/src/slack/monitor/message-handler/prepare.sender-prefix.test.ts b/src/slack/monitor/message-handler/prepare.sender-prefix.test.ts index e0f51f4472..f7aa2df526 100644 --- a/src/slack/monitor/message-handler/prepare.sender-prefix.test.ts +++ b/src/slack/monitor/message-handler/prepare.sender-prefix.test.ts @@ -7,7 +7,7 @@ describe("prepareSlackMessage sender prefix", () => { it("prefixes channel bodies with sender label", async () => { const ctx = { cfg: { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { slack: {} }, }, accountId: "default", @@ -40,7 +40,7 @@ describe("prepareSlackMessage sender prefix", () => { replyToMode: "off", threadHistoryScope: "channel", threadInheritParent: false, - slashCommand: { command: "/clawd", enabled: true }, + slashCommand: { command: "/openclaw", enabled: true }, textLimit: 2000, ackReactionScope: "off", mediaMaxBytes: 1000, diff --git a/src/slack/monitor/slash.command-arg-menus.test.ts b/src/slack/monitor/slash.command-arg-menus.test.ts index b7b5011f0e..641045ee45 100644 --- a/src/slack/monitor/slash.command-arg-menus.test.ts +++ b/src/slack/monitor/slash.command-arg-menus.test.ts @@ -68,7 +68,12 @@ function createHarness() { groupPolicy: "open", useAccessGroups: false, channelsConfig: undefined, - slashCommand: { enabled: true, name: "clawd", ephemeral: true, sessionPrefix: "slack:slash" }, + slashCommand: { + enabled: true, + name: "openclaw", + ephemeral: true, + sessionPrefix: "slack:slash", + }, textLimit: 4000, app, isChannelAllowed: () => true, @@ -126,7 +131,7 @@ describe("Slack native command argument menus", () => { const { actions, ctx, account } = createHarness(); registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never }); - const handler = actions.get("moltbot_cmdarg"); + const handler = actions.get("openclaw_cmdarg"); if (!handler) throw new Error("Missing arg-menu action handler"); const respond = vi.fn().mockResolvedValue(undefined); @@ -152,7 +157,7 @@ describe("Slack native command argument menus", () => { const { actions, ctx, account } = createHarness(); registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never }); - const handler = actions.get("moltbot_cmdarg"); + const handler = actions.get("openclaw_cmdarg"); if (!handler) throw new Error("Missing arg-menu action handler"); const respond = vi.fn().mockResolvedValue(undefined); @@ -180,7 +185,7 @@ describe("Slack native command argument menus", () => { const { actions, postEphemeral, ctx, account } = createHarness(); registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never }); - const handler = actions.get("moltbot_cmdarg"); + const handler = actions.get("openclaw_cmdarg"); if (!handler) throw new Error("Missing arg-menu action handler"); await handler({ @@ -202,7 +207,7 @@ describe("Slack native command argument menus", () => { const { actions, postEphemeral, ctx, account } = createHarness(); registerSlackMonitorSlashCommands({ ctx: ctx as never, account: account as never }); - const handler = actions.get("moltbot_cmdarg"); + const handler = actions.get("openclaw_cmdarg"); if (!handler) throw new Error("Missing arg-menu action handler"); await handler({ diff --git a/src/slack/monitor/slash.policy.test.ts b/src/slack/monitor/slash.policy.test.ts index 182e7a0152..7cf7430fcc 100644 --- a/src/slack/monitor/slash.policy.test.ts +++ b/src/slack/monitor/slash.policy.test.ts @@ -61,7 +61,12 @@ function createHarness(overrides?: { groupPolicy: overrides?.groupPolicy ?? "open", useAccessGroups: true, channelsConfig: overrides?.channelsConfig, - slashCommand: { enabled: true, name: "clawd", ephemeral: true, sessionPrefix: "slack:slash" }, + slashCommand: { + enabled: true, + name: "openclaw", + ephemeral: true, + sessionPrefix: "slack:slash", + }, textLimit: 4000, app, isChannelAllowed: () => true, diff --git a/src/slack/monitor/slash.ts b/src/slack/monitor/slash.ts index 3534561ab6..3b2c3680f8 100644 --- a/src/slack/monitor/slash.ts +++ b/src/slack/monitor/slash.ts @@ -41,7 +41,7 @@ import { deliverSlackSlashReplies } from "./replies.js"; type SlackBlock = { type: string; [key: string]: unknown }; -const SLACK_COMMAND_ARG_ACTION_ID = "moltbot_cmdarg"; +const SLACK_COMMAND_ARG_ACTION_ID = "openclaw_cmdarg"; const SLACK_COMMAND_ARG_VALUE_PREFIX = "cmdarg"; function chunkItems(items: T[], size: number): T[][] { @@ -528,68 +528,73 @@ export function registerSlackMonitorSlashCommands(params: { if (nativeCommands.length === 0 || !supportsInteractiveArgMenus) return; - ( - ctx.app as unknown as { action: NonNullable<(typeof ctx.app & { action?: unknown })["action"]> } - ).action(SLACK_COMMAND_ARG_ACTION_ID, async (args: SlackActionMiddlewareArgs) => { - const { ack, body, respond } = args; - const action = args.action as { value?: string }; - await ack(); - const respondFn = - respond ?? - (async (payload: { text: string; blocks?: SlackBlock[]; response_type?: string }) => { - if (!body.channel?.id || !body.user?.id) return; - await ctx.app.client.chat.postEphemeral({ - token: ctx.botToken, - channel: body.channel.id, - user: body.user.id, - text: payload.text, - blocks: payload.blocks, + const registerArgAction = (actionId: string) => { + ( + ctx.app as unknown as { + action: NonNullable<(typeof ctx.app & { action?: unknown })["action"]>; + } + ).action(actionId, async (args: SlackActionMiddlewareArgs) => { + const { ack, body, respond } = args; + const action = args.action as { value?: string }; + await ack(); + const respondFn = + respond ?? + (async (payload: { text: string; blocks?: SlackBlock[]; response_type?: string }) => { + if (!body.channel?.id || !body.user?.id) return; + await ctx.app.client.chat.postEphemeral({ + token: ctx.botToken, + channel: body.channel.id, + user: body.user.id, + text: payload.text, + blocks: payload.blocks, + }); }); + const parsed = parseSlackCommandArgValue(action?.value); + if (!parsed) { + await respondFn({ + text: "Sorry, that button is no longer valid.", + response_type: "ephemeral", + }); + return; + } + if (body.user?.id && parsed.userId !== body.user.id) { + await respondFn({ + text: "That menu is for another user.", + response_type: "ephemeral", + }); + return; + } + const commandDefinition = findCommandByNativeName(parsed.command, "slack"); + const commandArgs: CommandArgs = { + values: { [parsed.arg]: parsed.value }, + }; + const prompt = commandDefinition + ? buildCommandTextFromArgs(commandDefinition, commandArgs) + : `/${parsed.command} ${parsed.value}`; + const user = body.user; + const userName = + user && "name" in user && user.name + ? user.name + : user && "username" in user && user.username + ? user.username + : (user?.id ?? ""); + const triggerId = "trigger_id" in body ? body.trigger_id : undefined; + const commandPayload = { + user_id: user?.id ?? "", + user_name: userName, + channel_id: body.channel?.id ?? "", + channel_name: body.channel?.name ?? body.channel?.id ?? "", + trigger_id: triggerId ?? String(Date.now()), + } as SlackCommandMiddlewareArgs["command"]; + await handleSlashCommand({ + command: commandPayload, + ack: async () => {}, + respond: respondFn as SlackCommandMiddlewareArgs["respond"], + prompt, + commandArgs, + commandDefinition: commandDefinition ?? undefined, }); - const parsed = parseSlackCommandArgValue(action?.value); - if (!parsed) { - await respondFn({ - text: "Sorry, that button is no longer valid.", - response_type: "ephemeral", - }); - return; - } - if (body.user?.id && parsed.userId !== body.user.id) { - await respondFn({ - text: "That menu is for another user.", - response_type: "ephemeral", - }); - return; - } - const commandDefinition = findCommandByNativeName(parsed.command, "slack"); - const commandArgs: CommandArgs = { - values: { [parsed.arg]: parsed.value }, - }; - const prompt = commandDefinition - ? buildCommandTextFromArgs(commandDefinition, commandArgs) - : `/${parsed.command} ${parsed.value}`; - const user = body.user; - const userName = - user && "name" in user && user.name - ? user.name - : user && "username" in user && user.username - ? user.username - : (user?.id ?? ""); - const triggerId = "trigger_id" in body ? body.trigger_id : undefined; - const commandPayload = { - user_id: user?.id ?? "", - user_name: userName, - channel_id: body.channel?.id ?? "", - channel_name: body.channel?.name ?? body.channel?.id ?? "", - trigger_id: triggerId ?? String(Date.now()), - } as SlackCommandMiddlewareArgs["command"]; - await handleSlashCommand({ - command: commandPayload, - ack: async () => {}, - respond: respondFn as SlackCommandMiddlewareArgs["respond"], - prompt, - commandArgs, - commandDefinition: commandDefinition ?? undefined, }); - }); + }; + registerArgAction(SLACK_COMMAND_ARG_ACTION_ID); } diff --git a/src/slack/monitor/types.ts b/src/slack/monitor/types.ts index 06f72b3067..c77bd53f96 100644 --- a/src/slack/monitor/types.ts +++ b/src/slack/monitor/types.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig, SlackSlashCommandConfig } from "../../config/config.js"; +import type { OpenClawConfig, SlackSlashCommandConfig } from "../../config/config.js"; import type { RuntimeEnv } from "../../runtime.js"; import type { SlackFile, SlackMessageEvent } from "../types.js"; @@ -7,7 +7,7 @@ export type MonitorSlackOpts = { appToken?: string; accountId?: string; mode?: "socket" | "http"; - config?: MoltbotConfig; + config?: OpenClawConfig; runtime?: RuntimeEnv; abortSignal?: AbortSignal; mediaMaxMb?: number; diff --git a/src/slack/threading-tool-context.test.ts b/src/slack/threading-tool-context.test.ts index 6adab5dc90..fae665dc3c 100644 --- a/src/slack/threading-tool-context.test.ts +++ b/src/slack/threading-tool-context.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { buildSlackThreadingToolContext } from "./threading-tool-context.js"; -const emptyCfg = {} as MoltbotConfig; +const emptyCfg = {} as OpenClawConfig; describe("buildSlackThreadingToolContext", () => { it("uses top-level replyToMode by default", () => { @@ -11,7 +11,7 @@ describe("buildSlackThreadingToolContext", () => { channels: { slack: { replyToMode: "first" }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, @@ -28,7 +28,7 @@ describe("buildSlackThreadingToolContext", () => { replyToModeByChatType: { direct: "all" }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, @@ -45,7 +45,7 @@ describe("buildSlackThreadingToolContext", () => { replyToModeByChatType: { direct: "all" }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, @@ -61,7 +61,7 @@ describe("buildSlackThreadingToolContext", () => { replyToMode: "first", }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, @@ -78,7 +78,7 @@ describe("buildSlackThreadingToolContext", () => { dm: { replyToMode: "all" }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, @@ -92,7 +92,7 @@ describe("buildSlackThreadingToolContext", () => { channels: { slack: { replyToMode: "off" }, }, - } as MoltbotConfig; + } as OpenClawConfig; const result = buildSlackThreadingToolContext({ cfg, accountId: null, diff --git a/src/slack/threading-tool-context.ts b/src/slack/threading-tool-context.ts index a54d2c3a66..6a8e1b57df 100644 --- a/src/slack/threading-tool-context.ts +++ b/src/slack/threading-tool-context.ts @@ -2,11 +2,11 @@ import type { ChannelThreadingContext, ChannelThreadingToolContext, } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveSlackAccount, resolveSlackReplyToMode } from "./accounts.js"; export function buildSlackThreadingToolContext(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; context: ChannelThreadingContext; hasRepliedRef?: { value: boolean }; diff --git a/src/telegram/accounts.test.ts b/src/telegram/accounts.test.ts index cb756aafbb..79273611dd 100644 --- a/src/telegram/accounts.test.ts +++ b/src/telegram/accounts.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveTelegramAccount } from "./accounts.js"; describe("resolveTelegramAccount", () => { @@ -8,7 +8,7 @@ describe("resolveTelegramAccount", () => { const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = ""; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { accounts: { work: { botToken: "tok-work" } } }, }, @@ -31,7 +31,7 @@ describe("resolveTelegramAccount", () => { const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = "tok-env"; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { accounts: { work: { botToken: "tok-work" } } }, }, @@ -54,7 +54,7 @@ describe("resolveTelegramAccount", () => { const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = "tok-env"; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { botToken: "tok-config" }, }, @@ -77,7 +77,7 @@ describe("resolveTelegramAccount", () => { const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN; process.env.TELEGRAM_BOT_TOKEN = ""; try { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { accounts: { work: { botToken: "tok-work" } } }, }, diff --git a/src/telegram/accounts.ts b/src/telegram/accounts.ts index 80eb535a3a..4c2eb69a6c 100644 --- a/src/telegram/accounts.ts +++ b/src/telegram/accounts.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { TelegramAccountConfig } from "../config/types.js"; import { isTruthyEnvValue } from "../infra/env.js"; import { listBoundAccountIds, resolveDefaultAgentBoundAccountId } from "../routing/bindings.js"; @@ -6,7 +6,7 @@ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.j import { resolveTelegramToken } from "./token.js"; const debugAccounts = (...args: unknown[]) => { - if (isTruthyEnvValue(process.env.CLAWDBOT_DEBUG_TELEGRAM_ACCOUNTS)) { + if (isTruthyEnvValue(process.env.OPENCLAW_DEBUG_TELEGRAM_ACCOUNTS)) { console.warn("[telegram:accounts]", ...args); } }; @@ -20,7 +20,7 @@ export type ResolvedTelegramAccount = { config: TelegramAccountConfig; }; -function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { +function listConfiguredAccountIds(cfg: OpenClawConfig): string[] { const accounts = cfg.channels?.telegram?.accounts; if (!accounts || typeof accounts !== "object") return []; const ids = new Set(); @@ -31,7 +31,7 @@ function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { return [...ids]; } -export function listTelegramAccountIds(cfg: MoltbotConfig): string[] { +export function listTelegramAccountIds(cfg: OpenClawConfig): string[] { const ids = Array.from( new Set([...listConfiguredAccountIds(cfg), ...listBoundAccountIds(cfg, "telegram")]), ); @@ -40,7 +40,7 @@ export function listTelegramAccountIds(cfg: MoltbotConfig): string[] { return ids.sort((a, b) => a.localeCompare(b)); } -export function resolveDefaultTelegramAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultTelegramAccountId(cfg: OpenClawConfig): string { const boundDefault = resolveDefaultAgentBoundAccountId(cfg, "telegram"); if (boundDefault) return boundDefault; const ids = listTelegramAccountIds(cfg); @@ -49,7 +49,7 @@ export function resolveDefaultTelegramAccountId(cfg: MoltbotConfig): string { } function resolveAccountConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId: string, ): TelegramAccountConfig | undefined { const accounts = cfg.channels?.telegram?.accounts; @@ -61,7 +61,7 @@ function resolveAccountConfig( return matchKey ? (accounts[matchKey] as TelegramAccountConfig | undefined) : undefined; } -function mergeTelegramAccountConfig(cfg: MoltbotConfig, accountId: string): TelegramAccountConfig { +function mergeTelegramAccountConfig(cfg: OpenClawConfig, accountId: string): TelegramAccountConfig { const { accounts: _ignored, ...base } = (cfg.channels?.telegram ?? {}) as TelegramAccountConfig & { accounts?: unknown }; const account = resolveAccountConfig(cfg, accountId) ?? {}; @@ -69,7 +69,7 @@ function mergeTelegramAccountConfig(cfg: MoltbotConfig, accountId: string): Tele } export function resolveTelegramAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): ResolvedTelegramAccount { const hasExplicitAccountId = Boolean(params.accountId?.trim()); @@ -110,7 +110,7 @@ export function resolveTelegramAccount(params: { return fallback; } -export function listEnabledTelegramAccounts(cfg: MoltbotConfig): ResolvedTelegramAccount[] { +export function listEnabledTelegramAccounts(cfg: OpenClawConfig): ResolvedTelegramAccount[] { return listTelegramAccountIds(cfg) .map((accountId) => resolveTelegramAccount({ cfg, accountId })) .filter((account) => account.enabled); diff --git a/src/telegram/bot-message-context.dm-threads.test.ts b/src/telegram/bot-message-context.dm-threads.test.ts index d710e0b1b4..6162e1cb1b 100644 --- a/src/telegram/bot-message-context.dm-threads.test.ts +++ b/src/telegram/bot-message-context.dm-threads.test.ts @@ -4,7 +4,7 @@ import { buildTelegramMessageContext } from "./bot-message-context.js"; describe("buildTelegramMessageContext dm thread sessions", () => { const baseConfig = { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never; @@ -73,7 +73,7 @@ describe("buildTelegramMessageContext dm thread sessions", () => { describe("buildTelegramMessageContext group sessions without forum", () => { const baseConfig = { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never; diff --git a/src/telegram/bot-message-context.sender-prefix.test.ts b/src/telegram/bot-message-context.sender-prefix.test.ts index c7f0e5de9f..03c4dbb9a8 100644 --- a/src/telegram/bot-message-context.sender-prefix.test.ts +++ b/src/telegram/bot-message-context.sender-prefix.test.ts @@ -25,7 +25,7 @@ describe("buildTelegramMessageContext sender prefix", () => { }, } as never, cfg: { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never, @@ -72,7 +72,7 @@ describe("buildTelegramMessageContext sender prefix", () => { }, } as never, cfg: { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never, @@ -118,7 +118,7 @@ describe("buildTelegramMessageContext sender prefix", () => { }, } as never, cfg: { - agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/clawd" } }, + agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never, diff --git a/src/telegram/bot-message-context.ts b/src/telegram/bot-message-context.ts index abd06cdefd..9696e4f1b0 100644 --- a/src/telegram/bot-message-context.ts +++ b/src/telegram/bot-message-context.ts @@ -21,7 +21,7 @@ import { formatLocationText, toLocationContext } from "../channels/location.js"; import { recordInboundSession } from "../channels/session.js"; import { formatCliCommand } from "../cli/command-format.js"; import { readSessionUpdatedAt, resolveStorePath } from "../config/sessions.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { DmPolicy, TelegramGroupConfig, TelegramTopicConfig } from "../config/types.js"; import { logVerbose, shouldLogVerbose } from "../globals.js"; import { recordChannelActivity } from "../infra/channel-activity.js"; @@ -96,7 +96,7 @@ type BuildTelegramMessageContextParams = { storeAllowFrom: string[]; options?: TelegramMessageContextOptions; bot: Bot; - cfg: MoltbotConfig; + cfg: OpenClawConfig; account: { accountId: string }; historyLimit: number; groupHistories: Map; @@ -111,7 +111,7 @@ type BuildTelegramMessageContextParams = { }; async function resolveStickerVisionSupport(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentId?: string; }): Promise { try { @@ -272,14 +272,14 @@ export const buildTelegramMessageContext = async ({ bot.api.sendMessage( chatId, [ - "Moltbot: access not configured.", + "OpenClaw: access not configured.", "", `Your Telegram user id: ${telegramUserId}`, "", `Pairing code: ${code}`, "", "Ask the bot owner to approve with:", - formatCliCommand("moltbot pairing approve telegram "), + formatCliCommand("openclaw pairing approve telegram "), ].join("\n"), ), }); diff --git a/src/telegram/bot-native-commands.plugin-auth.test.ts b/src/telegram/bot-native-commands.plugin-auth.test.ts index 03f99e1fe3..533f5fda3c 100644 --- a/src/telegram/bot-native-commands.plugin-auth.test.ts +++ b/src/telegram/bot-native-commands.plugin-auth.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; import type { ChannelGroupPolicy } from "../config/group-policy.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { TelegramAccountConfig } from "../config/types.js"; import type { RuntimeEnv } from "../runtime.js"; import { registerTelegramNativeCommands } from "./bot-native-commands.js"; @@ -47,7 +47,7 @@ describe("registerTelegramNativeCommands (plugin auth)", () => { }, } as const; - const cfg = {} as MoltbotConfig; + const cfg = {} as OpenClawConfig; const telegramCfg = {} as TelegramAccountConfig; const resolveGroupPolicy = () => ({ diff --git a/src/telegram/bot-native-commands.ts b/src/telegram/bot-native-commands.ts index 59f109a1ff..5f37b81dca 100644 --- a/src/telegram/bot-native-commands.ts +++ b/src/telegram/bot-native-commands.ts @@ -37,7 +37,7 @@ import type { TelegramGroupConfig, TelegramTopicConfig, } from "../config/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { RuntimeEnv } from "../runtime.js"; import { deliverReplies } from "./bot/delivery.js"; import { buildInlineKeyboard } from "./send.js"; @@ -68,7 +68,7 @@ type TelegramCommandAuthResult = { type RegisterTelegramNativeCommandsParams = { bot: Bot; - cfg: MoltbotConfig; + cfg: OpenClawConfig; runtime: RuntimeEnv; accountId: string; telegramCfg: TelegramAccountConfig; @@ -92,7 +92,7 @@ type RegisterTelegramNativeCommandsParams = { async function resolveTelegramCommandAuth(params: { msg: NonNullable; bot: Bot; - cfg: MoltbotConfig; + cfg: OpenClawConfig; telegramCfg: TelegramAccountConfig; allowFrom?: Array; groupAllowFrom?: Array; diff --git a/src/telegram/bot.create-telegram-bot.accepts-group-messages-mentionpatterns-match-without-botusername.test.ts b/src/telegram/bot.create-telegram-bot.accepts-group-messages-mentionpatterns-match-without-botusername.test.ts index 03aaeebd74..180168b27e 100644 --- a/src/telegram/bot.create-telegram-bot.accepts-group-messages-mentionpatterns-match-without-botusername.test.ts +++ b/src/telegram/bot.create-telegram-bot.accepts-group-messages-mentionpatterns-match-without-botusername.test.ts @@ -5,7 +5,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -196,7 +196,7 @@ describe("createTelegramBot", () => { message_id: 1, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -245,7 +245,7 @@ describe("createTelegramBot", () => { message_id: 3, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -288,7 +288,7 @@ describe("createTelegramBot", () => { username: "ada", }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -334,7 +334,7 @@ describe("createTelegramBot", () => { message_id: 123, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -375,7 +375,7 @@ describe("createTelegramBot", () => { message_id: 2, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -435,7 +435,7 @@ describe("createTelegramBot", () => { from: { first_name: "Ada" }, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.applies-topic-skill-filters-system-prompts.test.ts b/src/telegram/bot.create-telegram-bot.applies-topic-skill-filters-system-prompts.test.ts index bb61ceebb8..a5397e3fad 100644 --- a/src/telegram/bot.create-telegram-bot.applies-topic-skill-filters-system-prompts.test.ts +++ b/src/telegram/bot.create-telegram-bot.applies-topic-skill-filters-system-prompts.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -201,7 +201,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -245,7 +245,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -365,7 +365,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }; diff --git a/src/telegram/bot.create-telegram-bot.blocks-all-group-messages-grouppolicy-is.test.ts b/src/telegram/bot.create-telegram-bot.blocks-all-group-messages-grouppolicy-is.test.ts index a9f5214c88..2755e35571 100644 --- a/src/telegram/bot.create-telegram-bot.blocks-all-group-messages-grouppolicy-is.test.ts +++ b/src/telegram/bot.create-telegram-bot.blocks-all-group-messages-grouppolicy-is.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -178,10 +178,10 @@ describe("createTelegramBot", () => { message: { chat: { id: -100123456789, type: "group", title: "Test Group" }, from: { id: 123456789, username: "testuser" }, - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -208,10 +208,10 @@ describe("createTelegramBot", () => { message: { chat: { id: -100123456789, type: "group", title: "Test Group" }, from: { id: 999999, username: "notallowed" }, // Not in allowFrom - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -241,7 +241,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -271,7 +271,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -301,7 +301,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -331,7 +331,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -360,7 +360,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.dedupes-duplicate-callback-query-updates-by-update.test.ts b/src/telegram/bot.create-telegram-bot.dedupes-duplicate-callback-query-updates-by-update.test.ts index ebd1ff0a92..ac8e0bdc20 100644 --- a/src/telegram/bot.create-telegram-bot.dedupes-duplicate-callback-query-updates-by-update.test.ts +++ b/src/telegram/bot.create-telegram-bot.dedupes-duplicate-callback-query-updates-by-update.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -186,7 +186,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }; @@ -222,7 +222,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); @@ -237,7 +237,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); diff --git a/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts b/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts index c3844ac88a..7238375073 100644 --- a/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts +++ b/src/telegram/bot.create-telegram-bot.installs-grammy-throttler.test.ts @@ -7,7 +7,7 @@ let getTelegramSequentialKey: typeof import("./bot.js").getTelegramSequentialKey let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-throttler-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-throttler-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ loadWebMedia: vi.fn(), @@ -294,7 +294,7 @@ describe("createTelegramBot", () => { message_id: 10, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -328,7 +328,7 @@ describe("createTelegramBot", () => { }; await handler({ message, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -371,7 +371,7 @@ describe("createTelegramBot", () => { date: 1736380800, from: { id: 999, username: "random" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -408,12 +408,12 @@ describe("createTelegramBot", () => { await handler({ message, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); await handler({ message: { ...message, text: "hello again" }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -428,7 +428,7 @@ describe("createTelegramBot", () => { const handler = getOnHandler("message") as (ctx: Record) => Promise; await handler({ message: { chat: { id: 42, type: "private" }, text: "hi" }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.matches-tg-prefixed-allowfrom-entries-case-insensitively.test.ts b/src/telegram/bot.create-telegram-bot.matches-tg-prefixed-allowfrom-entries-case-insensitively.test.ts index 72ee9de0b2..2f1725947a 100644 --- a/src/telegram/bot.create-telegram-bot.matches-tg-prefixed-allowfrom-entries-case-insensitively.test.ts +++ b/src/telegram/bot.create-telegram-bot.matches-tg-prefixed-allowfrom-entries-case-insensitively.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -182,7 +182,7 @@ describe("createTelegramBot", () => { text: "hello from prefixed user", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -212,7 +212,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -242,7 +242,7 @@ describe("createTelegramBot", () => { text: "/status", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -280,7 +280,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -325,7 +325,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -366,7 +366,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.matches-usernames-case-insensitively-grouppolicy-is.test.ts b/src/telegram/bot.create-telegram-bot.matches-usernames-case-insensitively-grouppolicy-is.test.ts index d46fe663d3..532111bbe8 100644 --- a/src/telegram/bot.create-telegram-bot.matches-usernames-case-insensitively-grouppolicy-is.test.ts +++ b/src/telegram/bot.create-telegram-bot.matches-usernames-case-insensitively-grouppolicy-is.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -182,7 +182,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -211,7 +211,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -239,7 +239,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -267,7 +267,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -297,7 +297,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -326,7 +326,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -356,7 +356,7 @@ describe("createTelegramBot", () => { text: "hello from prefixed user", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.routes-dms-by-telegram-accountid-binding.test.ts b/src/telegram/bot.create-telegram-bot.routes-dms-by-telegram-accountid-binding.test.ts index e854d19621..0e0774379b 100644 --- a/src/telegram/bot.create-telegram-bot.routes-dms-by-telegram-accountid-binding.test.ts +++ b/src/telegram/bot.create-telegram-bot.routes-dms-by-telegram-accountid-binding.test.ts @@ -4,7 +4,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-${Math.random().toString(16).slice(2)}.json`, })); const { loadWebMedia } = vi.hoisted(() => ({ @@ -193,7 +193,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -227,7 +227,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -269,7 +269,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -297,7 +297,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -357,7 +357,7 @@ describe("createTelegramBot", () => { message_id: 5, from: { first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.create-telegram-bot.sends-replies-without-native-reply-threading.test.ts b/src/telegram/bot.create-telegram-bot.sends-replies-without-native-reply-threading.test.ts index 61cf4def69..7cac6ad72d 100644 --- a/src/telegram/bot.create-telegram-bot.sends-replies-without-native-reply-threading.test.ts +++ b/src/telegram/bot.create-telegram-bot.sends-replies-without-native-reply-threading.test.ts @@ -7,7 +7,7 @@ let createTelegramBot: typeof import("./bot.js").createTelegramBot; let resetInboundDedupe: typeof import("../auto-reply/reply/inbound-dedupe.js").resetInboundDedupe; const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-reply-threading-${Math.random() + sessionStorePath: `/tmp/openclaw-telegram-reply-threading-${Math.random() .toString(16) .slice(2)}.json`, })); @@ -179,7 +179,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -207,7 +207,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -239,7 +239,7 @@ describe("createTelegramBot", () => { text: "hi", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -265,7 +265,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -294,10 +294,10 @@ describe("createTelegramBot", () => { await handler({ message: { chat: { id: 456, type: "group", title: "Ops" }, - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -322,7 +322,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -332,7 +332,7 @@ describe("createTelegramBot", () => { onSpy.mockReset(); const replySpy = replyModule.__replySpy as unknown as ReturnType; replySpy.mockReset(); - const storeDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-telegram-")); + const storeDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-telegram-")); const storePath = path.join(storeDir, "sessions.json"); fs.writeFileSync( storePath, @@ -369,7 +369,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts b/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts index 79c8aab282..bd3b73499f 100644 --- a/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts +++ b/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts @@ -151,7 +151,7 @@ describe("telegram inbound media", () => { photo: [{ file_id: "fid" }], date: 1736380800, // 2025-01-09T00:00:00Z }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/1.jpg" }), }); @@ -206,7 +206,7 @@ describe("telegram inbound media", () => { chat: { id: 1234, type: "private" }, photo: [{ file_id: "fid" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/2.jpg" }), }); @@ -249,7 +249,7 @@ describe("telegram inbound media", () => { chat: { id: 1234, type: "private" }, photo: [{ file_id: "fid" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); @@ -319,7 +319,7 @@ describe("telegram media groups", () => { media_group_id: "album123", photo: [{ file_id: "photo1" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/photo1.jpg" }), }); @@ -331,7 +331,7 @@ describe("telegram media groups", () => { media_group_id: "album123", photo: [{ file_id: "photo2" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/photo2.jpg" }), }); @@ -385,7 +385,7 @@ describe("telegram media groups", () => { media_group_id: "albumA", photo: [{ file_id: "photoA1" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/photoA1.jpg" }), }); @@ -398,7 +398,7 @@ describe("telegram media groups", () => { media_group_id: "albumB", photo: [{ file_id: "photoB1" }], }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "photos/photoB1.jpg" }), }); @@ -477,7 +477,7 @@ describe("telegram stickers", () => { }, date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "stickers/sticker.webp" }), }); @@ -558,7 +558,7 @@ describe("telegram stickers", () => { }, date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "stickers/sticker.webp" }), }); @@ -624,7 +624,7 @@ describe("telegram stickers", () => { }, date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "stickers/animated.tgs" }), }); @@ -684,7 +684,7 @@ describe("telegram stickers", () => { }, date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "stickers/video.webm" }), }); @@ -737,7 +737,7 @@ describe("telegram text fragments", () => { date: 1736380800, text: part1, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); @@ -748,7 +748,7 @@ describe("telegram text fragments", () => { date: 1736380801, text: part2, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); diff --git a/src/telegram/bot.media.includes-location-text-ctx-fields-pins.test.ts b/src/telegram/bot.media.includes-location-text-ctx-fields-pins.test.ts index e991e6aec8..5a4f1b3625 100644 --- a/src/telegram/bot.media.includes-location-text-ctx-fields-pins.test.ts +++ b/src/telegram/bot.media.includes-location-text-ctx-fields-pins.test.ts @@ -123,7 +123,7 @@ describe("telegram inbound media", () => { horizontal_accuracy: 12, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "unused" }), }); @@ -166,7 +166,7 @@ describe("telegram inbound media", () => { location: { latitude: 48.858844, longitude: 2.294351 }, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ file_path: "unused" }), }); diff --git a/src/telegram/bot.test.ts b/src/telegram/bot.test.ts index c075174fb7..8129adc7a6 100644 --- a/src/telegram/bot.test.ts +++ b/src/telegram/bot.test.ts @@ -22,7 +22,7 @@ vi.mock("../auto-reply/skill-commands.js", () => ({ })); const { sessionStorePath } = vi.hoisted(() => ({ - sessionStorePath: `/tmp/moltbot-telegram-bot-${Math.random().toString(16).slice(2)}.json`, + sessionStorePath: `/tmp/openclaw-telegram-bot-${Math.random().toString(16).slice(2)}.json`, })); function resolveSkillCommands(config: Parameters[0]) { @@ -382,7 +382,7 @@ describe("createTelegramBot", () => { message_id: 10, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -425,7 +425,7 @@ describe("createTelegramBot", () => { message_id: 11, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -454,7 +454,7 @@ describe("createTelegramBot", () => { message_id: 12, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -506,7 +506,7 @@ describe("createTelegramBot", () => { message_id: 13, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -539,7 +539,7 @@ describe("createTelegramBot", () => { }; await handler({ message, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -583,7 +583,7 @@ describe("createTelegramBot", () => { date: 1736380800, from: { id: 999, username: "random" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -621,12 +621,12 @@ describe("createTelegramBot", () => { await handler({ message, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); await handler({ message: { ...message, text: "hello again" }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -642,7 +642,7 @@ describe("createTelegramBot", () => { const handler = getOnHandler("message") as (ctx: Record) => Promise; await handler({ message: { chat: { id: 42, type: "private" }, text: "hi" }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -681,7 +681,7 @@ describe("createTelegramBot", () => { message_id: 1, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -733,7 +733,7 @@ describe("createTelegramBot", () => { username: "ada", }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -781,7 +781,7 @@ describe("createTelegramBot", () => { message_id: 123, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -824,7 +824,7 @@ describe("createTelegramBot", () => { message_id: 2, from: { id: 9, first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -886,7 +886,7 @@ describe("createTelegramBot", () => { from: { first_name: "Ada" }, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -922,7 +922,7 @@ describe("createTelegramBot", () => { text: "summarize this", }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -953,7 +953,7 @@ describe("createTelegramBot", () => { text: "summarize this", }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -982,7 +982,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1011,7 +1011,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1044,7 +1044,7 @@ describe("createTelegramBot", () => { text: "hi", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1071,7 +1071,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1101,10 +1101,10 @@ describe("createTelegramBot", () => { await handler({ message: { chat: { id: 456, type: "group", title: "Ops" }, - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1130,7 +1130,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1158,10 +1158,10 @@ describe("createTelegramBot", () => { reply_to_message: { message_id: 42, text: "original reply", - from: { id: 999, first_name: "Moltbot" }, + from: { id: 999, first_name: "OpenClaw" }, }, }, - me: { id: 999, username: "moltbot_bot" }, + me: { id: 999, username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1174,7 +1174,7 @@ describe("createTelegramBot", () => { onSpy.mockReset(); const replySpy = replyModule.__replySpy as unknown as ReturnType; replySpy.mockReset(); - const storeDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-telegram-")); + const storeDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-telegram-")); const storePath = path.join(storeDir, "sessions.json"); fs.writeFileSync( storePath, @@ -1211,7 +1211,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1253,7 +1253,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1288,7 +1288,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1331,7 +1331,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1375,7 +1375,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1418,7 +1418,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1447,7 +1447,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1509,7 +1509,7 @@ describe("createTelegramBot", () => { message_id: 5, from: { first_name: "Ada" }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1543,10 +1543,10 @@ describe("createTelegramBot", () => { message: { chat: { id: -100123456789, type: "group", title: "Test Group" }, from: { id: 123456789, username: "testuser" }, - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1574,10 +1574,10 @@ describe("createTelegramBot", () => { message: { chat: { id: -100123456789, type: "group", title: "Test Group" }, from: { id: 999999, username: "notallowed" }, // Not in allowFrom - text: "@moltbot_bot hello", + text: "@openclaw_bot hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1608,7 +1608,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1639,7 +1639,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1670,7 +1670,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1701,7 +1701,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1731,7 +1731,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1762,7 +1762,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1792,7 +1792,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1821,7 +1821,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1850,7 +1850,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1881,7 +1881,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1911,7 +1911,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1942,7 +1942,7 @@ describe("createTelegramBot", () => { text: "hello from prefixed user", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -1974,7 +1974,7 @@ describe("createTelegramBot", () => { text: "hello from prefixed user", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2005,7 +2005,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2036,7 +2036,7 @@ describe("createTelegramBot", () => { text: "/status", date: 1736380800, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2075,7 +2075,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2121,7 +2121,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2163,7 +2163,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2215,7 +2215,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2260,7 +2260,7 @@ describe("createTelegramBot", () => { message_id: 42, message_thread_id: 99, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -2507,7 +2507,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 42, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }; @@ -2545,7 +2545,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }; @@ -2582,7 +2582,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); @@ -2597,7 +2597,7 @@ describe("createTelegramBot", () => { message_id: 9001, }, }, - me: { username: "moltbot_bot" }, + me: { username: "openclaw_bot" }, getFile: async () => ({}), }); diff --git a/src/telegram/bot.ts b/src/telegram/bot.ts index ae21d10da7..fb0940d3bd 100644 --- a/src/telegram/bot.ts +++ b/src/telegram/bot.ts @@ -12,7 +12,7 @@ import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, } from "../config/commands.js"; -import type { MoltbotConfig, ReplyToMode } from "../config/config.js"; +import type { OpenClawConfig, ReplyToMode } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { resolveChannelGroupPolicy, @@ -57,7 +57,7 @@ export type TelegramBotOptions = { mediaMaxMb?: number; replyToMode?: ReplyToMode; proxyFetch?: typeof fetch; - config?: MoltbotConfig; + config?: OpenClawConfig; updateOffset?: { lastUpdateId?: number | null; onUpdateId?: (updateId: number) => void | Promise; diff --git a/src/telegram/bot/helpers.test.ts b/src/telegram/bot/helpers.test.ts index 8e90bb520a..1f0a581326 100644 --- a/src/telegram/bot/helpers.test.ts +++ b/src/telegram/bot/helpers.test.ts @@ -91,8 +91,8 @@ describe("normalizeForwardedContext", () => { it("handles legacy forwards with signatures", () => { const ctx = normalizeForwardedContext({ forward_from_chat: { - title: "Moltbot Updates", - username: "moltbot", + title: "OpenClaw Updates", + username: "openclaw", id: 99, type: "channel", }, @@ -100,11 +100,11 @@ describe("normalizeForwardedContext", () => { forward_date: 789, } as any); expect(ctx).not.toBeNull(); - expect(ctx?.from).toBe("Moltbot Updates (Stan)"); + expect(ctx?.from).toBe("OpenClaw Updates (Stan)"); expect(ctx?.fromType).toBe("legacy_channel"); expect(ctx?.fromId).toBe("99"); - expect(ctx?.fromUsername).toBe("moltbot"); - expect(ctx?.fromTitle).toBe("Moltbot Updates"); + expect(ctx?.fromUsername).toBe("openclaw"); + expect(ctx?.fromTitle).toBe("OpenClaw Updates"); expect(ctx?.fromSignature).toBe("Stan"); expect(ctx?.date).toBe(789); }); diff --git a/src/telegram/draft-chunking.test.ts b/src/telegram/draft-chunking.test.ts index d2ebb75f91..4c8dae7633 100644 --- a/src/telegram/draft-chunking.test.ts +++ b/src/telegram/draft-chunking.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveTelegramDraftStreamingChunking } from "./draft-chunking.js"; describe("resolveTelegramDraftStreamingChunking", () => { @@ -14,7 +14,7 @@ describe("resolveTelegramDraftStreamingChunking", () => { }); it("clamps to telegram.textChunkLimit", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { allowFrom: ["*"], textChunkLimit: 150 } }, }; const chunking = resolveTelegramDraftStreamingChunking(cfg, "default"); @@ -26,7 +26,7 @@ describe("resolveTelegramDraftStreamingChunking", () => { }); it("supports per-account overrides", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { allowFrom: ["*"], diff --git a/src/telegram/draft-chunking.ts b/src/telegram/draft-chunking.ts index fd0d33e155..e73a76ae8c 100644 --- a/src/telegram/draft-chunking.ts +++ b/src/telegram/draft-chunking.ts @@ -1,13 +1,13 @@ import { resolveTextChunkLimit } from "../auto-reply/chunk.js"; import { getChannelDock } from "../channels/dock.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { normalizeAccountId } from "../routing/session-key.js"; const DEFAULT_TELEGRAM_DRAFT_STREAM_MIN = 200; const DEFAULT_TELEGRAM_DRAFT_STREAM_MAX = 800; export function resolveTelegramDraftStreamingChunking( - cfg: MoltbotConfig | undefined, + cfg: OpenClawConfig | undefined, accountId?: string | null, ): { minChars: number; diff --git a/src/telegram/fetch.test.ts b/src/telegram/fetch.test.ts index 17cda1d002..4373592861 100644 --- a/src/telegram/fetch.test.ts +++ b/src/telegram/fetch.test.ts @@ -39,7 +39,7 @@ describe("resolveTelegramFetch", () => { }); it("honors env enable override", async () => { - vi.stubEnv("CLAWDBOT_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY", "1"); + vi.stubEnv("OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY", "1"); globalThis.fetch = vi.fn(async () => ({})) as unknown as typeof fetch; const { resolveTelegramFetch, setDefaultAutoSelectFamily } = await loadModule(); resolveTelegramFetch(); @@ -54,7 +54,7 @@ describe("resolveTelegramFetch", () => { }); it("env disable override wins over config", async () => { - vi.stubEnv("CLAWDBOT_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY", "1"); + vi.stubEnv("OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY", "1"); globalThis.fetch = vi.fn(async () => ({})) as unknown as typeof fetch; const { resolveTelegramFetch, setDefaultAutoSelectFamily } = await loadModule(); resolveTelegramFetch(undefined, { network: { autoSelectFamily: true } }); diff --git a/src/telegram/group-migration.ts b/src/telegram/group-migration.ts index 588fb0c533..ff99a2a06b 100644 --- a/src/telegram/group-migration.ts +++ b/src/telegram/group-migration.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { TelegramGroupConfig } from "../config/types.telegram.js"; import { normalizeAccountId } from "../routing/session-key.js"; @@ -13,7 +13,7 @@ export type TelegramGroupMigrationResult = { }; function resolveAccountGroups( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId?: string | null, ): { groups?: TelegramGroups } { if (!accountId) return {}; @@ -43,7 +43,7 @@ export function migrateTelegramGroupsInPlace( } export function migrateTelegramGroupConfig(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; oldChatId: string; newChatId: string; diff --git a/src/telegram/inline-buttons.ts b/src/telegram/inline-buttons.ts index 72f5c8232e..ada8e09fef 100644 --- a/src/telegram/inline-buttons.ts +++ b/src/telegram/inline-buttons.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { TelegramInlineButtonsScope } from "../config/types.telegram.js"; import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; import { parseTelegramTarget } from "./targets.js"; @@ -38,7 +38,7 @@ function resolveInlineButtonsScopeFromCapabilities( } export function resolveTelegramInlineButtonsScope(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): TelegramInlineButtonsScope { const account = resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId }); @@ -46,7 +46,7 @@ export function resolveTelegramInlineButtonsScope(params: { } export function isTelegramInlineButtonsEnabled(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): boolean { if (params.accountId) { diff --git a/src/telegram/monitor.ts b/src/telegram/monitor.ts index c3b3a5a2f9..2709b591b7 100644 --- a/src/telegram/monitor.ts +++ b/src/telegram/monitor.ts @@ -1,5 +1,5 @@ import { type RunOptions, run } from "@grammyjs/runner"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { resolveAgentMaxConcurrent } from "../config/agent-limits.js"; import { computeBackoff, sleepWithAbort } from "../infra/backoff.js"; @@ -17,7 +17,7 @@ import { startTelegramWebhook } from "./webhook.js"; export type MonitorTelegramOpts = { token?: string; accountId?: string; - config?: MoltbotConfig; + config?: OpenClawConfig; runtime?: RuntimeEnv; abortSignal?: AbortSignal; useWebhook?: boolean; @@ -28,7 +28,7 @@ export type MonitorTelegramOpts = { webhookUrl?: string; }; -export function createTelegramRunnerOptions(cfg: MoltbotConfig): RunOptions { +export function createTelegramRunnerOptions(cfg: OpenClawConfig): RunOptions { return { sink: { concurrency: resolveAgentMaxConcurrent(cfg), diff --git a/src/telegram/network-config.test.ts b/src/telegram/network-config.test.ts index cb4bc4c6e3..1766fac71f 100644 --- a/src/telegram/network-config.test.ts +++ b/src/telegram/network-config.test.ts @@ -6,25 +6,25 @@ describe("resolveTelegramAutoSelectFamilyDecision", () => { it("prefers env enable over env disable", () => { const decision = resolveTelegramAutoSelectFamilyDecision({ env: { - CLAWDBOT_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY: "1", - CLAWDBOT_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1", + OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY: "1", + OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1", }, nodeMajor: 22, }); expect(decision).toEqual({ value: true, - source: "env:CLAWDBOT_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY", + source: "env:OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY", }); }); it("uses env disable when set", () => { const decision = resolveTelegramAutoSelectFamilyDecision({ - env: { CLAWDBOT_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1" }, + env: { OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY: "1" }, nodeMajor: 22, }); expect(decision).toEqual({ value: false, - source: "env:CLAWDBOT_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY", + source: "env:OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY", }); }); diff --git a/src/telegram/network-config.ts b/src/telegram/network-config.ts index ac5dd05a72..4e85601056 100644 --- a/src/telegram/network-config.ts +++ b/src/telegram/network-config.ts @@ -4,8 +4,8 @@ import { isTruthyEnvValue } from "../infra/env.js"; import type { TelegramNetworkConfig } from "../config/types.telegram.js"; export const TELEGRAM_DISABLE_AUTO_SELECT_FAMILY_ENV = - "CLAWDBOT_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY"; -export const TELEGRAM_ENABLE_AUTO_SELECT_FAMILY_ENV = "CLAWDBOT_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY"; + "OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY"; +export const TELEGRAM_ENABLE_AUTO_SELECT_FAMILY_ENV = "OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY"; export type TelegramAutoSelectFamilyDecision = { value: boolean | null; diff --git a/src/telegram/pairing-store.test.ts b/src/telegram/pairing-store.test.ts index 5a13e4658b..34e9fb9312 100644 --- a/src/telegram/pairing-store.test.ts +++ b/src/telegram/pairing-store.test.ts @@ -12,14 +12,14 @@ import { } from "./pairing-store.js"; async function withTempStateDir(fn: (stateDir: string) => Promise) { - const previous = process.env.CLAWDBOT_STATE_DIR; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-pairing-")); - process.env.CLAWDBOT_STATE_DIR = dir; + const previous = process.env.OPENCLAW_STATE_DIR; + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-pairing-")); + process.env.OPENCLAW_STATE_DIR = dir; try { return await fn(dir); } finally { - if (previous === undefined) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = previous; + if (previous === undefined) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = previous; await fs.rm(dir, { recursive: true, force: true }); } } diff --git a/src/telegram/pairing-store.ts b/src/telegram/pairing-store.ts index 087fa1e164..4f5eb14c63 100644 --- a/src/telegram/pairing-store.ts +++ b/src/telegram/pairing-store.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { addChannelAllowFromStoreEntry, approveChannelPairingCode, @@ -95,7 +95,7 @@ export async function approveTelegramPairingCode(params: { } export async function resolveTelegramEffectiveAllowFrom(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; env?: NodeJS.ProcessEnv; }): Promise<{ dm: string[]; group: string[] }> { const env = params.env ?? process.env; diff --git a/src/telegram/reaction-level.test.ts b/src/telegram/reaction-level.test.ts index 1f077ff9dd..7fddd7d2df 100644 --- a/src/telegram/reaction-level.test.ts +++ b/src/telegram/reaction-level.test.ts @@ -1,6 +1,6 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveTelegramReactionLevel } from "./reaction-level.js"; describe("resolveTelegramReactionLevel", () => { @@ -19,7 +19,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("defaults to minimal level when reactionLevel is not set", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: {} }, }; @@ -31,7 +31,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("returns off level with no reactions enabled", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "off" } }, }; @@ -43,7 +43,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("returns ack level with only ackEnabled", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "ack" } }, }; @@ -55,7 +55,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("returns minimal level with agent reactions enabled and minimal guidance", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "minimal" } }, }; @@ -67,7 +67,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("returns extensive level with agent reactions enabled and extensive guidance", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "extensive" } }, }; @@ -79,7 +79,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("resolves reaction level from a specific account", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "ack", @@ -98,7 +98,7 @@ describe("resolveTelegramReactionLevel", () => { }); it("falls back to global level when account has no reactionLevel", () => { - const cfg: MoltbotConfig = { + const cfg: OpenClawConfig = { channels: { telegram: { reactionLevel: "minimal", diff --git a/src/telegram/reaction-level.ts b/src/telegram/reaction-level.ts index 0105f0fb34..2a88c573aa 100644 --- a/src/telegram/reaction-level.ts +++ b/src/telegram/reaction-level.ts @@ -1,4 +1,4 @@ -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveTelegramAccount } from "./accounts.js"; export type TelegramReactionLevel = "off" | "ack" | "minimal" | "extensive"; @@ -17,7 +17,7 @@ export type ResolvedReactionLevel = { * Resolve the effective reaction level and its implications. */ export function resolveTelegramReactionLevel(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string; }): ResolvedReactionLevel { const account = resolveTelegramAccount({ diff --git a/src/telegram/sticker-cache.test.ts b/src/telegram/sticker-cache.test.ts index ddb280ac6f..7d82c7651f 100644 --- a/src/telegram/sticker-cache.test.ts +++ b/src/telegram/sticker-cache.test.ts @@ -11,10 +11,10 @@ import { // Mock the state directory to use a temp location vi.mock("../config/paths.js", () => ({ - STATE_DIR: "/tmp/moltbot-test-sticker-cache", + STATE_DIR: "/tmp/openclaw-test-sticker-cache", })); -const TEST_CACHE_DIR = "/tmp/moltbot-test-sticker-cache/telegram"; +const TEST_CACHE_DIR = "/tmp/openclaw-test-sticker-cache/telegram"; const TEST_CACHE_FILE = path.join(TEST_CACHE_DIR, "sticker-cache.json"); describe("sticker-cache", () => { diff --git a/src/telegram/sticker-cache.ts b/src/telegram/sticker-cache.ts index fc2d7c97a8..278b944ae3 100644 --- a/src/telegram/sticker-cache.ts +++ b/src/telegram/sticker-cache.ts @@ -1,6 +1,6 @@ import fs from "node:fs/promises"; import path from "node:path"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { STATE_DIR } from "../config/paths.js"; import { loadJsonFile, saveJsonFile } from "../infra/json-file.js"; import { logVerbose } from "../globals.js"; @@ -146,7 +146,7 @@ const VISION_PROVIDERS = ["openai", "anthropic", "google", "minimax"] as const; export interface DescribeStickerParams { imagePath: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; agentDir?: string; agentId?: string; } diff --git a/src/telegram/token.test.ts b/src/telegram/token.test.ts index 08e17519a9..9f469721b9 100644 --- a/src/telegram/token.test.ts +++ b/src/telegram/token.test.ts @@ -4,11 +4,11 @@ import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveTelegramToken } from "./token.js"; function withTempDir(): string { - return fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-telegram-token-")); + return fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-telegram-token-")); } describe("resolveTelegramToken", () => { @@ -20,7 +20,7 @@ describe("resolveTelegramToken", () => { vi.stubEnv("TELEGRAM_BOT_TOKEN", "env-token"); const cfg = { channels: { telegram: { botToken: "cfg-token" } }, - } as MoltbotConfig; + } as OpenClawConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("cfg-token"); expect(res.source).toBe("config"); @@ -30,7 +30,7 @@ describe("resolveTelegramToken", () => { vi.stubEnv("TELEGRAM_BOT_TOKEN", "env-token"); const cfg = { channels: { telegram: {} }, - } as MoltbotConfig; + } as OpenClawConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("env-token"); expect(res.source).toBe("env"); @@ -41,7 +41,7 @@ describe("resolveTelegramToken", () => { const dir = withTempDir(); const tokenFile = path.join(dir, "token.txt"); fs.writeFileSync(tokenFile, "file-token\n", "utf-8"); - const cfg = { channels: { telegram: { tokenFile } } } as MoltbotConfig; + const cfg = { channels: { telegram: { tokenFile } } } as OpenClawConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("file-token"); expect(res.source).toBe("tokenFile"); @@ -52,7 +52,7 @@ describe("resolveTelegramToken", () => { vi.stubEnv("TELEGRAM_BOT_TOKEN", ""); const cfg = { channels: { telegram: { botToken: "cfg-token" } }, - } as MoltbotConfig; + } as OpenClawConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("cfg-token"); expect(res.source).toBe("config"); @@ -64,7 +64,7 @@ describe("resolveTelegramToken", () => { const tokenFile = path.join(dir, "missing-token.txt"); const cfg = { channels: { telegram: { tokenFile, botToken: "cfg-token" } }, - } as MoltbotConfig; + } as OpenClawConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe(""); expect(res.source).toBe("none"); diff --git a/src/telegram/token.ts b/src/telegram/token.ts index cf6ba5f62e..d830c7761c 100644 --- a/src/telegram/token.ts +++ b/src/telegram/token.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; export type TelegramTokenSource = "env" | "tokenFile" | "config" | "none"; @@ -17,7 +17,7 @@ type ResolveTelegramTokenOpts = { }; export function resolveTelegramToken( - cfg?: MoltbotConfig, + cfg?: OpenClawConfig, opts: ResolveTelegramTokenOpts = {}, ): TelegramTokenResolution { const accountId = normalizeAccountId(opts.accountId); diff --git a/src/telegram/update-offset-store.test.ts b/src/telegram/update-offset-store.test.ts index cab586173a..335adc2c71 100644 --- a/src/telegram/update-offset-store.test.ts +++ b/src/telegram/update-offset-store.test.ts @@ -7,14 +7,14 @@ import { describe, expect, it } from "vitest"; import { readTelegramUpdateOffset, writeTelegramUpdateOffset } from "./update-offset-store.js"; async function withTempStateDir(fn: (dir: string) => Promise) { - const previous = process.env.CLAWDBOT_STATE_DIR; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-telegram-")); - process.env.CLAWDBOT_STATE_DIR = dir; + const previous = process.env.OPENCLAW_STATE_DIR; + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-telegram-")); + process.env.OPENCLAW_STATE_DIR = dir; try { return await fn(dir); } finally { - if (previous === undefined) delete process.env.CLAWDBOT_STATE_DIR; - else process.env.CLAWDBOT_STATE_DIR = previous; + if (previous === undefined) delete process.env.OPENCLAW_STATE_DIR; + else process.env.OPENCLAW_STATE_DIR = previous; await fs.rm(dir, { recursive: true, force: true }); } } diff --git a/src/telegram/webhook.ts b/src/telegram/webhook.ts index e8c224eb27..1ae534ce21 100644 --- a/src/telegram/webhook.ts +++ b/src/telegram/webhook.ts @@ -1,7 +1,7 @@ import { createServer } from "node:http"; import { webhookCallback } from "grammy"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { isDiagnosticsEnabled } from "../infra/diagnostic-events.js"; import { formatErrorMessage } from "../infra/errors.js"; import type { RuntimeEnv } from "../runtime.js"; @@ -20,7 +20,7 @@ import { withTelegramApiErrorLogging } from "./api-logging.js"; export async function startTelegramWebhook(opts: { token: string; accountId?: string; - config?: MoltbotConfig; + config?: OpenClawConfig; path?: string; port?: number; host?: string; diff --git a/src/terminal/links.ts b/src/terminal/links.ts index 0d965633ab..879c279371 100644 --- a/src/terminal/links.ts +++ b/src/terminal/links.ts @@ -1,6 +1,6 @@ import { formatTerminalLink } from "../utils.js"; -export const DOCS_ROOT = "https://docs.molt.bot"; +export const DOCS_ROOT = "https://docs.openclaw.ai"; export function formatDocsLink( path: string, diff --git a/src/test-helpers/workspace.ts b/src/test-helpers/workspace.ts index 73b00629f5..6106e492d9 100644 --- a/src/test-helpers/workspace.ts +++ b/src/test-helpers/workspace.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -export async function makeTempWorkspace(prefix = "moltbot-workspace-"): Promise { +export async function makeTempWorkspace(prefix = "openclaw-workspace-"): Promise { return fs.mkdtemp(path.join(os.tmpdir(), prefix)); } diff --git a/src/tts/tts.test.ts b/src/tts/tts.test.ts index 8462cba018..996999bea2 100644 --- a/src/tts/tts.test.ts +++ b/src/tts/tts.test.ts @@ -449,8 +449,8 @@ describe("tts", () => { }; it("skips auto-TTS when inbound audio gating is on and the message is not audio", async () => { - const prevPrefs = process.env.CLAWDBOT_TTS_PREFS; - process.env.CLAWDBOT_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; + const prevPrefs = process.env.OPENCLAW_TTS_PREFS; + process.env.OPENCLAW_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; const originalFetch = globalThis.fetch; const fetchMock = vi.fn(async () => ({ ok: true, @@ -470,12 +470,12 @@ describe("tts", () => { expect(fetchMock).not.toHaveBeenCalled(); globalThis.fetch = originalFetch; - process.env.CLAWDBOT_TTS_PREFS = prevPrefs; + process.env.OPENCLAW_TTS_PREFS = prevPrefs; }); it("attempts auto-TTS when inbound audio gating is on and the message is audio", async () => { - const prevPrefs = process.env.CLAWDBOT_TTS_PREFS; - process.env.CLAWDBOT_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; + const prevPrefs = process.env.OPENCLAW_TTS_PREFS; + process.env.OPENCLAW_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; const originalFetch = globalThis.fetch; const fetchMock = vi.fn(async () => ({ ok: true, @@ -494,12 +494,12 @@ describe("tts", () => { expect(fetchMock).toHaveBeenCalledTimes(1); globalThis.fetch = originalFetch; - process.env.CLAWDBOT_TTS_PREFS = prevPrefs; + process.env.OPENCLAW_TTS_PREFS = prevPrefs; }); it("skips auto-TTS in tagged mode unless a tts tag is present", async () => { - const prevPrefs = process.env.CLAWDBOT_TTS_PREFS; - process.env.CLAWDBOT_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; + const prevPrefs = process.env.OPENCLAW_TTS_PREFS; + process.env.OPENCLAW_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; const originalFetch = globalThis.fetch; const fetchMock = vi.fn(async () => ({ ok: true, @@ -526,12 +526,12 @@ describe("tts", () => { expect(fetchMock).not.toHaveBeenCalled(); globalThis.fetch = originalFetch; - process.env.CLAWDBOT_TTS_PREFS = prevPrefs; + process.env.OPENCLAW_TTS_PREFS = prevPrefs; }); it("runs auto-TTS in tagged mode when tags are present", async () => { - const prevPrefs = process.env.CLAWDBOT_TTS_PREFS; - process.env.CLAWDBOT_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; + const prevPrefs = process.env.OPENCLAW_TTS_PREFS; + process.env.OPENCLAW_TTS_PREFS = `/tmp/tts-test-${Date.now()}.json`; const originalFetch = globalThis.fetch; const fetchMock = vi.fn(async () => ({ ok: true, @@ -557,7 +557,7 @@ describe("tts", () => { expect(fetchMock).toHaveBeenCalledTimes(1); globalThis.fetch = originalFetch; - process.env.CLAWDBOT_TTS_PREFS = prevPrefs; + process.env.OPENCLAW_TTS_PREFS = prevPrefs; }); }); }); diff --git a/src/tts/tts.ts b/src/tts/tts.ts index faa83d3a6c..c4c9ce3071 100644 --- a/src/tts/tts.ts +++ b/src/tts/tts.ts @@ -17,7 +17,7 @@ import { EdgeTTS } from "node-edge-tts"; import type { ReplyPayload } from "../auto-reply/types.js"; import { normalizeChannelId } from "../channels/plugins/index.js"; import type { ChannelId } from "../channels/plugins/types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { TtsConfig, TtsAutoMode, @@ -245,7 +245,7 @@ function resolveModelOverridePolicy( }; } -export function resolveTtsConfig(cfg: MoltbotConfig): ResolvedTtsConfig { +export function resolveTtsConfig(cfg: OpenClawConfig): ResolvedTtsConfig { const raw: TtsConfig = cfg.messages?.tts ?? {}; const providerSource = raw.provider ? "config" : "default"; const edgeOutputFormat = raw.edge?.outputFormat?.trim(); @@ -304,7 +304,7 @@ export function resolveTtsConfig(cfg: MoltbotConfig): ResolvedTtsConfig { export function resolveTtsPrefsPath(config: ResolvedTtsConfig): string { if (config.prefsPath?.trim()) return resolveUserPath(config.prefsPath.trim()); - const envPath = process.env.CLAWDBOT_TTS_PREFS?.trim(); + const envPath = process.env.OPENCLAW_TTS_PREFS?.trim(); if (envPath) return resolveUserPath(envPath); return path.join(CONFIG_DIR, "settings", "tts.json"); } @@ -330,7 +330,7 @@ export function resolveTtsAutoMode(params: { return params.config.auto; } -export function buildTtsSystemPromptHint(cfg: MoltbotConfig): string | undefined { +export function buildTtsSystemPromptHint(cfg: OpenClawConfig): string | undefined { const config = resolveTtsConfig(cfg); const prefsPath = resolveTtsPrefsPath(config); const autoMode = resolveTtsAutoMode({ config, prefsPath }); @@ -809,7 +809,7 @@ type SummaryModelSelection = { }; function resolveSummaryModelRef( - cfg: MoltbotConfig, + cfg: OpenClawConfig, config: ResolvedTtsConfig, ): SummaryModelSelection { const defaultRef = resolveDefaultModelForAgent({ cfg }); @@ -833,7 +833,7 @@ function isTextContentBlock(block: { type: string }): block is TextContent { async function summarizeText(params: { text: string; targetLength: number; - cfg: MoltbotConfig; + cfg: OpenClawConfig; config: ResolvedTtsConfig; timeoutMs: number; }): Promise { @@ -1078,7 +1078,7 @@ async function edgeTTS(params: { export async function textToSpeech(params: { text: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; prefsPath?: string; channel?: string; overrides?: TtsDirectiveOverrides; @@ -1249,7 +1249,7 @@ export async function textToSpeech(params: { export async function textToSpeechTelephony(params: { text: string; - cfg: MoltbotConfig; + cfg: OpenClawConfig; prefsPath?: string; }): Promise { const config = resolveTtsConfig(params.cfg); @@ -1343,7 +1343,7 @@ export async function textToSpeechTelephony(params: { export async function maybeApplyTtsToPayload(params: { payload: ReplyPayload; - cfg: MoltbotConfig; + cfg: OpenClawConfig; channel?: string; kind?: "tool" | "block" | "final"; inboundAudio?: boolean; diff --git a/src/tui/commands.ts b/src/tui/commands.ts index dfc4196328..f119a93ae7 100644 --- a/src/tui/commands.ts +++ b/src/tui/commands.ts @@ -1,7 +1,7 @@ import type { SlashCommand } from "@mariozechner/pi-tui"; import { listChatCommands, listChatCommandsForConfig } from "../auto-reply/commands-registry.js"; import { formatThinkingLevels, listThinkingLevelLabels } from "../auto-reply/thinking.js"; -import type { MoltbotConfig } from "../config/types.js"; +import type { OpenClawConfig } from "../config/types.js"; const VERBOSE_LEVELS = ["on", "off"]; const REASONING_LEVELS = ["on", "off"]; @@ -15,7 +15,7 @@ export type ParsedCommand = { }; export type SlashCommandOptions = { - cfg?: MoltbotConfig; + cfg?: OpenClawConfig; provider?: string; model?: string; }; diff --git a/src/tui/gateway-chat.ts b/src/tui/gateway-chat.ts index c13d48ccf5..0dc08e9c25 100644 --- a/src/tui/gateway-chat.ts +++ b/src/tui/gateway-chat.ts @@ -112,7 +112,7 @@ export class GatewayChatClient { token: resolved.token, password: resolved.password, clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT, - clientDisplayName: "moltbot-tui", + clientDisplayName: "openclaw-tui", clientVersion: VERSION, platform: process.platform, mode: GATEWAY_CLIENT_MODES.UI, @@ -235,7 +235,7 @@ export function resolveGatewayConnection(opts: GatewayConnectionOptions) { ? typeof remote?.token === "string" && remote.token.trim().length > 0 ? remote.token.trim() : undefined - : process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || + : process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || (typeof authToken === "string" && authToken.trim().length > 0 ? authToken.trim() : undefined)); @@ -244,7 +244,7 @@ export function resolveGatewayConnection(opts: GatewayConnectionOptions) { (typeof opts.password === "string" && opts.password.trim().length > 0 ? opts.password.trim() : undefined) || - process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || + process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || (typeof remote?.password === "string" && remote.password.trim().length > 0 ? remote.password.trim() : undefined); diff --git a/src/tui/tui.ts b/src/tui/tui.ts index a7e72f179f..566c6a1288 100644 --- a/src/tui/tui.ts +++ b/src/tui/tui.ts @@ -290,7 +290,7 @@ export async function runTui(opts: TuiOptions) { const agentLabel = formatAgentLabel(currentAgentId); header.setText( theme.header( - `moltbot tui - ${client.connection.url} - agent ${agentLabel} - session ${sessionLabel}`, + `openclaw tui - ${client.connection.url} - agent ${agentLabel} - session ${sessionLabel}`, ), ); }; diff --git a/src/utils.test.ts b/src/utils.test.ts index 769c98a4fe..22ebda7ee1 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -39,7 +39,7 @@ describe("withWhatsAppPrefix", () => { describe("ensureDir", () => { it("creates nested directory", async () => { - const tmp = await fs.promises.mkdtemp(path.join(os.tmpdir(), "moltbot-test-")); + const tmp = await fs.promises.mkdtemp(path.join(os.tmpdir(), "openclaw-test-")); const target = path.join(tmp, "nested", "dir"); await ensureDir(target); expect(fs.existsSync(target)).toBe(true); @@ -91,7 +91,7 @@ describe("jidToE164", () => { }); it("maps @lid from authDir mapping files", () => { - const authDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + const authDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); const mappingPath = path.join(authDir, "lid-mapping-456_reverse.json"); fs.writeFileSync(mappingPath, JSON.stringify("5559876")); expect(jidToE164("456@lid", { authDir })).toBe("+5559876"); @@ -99,7 +99,7 @@ describe("jidToE164", () => { }); it("maps @hosted.lid from authDir mapping files", () => { - const authDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + const authDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); const mappingPath = path.join(authDir, "lid-mapping-789_reverse.json"); fs.writeFileSync(mappingPath, JSON.stringify(4440001)); expect(jidToE164("789@hosted.lid", { authDir })).toBe("+4440001"); @@ -111,8 +111,8 @@ describe("jidToE164", () => { }); it("falls back through lidMappingDirs in order", () => { - const first = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-lid-a-")); - const second = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-lid-b-")); + const first = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-lid-a-")); + const second = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-lid-b-")); const mappingPath = path.join(second, "lid-mapping-321_reverse.json"); fs.writeFileSync(mappingPath, JSON.stringify("123321")); expect(jidToE164("321@lid", { lidMappingDirs: [first, second] })).toBe("+123321"); @@ -122,10 +122,10 @@ describe("jidToE164", () => { }); describe("resolveConfigDir", () => { - it("prefers ~/.moltbot when legacy dir is missing", async () => { - const root = await fs.promises.mkdtemp(path.join(os.tmpdir(), "moltbot-config-dir-")); + it("prefers ~/.openclaw when legacy dir is missing", async () => { + const root = await fs.promises.mkdtemp(path.join(os.tmpdir(), "openclaw-config-dir-")); try { - const newDir = path.join(root, ".moltbot"); + const newDir = path.join(root, ".openclaw"); await fs.promises.mkdir(newDir, { recursive: true }); const resolved = resolveConfigDir({} as NodeJS.ProcessEnv, () => root); expect(resolved).toBe(newDir); @@ -159,7 +159,7 @@ describe("resolveUserPath", () => { }); it("expands ~/ to home dir", () => { - expect(resolveUserPath("~/clawd")).toBe(path.resolve(os.homedir(), "clawd")); + expect(resolveUserPath("~/openclaw")).toBe(path.resolve(os.homedir(), "openclaw")); }); it("resolves relative paths", () => { diff --git a/src/utils.ts b/src/utils.ts index 7c441f4f10..86bb1e06fe 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -215,18 +215,16 @@ export function resolveConfigDir( env: NodeJS.ProcessEnv = process.env, homedir: () => string = os.homedir, ): string { - const override = env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim(); + const override = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim(); if (override) return resolveUserPath(override); - const legacyDir = path.join(homedir(), ".clawdbot"); - const newDir = path.join(homedir(), ".moltbot"); + const newDir = path.join(homedir(), ".openclaw"); try { - const hasLegacy = fs.existsSync(legacyDir); const hasNew = fs.existsSync(newDir); - if (!hasLegacy && hasNew) return newDir; + if (hasNew) return newDir; } catch { // best-effort } - return legacyDir; + return newDir; } export function resolveHomeDir(): string | undefined { @@ -282,5 +280,5 @@ export function formatTerminalLink( return `\u001b]8;;${safeUrl}\u0007${safeLabel}\u001b]8;;\u0007`; } -// Configuration root; can be overridden via CLAWDBOT_STATE_DIR. +// Configuration root; can be overridden via OPENCLAW_STATE_DIR. export const CONFIG_DIR = resolveConfigDir(); diff --git a/src/utils/usage-format.test.ts b/src/utils/usage-format.test.ts index 12da3b182e..8d7985f4df 100644 --- a/src/utils/usage-format.test.ts +++ b/src/utils/usage-format.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { estimateUsageCost, formatTokenCount, @@ -35,7 +35,7 @@ describe("usage-format", () => { }, }, }, - } as MoltbotConfig; + } as OpenClawConfig; const cost = resolveModelCostConfig({ provider: "test", diff --git a/src/utils/usage-format.ts b/src/utils/usage-format.ts index 962e55bc49..77e5497b10 100644 --- a/src/utils/usage-format.ts +++ b/src/utils/usage-format.ts @@ -1,5 +1,5 @@ import type { NormalizedUsage } from "../agents/usage.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; export type ModelCostConfig = { input: number; @@ -34,7 +34,7 @@ export function formatUsd(value?: number): string | undefined { export function resolveModelCostConfig(params: { provider?: string; model?: string; - config?: MoltbotConfig; + config?: OpenClawConfig; }): ModelCostConfig | undefined { const provider = params.provider?.trim(); const model = params.model?.trim(); diff --git a/src/version.ts b/src/version.ts index 18c3a3b73d..e254dd91fe 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,6 +1,6 @@ import { createRequire } from "node:module"; -declare const __CLAWDBOT_VERSION__: string | undefined; +declare const __OPENCLAW_VERSION__: string | undefined; function readVersionFromPackageJson(): string | null { try { @@ -12,11 +12,11 @@ function readVersionFromPackageJson(): string | null { } } -// Single source of truth for the current moltbot version. +// Single source of truth for the current OpenClaw version. // - Embedded/bundled builds: injected define or env var. // - Dev/npm builds: package.json. export const VERSION = - (typeof __CLAWDBOT_VERSION__ === "string" && __CLAWDBOT_VERSION__) || - process.env.CLAWDBOT_BUNDLED_VERSION || + (typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) || + process.env.OPENCLAW_BUNDLED_VERSION || readVersionFromPackageJson() || "0.0.0"; diff --git a/src/web/accounts.ts b/src/web/accounts.ts index 79b6ea6427..c5010a741e 100644 --- a/src/web/accounts.ts +++ b/src/web/accounts.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveOAuthDir } from "../config/paths.js"; import type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "../config/types.js"; import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js"; @@ -30,13 +30,13 @@ export type ResolvedWhatsAppAccount = { debounceMs?: number; }; -function listConfiguredAccountIds(cfg: MoltbotConfig): string[] { +function listConfiguredAccountIds(cfg: OpenClawConfig): string[] { const accounts = cfg.channels?.whatsapp?.accounts; if (!accounts || typeof accounts !== "object") return []; return Object.keys(accounts).filter(Boolean); } -export function listWhatsAppAuthDirs(cfg: MoltbotConfig): string[] { +export function listWhatsAppAuthDirs(cfg: OpenClawConfig): string[] { const oauthDir = resolveOAuthDir(); const whatsappDir = path.join(oauthDir, "whatsapp"); const authDirs = new Set([oauthDir, path.join(whatsappDir, DEFAULT_ACCOUNT_ID)]); @@ -59,24 +59,24 @@ export function listWhatsAppAuthDirs(cfg: MoltbotConfig): string[] { return Array.from(authDirs); } -export function hasAnyWhatsAppAuth(cfg: MoltbotConfig): boolean { +export function hasAnyWhatsAppAuth(cfg: OpenClawConfig): boolean { return listWhatsAppAuthDirs(cfg).some((authDir) => hasWebCredsSync(authDir)); } -export function listWhatsAppAccountIds(cfg: MoltbotConfig): string[] { +export function listWhatsAppAccountIds(cfg: OpenClawConfig): string[] { const ids = listConfiguredAccountIds(cfg); if (ids.length === 0) return [DEFAULT_ACCOUNT_ID]; return ids.sort((a, b) => a.localeCompare(b)); } -export function resolveDefaultWhatsAppAccountId(cfg: MoltbotConfig): string { +export function resolveDefaultWhatsAppAccountId(cfg: OpenClawConfig): string { const ids = listWhatsAppAccountIds(cfg); if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID; return ids[0] ?? DEFAULT_ACCOUNT_ID; } function resolveAccountConfig( - cfg: MoltbotConfig, + cfg: OpenClawConfig, accountId: string, ): WhatsAppAccountConfig | undefined { const accounts = cfg.channels?.whatsapp?.accounts; @@ -102,7 +102,7 @@ function legacyAuthExists(authDir: string): boolean { } } -export function resolveWhatsAppAuthDir(params: { cfg: MoltbotConfig; accountId: string }): { +export function resolveWhatsAppAuthDir(params: { cfg: OpenClawConfig; accountId: string }): { authDir: string; isLegacy: boolean; } { @@ -125,7 +125,7 @@ export function resolveWhatsAppAuthDir(params: { cfg: MoltbotConfig; accountId: } export function resolveWhatsAppAccount(params: { - cfg: MoltbotConfig; + cfg: OpenClawConfig; accountId?: string | null; }): ResolvedWhatsAppAccount { const rootCfg = params.cfg.channels?.whatsapp; @@ -160,7 +160,7 @@ export function resolveWhatsAppAccount(params: { }; } -export function listEnabledWhatsAppAccounts(cfg: MoltbotConfig): ResolvedWhatsAppAccount[] { +export function listEnabledWhatsAppAccounts(cfg: OpenClawConfig): ResolvedWhatsAppAccount[] { return listWhatsAppAccountIds(cfg) .map((accountId) => resolveWhatsAppAccount({ cfg, accountId })) .filter((account) => account.enabled); diff --git a/src/web/accounts.whatsapp-auth.test.ts b/src/web/accounts.whatsapp-auth.test.ts index b754a89829..cc28808650 100644 --- a/src/web/accounts.whatsapp-auth.test.ts +++ b/src/web/accounts.whatsapp-auth.test.ts @@ -15,16 +15,16 @@ describe("hasAnyWhatsAppAuth", () => { }; beforeEach(() => { - previousOauthDir = process.env.CLAWDBOT_OAUTH_DIR; - tempOauthDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-oauth-")); - process.env.CLAWDBOT_OAUTH_DIR = tempOauthDir; + previousOauthDir = process.env.OPENCLAW_OAUTH_DIR; + tempOauthDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-oauth-")); + process.env.OPENCLAW_OAUTH_DIR = tempOauthDir; }); afterEach(() => { if (previousOauthDir === undefined) { - delete process.env.CLAWDBOT_OAUTH_DIR; + delete process.env.OPENCLAW_OAUTH_DIR; } else { - process.env.CLAWDBOT_OAUTH_DIR = previousOauthDir; + process.env.OPENCLAW_OAUTH_DIR = previousOauthDir; } if (tempOauthDir) { fs.rmSync(tempOauthDir, { recursive: true, force: true }); @@ -47,7 +47,7 @@ describe("hasAnyWhatsAppAuth", () => { }); it("includes authDir overrides", () => { - const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-wa-auth-")); + const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-wa-auth-")); try { writeCreds(customDir); const cfg = { diff --git a/src/web/active-listener.ts b/src/web/active-listener.ts index 233f11a8f9..d01372ed09 100644 --- a/src/web/active-listener.ts +++ b/src/web/active-listener.ts @@ -43,7 +43,7 @@ export function requireActiveWebListener(accountId?: string | null): { const listener = listeners.get(id) ?? null; if (!listener) { throw new Error( - `No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`moltbot channels login --channel whatsapp --account ${id}`)}.`, + `No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`openclaw channels login --channel whatsapp --account ${id}`)}.`, ); } return { accountId: id, listener }; diff --git a/src/web/auth-store.ts b/src/web/auth-store.ts index 3e22fd22b3..f79ef92708 100644 --- a/src/web/auth-store.ts +++ b/src/web/auth-store.ts @@ -177,7 +177,7 @@ export async function pickWebChannel( const hasWeb = await webAuthExists(authDir); if (!hasWeb) { throw new Error( - `No WhatsApp Web session found. Run \`${formatCliCommand("moltbot channels login --channel whatsapp --verbose")}\` to link.`, + `No WhatsApp Web session found. Run \`${formatCliCommand("openclaw channels login --channel whatsapp --verbose")}\` to link.`, ); } return choice; diff --git a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts b/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts index b8e19e6aaa..2d31b7babb 100644 --- a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts +++ b/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts @@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({ })); import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { monitorWebChannel } from "./auto-reply.js"; import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js"; @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -104,7 +104,7 @@ describe("broadcast groups", () => { strategy: "sequential", "+1000": ["alfred", "baerbel"], }, - } satisfies MoltbotConfig); + } satisfies OpenClawConfig); const sendMedia = vi.fn(); const reply = vi.fn().mockResolvedValue(undefined); @@ -158,7 +158,7 @@ describe("broadcast groups", () => { strategy: "sequential", "123@g.us": ["alfred", "baerbel"], }, - } satisfies MoltbotConfig); + } satisfies OpenClawConfig); const sendMedia = vi.fn(); const reply = vi.fn().mockResolvedValue(undefined); @@ -269,7 +269,7 @@ describe("broadcast groups", () => { strategy: "parallel", "+1000": ["alfred", "baerbel"], }, - } satisfies MoltbotConfig); + } satisfies OpenClawConfig); const sendMedia = vi.fn(); const reply = vi.fn().mockResolvedValue(undefined); diff --git a/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts b/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts index 8c2f9045e1..bceb904192 100644 --- a/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts +++ b/src/web/auto-reply.broadcast-groups.skips-unknown-broadcast-agent-ids-agents-list.test.ts @@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({ })); import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { monitorWebChannel } from "./auto-reply.js"; import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js"; @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -103,7 +103,7 @@ describe("broadcast groups", () => { broadcast: { "+1000": ["alfred", "missing"], }, - } satisfies MoltbotConfig); + } satisfies OpenClawConfig); const sendMedia = vi.fn(); const reply = vi.fn().mockResolvedValue(undefined); diff --git a/src/web/auto-reply.partial-reply-gating.test.ts b/src/web/auto-reply.partial-reply-gating.test.ts index 43bb22db1d..d4ebc58702 100644 --- a/src/web/auto-reply.partial-reply-gating.test.ts +++ b/src/web/auto-reply.partial-reply-gating.test.ts @@ -16,7 +16,7 @@ vi.mock("../agents/pi-embedded.js", () => ({ import { runEmbeddedPiAgent } from "../agents/pi-embedded.js"; import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; import { getReplyFromConfig } from "../auto-reply/reply.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { monitorWebChannel } from "./auto-reply.js"; import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js"; @@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -63,7 +63,7 @@ afterEach(async () => { const makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -102,7 +102,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" }); - const mockConfig: MoltbotConfig = { + const mockConfig: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["*"] } }, }; @@ -145,7 +145,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" }); - const mockConfig: MoltbotConfig = { + const mockConfig: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["*"], @@ -195,7 +195,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue(undefined); - const mockConfig: MoltbotConfig = { + const mockConfig: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["*"] } }, session: { store: store.storePath }, }; @@ -249,7 +249,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue(undefined); - const mockConfig: MoltbotConfig = { + const mockConfig: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["*"] } }, session: { store: store.storePath }, }; diff --git a/src/web/auto-reply.typing-controller-idle.test.ts b/src/web/auto-reply.typing-controller-idle.test.ts index b805832c9d..d9ba0f46b1 100644 --- a/src/web/auto-reply.typing-controller-idle.test.ts +++ b/src/web/auto-reply.typing-controller-idle.test.ts @@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({ })); import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { monitorWebChannel } from "./auto-reply.js"; import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js"; @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -114,7 +114,7 @@ describe("typing controller idle", () => { return { text: "final reply" }; }); - const mockConfig: MoltbotConfig = { + const mockConfig: OpenClawConfig = { channels: { whatsapp: { allowFrom: ["*"] } }, }; diff --git a/src/web/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts b/src/web/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts index 7ec81e7ff1..60d9fb83ef 100644 --- a/src/web/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +++ b/src/web/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts @@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -63,7 +63,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { diff --git a/src/web/auto-reply.web-auto-reply.falls-back-text-media-send-fails.test.ts b/src/web/auto-reply.web-auto-reply.falls-back-text-media-send-fails.test.ts index 2c16df2ccf..c1bc72d6f8 100644 --- a/src/web/auto-reply.web-auto-reply.falls-back-text-media-send-fails.test.ts +++ b/src/web/auto-reply.web-auto-reply.falls-back-text-media-send-fails.test.ts @@ -47,7 +47,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -62,7 +62,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { diff --git a/src/web/auto-reply.web-auto-reply.prefixes-body-same-phone-marker-from.test.ts b/src/web/auto-reply.web-auto-reply.prefixes-body-same-phone-marker-from.test.ts index dd27bad8ad..2616c98c70 100644 --- a/src/web/auto-reply.web-auto-reply.prefixes-body-same-phone-marker-from.test.ts +++ b/src/web/auto-reply.web-auto-reply.prefixes-body-same-phone-marker-from.test.ts @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { diff --git a/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts b/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts index aa5bc8ba05..9c6bcd37ef 100644 --- a/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts +++ b/src/web/auto-reply.web-auto-reply.reconnects-after-connection-close.test.ts @@ -47,7 +47,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -62,7 +62,7 @@ afterEach(async () => { const makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -339,11 +339,11 @@ describe("web auto-reply", () => { const firstPattern = escapeRegExp(firstTimestamp); const secondPattern = escapeRegExp(secondTimestamp); expect(firstArgs.Body).toMatch( - new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${firstPattern}\\] \\[moltbot\\] first`), + new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${firstPattern}\\] \\[openclaw\\] first`), ); expect(firstArgs.Body).not.toContain("second"); expect(secondArgs.Body).toMatch( - new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${secondPattern}\\] \\[moltbot\\] second`), + new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${secondPattern}\\] \\[openclaw\\] second`), ); expect(secondArgs.Body).not.toContain("first"); diff --git a/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts b/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts index d8b3a38e7f..11ee7ce485 100644 --- a/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts +++ b/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -366,7 +366,7 @@ describe("web auto-reply", () => { return { close: vi.fn() }; }; - const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wa-auth-")); + const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wa-auth-")); try { await fs.writeFile( @@ -444,7 +444,7 @@ describe("web auto-reply", () => { return { close: vi.fn() }; }; - const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wa-auth-")); + const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wa-auth-")); try { await fs.writeFile( diff --git a/src/web/auto-reply.web-auto-reply.sends-tool-summaries-immediately-responseprefix.test.ts b/src/web/auto-reply.web-auto-reply.sends-tool-summaries-immediately-responseprefix.test.ts index 8232241863..f689b7a33d 100644 --- a/src/web/auto-reply.web-auto-reply.sends-tool-summaries-immediately-responseprefix.test.ts +++ b/src/web/auto-reply.web-auto-reply.sends-tool-summaries-immediately-responseprefix.test.ts @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -200,7 +200,7 @@ describe("web auto-reply", () => { expect(resolver).toHaveBeenCalled(); const resolverArg = resolver.mock.calls[0][0]; expect(resolverArg.Body).toContain("[Richbot]"); - expect(resolverArg.Body).not.toContain("[moltbot]"); + expect(resolverArg.Body).not.toContain("[openclaw]"); resetLoadConfigMock(); }); it("does not derive responsePrefix from identity.name when unset", async () => { diff --git a/src/web/auto-reply.web-auto-reply.supports-always-group-activation-silent-token-preserves.test.ts b/src/web/auto-reply.web-auto-reply.supports-always-group-activation-silent-token-preserves.test.ts index 6ace563273..ddddad1ea7 100644 --- a/src/web/auto-reply.web-auto-reply.supports-always-group-activation-silent-token-preserves.test.ts +++ b/src/web/auto-reply.web-auto-reply.supports-always-group-activation-silent-token-preserves.test.ts @@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -63,7 +63,7 @@ afterEach(async () => { const makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -126,7 +126,7 @@ describe("web auto-reply", () => { setLoadConfigMock(() => ({ messages: { - groupChat: { mentionPatterns: ["@clawd"] }, + groupChat: { mentionPatterns: ["@openclaw"] }, }, session: { store: storePath }, })); @@ -209,7 +209,7 @@ describe("web auto-reply", () => { }, messages: { groupChat: { - mentionPatterns: ["\\bclawd\\b"], + mentionPatterns: ["\\bopenclaw\\b"], }, }, })); @@ -248,9 +248,9 @@ describe("web auto-reply", () => { expect(resolver).not.toHaveBeenCalled(); - // Text-based mentionPatterns still work (user can type "clawd" explicitly). + // Text-based mentionPatterns still work (user can type "openclaw" explicitly). await capturedOnMessage?.({ - body: "clawd ping", + body: "openclaw ping", from: "123@g.us", conversationId: "123@g.us", chatId: "123@g.us", @@ -272,7 +272,7 @@ describe("web auto-reply", () => { }); it("emits heartbeat logs with connection metadata", async () => { vi.useFakeTimers(); - const logPath = `/tmp/moltbot-heartbeat-${crypto.randomUUID()}.log`; + const logPath = `/tmp/openclaw-heartbeat-${crypto.randomUUID()}.log`; setLoggerOverride({ level: "trace", file: logPath }); const runtime = { @@ -313,7 +313,7 @@ describe("web auto-reply", () => { expect(content).toMatch(/messagesHandled/); }); it("logs outbound replies to file", async () => { - const logPath = `/tmp/moltbot-log-test-${crypto.randomUUID()}.log`; + const logPath = `/tmp/openclaw-log-test-${crypto.randomUUID()}.log`; setLoggerOverride({ level: "trace", file: logPath }); let capturedOnMessage: diff --git a/src/web/auto-reply.web-auto-reply.uses-per-agent-mention-patterns-group-gating.test.ts b/src/web/auto-reply.web-auto-reply.uses-per-agent-mention-patterns-group-gating.test.ts index 64f448ebc4..80d63055e6 100644 --- a/src/web/auto-reply.web-auto-reply.uses-per-agent-mention-patterns-group-gating.test.ts +++ b/src/web/auto-reply.web-auto-reply.uses-per-agent-mention-patterns-group-gating.test.ts @@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { resetInboundDedupe(); previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-")); process.env.HOME = tempHome; }); @@ -61,7 +61,7 @@ afterEach(async () => { const _makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -200,7 +200,7 @@ describe("web auto-reply", () => { groups: { "*": { requireMention: false } }, }, }, - messages: { groupChat: { mentionPatterns: ["@clawd"] } }, + messages: { groupChat: { mentionPatterns: ["@openclaw"] } }, })); let capturedOnMessage: @@ -248,7 +248,7 @@ describe("web auto-reply", () => { groups: { "999@g.us": { requireMention: false } }, }, }, - messages: { groupChat: { mentionPatterns: ["@clawd"] } }, + messages: { groupChat: { mentionPatterns: ["@openclaw"] } }, })); let capturedOnMessage: @@ -265,7 +265,7 @@ describe("web auto-reply", () => { expect(capturedOnMessage).toBeDefined(); await capturedOnMessage?.({ - body: "@clawd hello", + body: "@openclaw hello", from: "123@g.us", conversationId: "123@g.us", chatId: "123@g.us", @@ -301,7 +301,7 @@ describe("web auto-reply", () => { }, }, }, - messages: { groupChat: { mentionPatterns: ["@clawd"] } }, + messages: { groupChat: { mentionPatterns: ["@openclaw"] } }, })); let capturedOnMessage: diff --git a/src/web/auto-reply/mentions.test.ts b/src/web/auto-reply/mentions.test.ts index 62d8613bc6..f7ea598b49 100644 --- a/src/web/auto-reply/mentions.test.ts +++ b/src/web/auto-reply/mentions.test.ts @@ -19,11 +19,11 @@ const makeMsg = (overrides: Partial): WebInboundMsg => }) as WebInboundMsg; describe("isBotMentionedFromTargets", () => { - const mentionCfg = { mentionRegexes: [/\bclawd\b/i] }; + const mentionCfg = { mentionRegexes: [/\bopenclaw\b/i] }; it("ignores regex matches when other mentions are present", () => { const msg = makeMsg({ - body: "@Clawd please help", + body: "@OpenClaw please help", mentionedJids: ["19998887777@s.whatsapp.net"], selfE164: "+15551234567", selfJid: "15551234567@s.whatsapp.net", @@ -45,7 +45,7 @@ describe("isBotMentionedFromTargets", () => { it("falls back to regex when no mentions are present", () => { const msg = makeMsg({ - body: "clawd can you help?", + body: "openclaw can you help?", selfE164: "+15551234567", selfJid: "15551234567@s.whatsapp.net", }); diff --git a/src/web/auto-reply/monitor.ts b/src/web/auto-reply/monitor.ts index 791b389677..6d05a13092 100644 --- a/src/web/auto-reply/monitor.ts +++ b/src/web/auto-reply/monitor.ts @@ -376,7 +376,7 @@ export async function monitorWebChannel( if (loggedOut) { runtime.error( - `WhatsApp session logged out. Run \`${formatCliCommand("moltbot channels login --channel web")}\` to relink.`, + `WhatsApp session logged out. Run \`${formatCliCommand("openclaw channels login --channel web")}\` to relink.`, ); await closeListener(); break; diff --git a/src/web/auto-reply/monitor/group-gating.test.ts b/src/web/auto-reply/monitor/group-gating.test.ts index f707b592b4..b0dc1e2f6a 100644 --- a/src/web/auto-reply/monitor/group-gating.test.ts +++ b/src/web/auto-reply/monitor/group-gating.test.ts @@ -9,7 +9,7 @@ const baseConfig = { groups: { "*": { requireMention: true } }, }, }, - session: { store: "/tmp/moltbot-sessions.json" }, + session: { store: "/tmp/openclaw-sessions.json" }, } as const; describe("applyGroupGating", () => { diff --git a/src/web/auto-reply/monitor/message-line.test.ts b/src/web/auto-reply/monitor/message-line.test.ts index 9e0bf9ede4..ad9bc475e0 100644 --- a/src/web/auto-reply/monitor/message-line.test.ts +++ b/src/web/auto-reply/monitor/message-line.test.ts @@ -6,7 +6,7 @@ describe("buildInboundLine", () => { it("prefixes group messages with sender", () => { const line = buildInboundLine({ cfg: { - agents: { defaults: { workspace: "/tmp/clawd" } }, + agents: { defaults: { workspace: "/tmp/openclaw" } }, channels: { whatsapp: { messagePrefix: "" } }, } as never, agentId: "main", diff --git a/src/web/auto-reply/monitor/process-message.ts b/src/web/auto-reply/monitor/process-message.ts index 84f03cf0b4..27b638cfbc 100644 --- a/src/web/auto-reply/monitor/process-message.ts +++ b/src/web/auto-reply/monitor/process-message.ts @@ -252,7 +252,7 @@ export async function processMessage(params: { const responsePrefix = prefixContext.responsePrefix ?? (configuredResponsePrefix === undefined && isSelfChat - ? (resolveIdentityNamePrefix(params.cfg, params.route.agentId) ?? "[moltbot]") + ? (resolveIdentityNamePrefix(params.cfg, params.route.agentId) ?? "[openclaw]") : undefined); const ctxPayload = finalizeInboundContext({ diff --git a/src/web/auto-reply/session-snapshot.test.ts b/src/web/auto-reply/session-snapshot.test.ts index de79ba5976..112641a6e9 100644 --- a/src/web/auto-reply/session-snapshot.test.ts +++ b/src/web/auto-reply/session-snapshot.test.ts @@ -12,7 +12,7 @@ describe("getSessionSnapshot", () => { vi.useFakeTimers(); vi.setSystemTime(new Date(2026, 0, 18, 5, 0, 0)); try { - const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-snapshot-")); + const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-snapshot-")); const storePath = path.join(root, "sessions.json"); const sessionKey = "agent:main:whatsapp:dm:s1"; diff --git a/src/web/inbound.media.test.ts b/src/web/inbound.media.test.ts index 49ba93a952..13474578a1 100644 --- a/src/web/inbound.media.test.ts +++ b/src/web/inbound.media.test.ts @@ -43,7 +43,7 @@ vi.mock("../media/store.js", async (importOriginal) => { }; }); -const HOME = path.join(os.tmpdir(), `moltbot-inbound-media-${crypto.randomUUID()}`); +const HOME = path.join(os.tmpdir(), `openclaw-inbound-media-${crypto.randomUUID()}`); process.env.HOME = HOME; vi.mock("@whiskeysockets/baileys", async () => { diff --git a/src/web/login.ts b/src/web/login.ts index 845fa23b03..4b82422546 100644 --- a/src/web/login.ts +++ b/src/web/login.ts @@ -57,7 +57,7 @@ export async function loginWeb( }); console.error( danger( - `WhatsApp reported the session is logged out. Cleared cached web session; please rerun ${formatCliCommand("moltbot channels login")} and scan the QR again.`, + `WhatsApp reported the session is logged out. Cleared cached web session; please rerun ${formatCliCommand("openclaw channels login")} and scan the QR again.`, ), ); throw new Error("Session logged out; cache cleared. Re-run login."); diff --git a/src/web/media.test.ts b/src/web/media.test.ts index bafac9bcda..b14c3778df 100644 --- a/src/web/media.test.ts +++ b/src/web/media.test.ts @@ -13,7 +13,7 @@ const tmpFiles: string[] = []; async function writeTempFile(buffer: Buffer, ext: string): Promise { const file = path.join( os.tmpdir(), - `moltbot-media-${Date.now()}-${Math.random().toString(16).slice(2)}${ext}`, + `openclaw-media-${Date.now()}-${Math.random().toString(16).slice(2)}${ext}`, ); tmpFiles.push(file); await fs.writeFile(file, buffer); diff --git a/src/web/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts b/src/web/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts index a9da1d6bb7..d341321902 100644 --- a/src/web/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts +++ b/src/web/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts @@ -88,7 +88,7 @@ describe("web monitor inbox", () => { created: true, }); resetWebInboundDedupe(); - authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); }); afterEach(() => { diff --git a/src/web/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test.ts b/src/web/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test.ts index 002f85f4a8..f190245cc6 100644 --- a/src/web/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test.ts +++ b/src/web/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test.ts @@ -88,7 +88,7 @@ describe("web monitor inbox", () => { created: true, }); resetWebInboundDedupe(); - authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); }); afterEach(() => { diff --git a/src/web/monitor-inbox.captures-media-path-image-messages.test.ts b/src/web/monitor-inbox.captures-media-path-image-messages.test.ts index a29e83556e..e438ea4cd3 100644 --- a/src/web/monitor-inbox.captures-media-path-image-messages.test.ts +++ b/src/web/monitor-inbox.captures-media-path-image-messages.test.ts @@ -88,7 +88,7 @@ describe("web monitor inbox", () => { created: true, }); resetWebInboundDedupe(); - authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); }); afterEach(() => { @@ -171,7 +171,7 @@ describe("web monitor inbox", () => { }); it("logs inbound bodies to file", async () => { - const logPath = path.join(os.tmpdir(), `moltbot-log-test-${crypto.randomUUID()}.log`); + const logPath = path.join(os.tmpdir(), `openclaw-log-test-${crypto.randomUUID()}.log`); setLoggerOverride({ level: "trace", file: logPath }); const onMessage = vi.fn(); diff --git a/src/web/monitor-inbox.streams-inbound-messages.test.ts b/src/web/monitor-inbox.streams-inbound-messages.test.ts index 1f1c616566..7a8c93a9be 100644 --- a/src/web/monitor-inbox.streams-inbound-messages.test.ts +++ b/src/web/monitor-inbox.streams-inbound-messages.test.ts @@ -87,7 +87,7 @@ describe("web monitor inbox", () => { created: true, }); resetWebInboundDedupe(); - authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-")); + authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); }); afterEach(() => { diff --git a/src/web/qr-image.test.ts b/src/web/qr-image.test.ts index fdd2ad779f..229a2de65b 100644 --- a/src/web/qr-image.test.ts +++ b/src/web/qr-image.test.ts @@ -7,7 +7,7 @@ import { renderQrPngBase64 } from "./qr-image.js"; describe("renderQrPngBase64", () => { it("renders a PNG data payload", async () => { - const b64 = await renderQrPngBase64("moltbot"); + const b64 = await renderQrPngBase64("openclaw"); const buf = Buffer.from(b64, "base64"); expect(buf.subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a"); }); diff --git a/src/web/reconnect.test.ts b/src/web/reconnect.test.ts index 63c5fba808..173c5d53a3 100644 --- a/src/web/reconnect.test.ts +++ b/src/web/reconnect.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { computeBackoff, DEFAULT_HEARTBEAT_SECONDS, @@ -11,7 +11,7 @@ import { } from "./reconnect.js"; describe("web reconnect helpers", () => { - const cfg: MoltbotConfig = {}; + const cfg: OpenClawConfig = {}; it("resolves sane reconnect defaults with clamps", () => { const policy = resolveReconnectPolicy(cfg, { diff --git a/src/web/reconnect.ts b/src/web/reconnect.ts index f727b7f9ac..86d19f7772 100644 --- a/src/web/reconnect.ts +++ b/src/web/reconnect.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import type { BackoffPolicy } from "../infra/backoff.js"; import { computeBackoff, sleepWithAbort } from "../infra/backoff.js"; @@ -19,14 +19,14 @@ export const DEFAULT_RECONNECT_POLICY: ReconnectPolicy = { const clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val)); -export function resolveHeartbeatSeconds(cfg: MoltbotConfig, overrideSeconds?: number): number { +export function resolveHeartbeatSeconds(cfg: OpenClawConfig, overrideSeconds?: number): number { const candidate = overrideSeconds ?? cfg.web?.heartbeatSeconds; if (typeof candidate === "number" && candidate > 0) return candidate; return DEFAULT_HEARTBEAT_SECONDS; } export function resolveReconnectPolicy( - cfg: MoltbotConfig, + cfg: OpenClawConfig, overrides?: Partial, ): ReconnectPolicy { const reconnectOverrides = cfg.web?.reconnect ?? {}; diff --git a/src/web/session.test.ts b/src/web/session.test.ts index db38c58931..3279e045ab 100644 --- a/src/web/session.test.ts +++ b/src/web/session.test.ts @@ -106,7 +106,7 @@ describe("web session", () => { }); it("does not clobber creds backup when creds.json is corrupted", async () => { - const credsSuffix = path.join(".clawdbot", "credentials", "whatsapp", "default", "creds.json"); + const credsSuffix = path.join(".openclaw", "credentials", "whatsapp", "default", "creds.json"); const copySpy = vi.spyOn(fsSync, "copyFileSync").mockImplementation(() => {}); const existsSpy = vi.spyOn(fsSync, "existsSync").mockImplementation((p) => { @@ -182,9 +182,9 @@ describe("web session", () => { }); it("rotates creds backup when creds.json is valid JSON", async () => { - const credsSuffix = path.join(".clawdbot", "credentials", "whatsapp", "default", "creds.json"); + const credsSuffix = path.join(".openclaw", "credentials", "whatsapp", "default", "creds.json"); const backupSuffix = path.join( - ".clawdbot", + ".openclaw", "credentials", "whatsapp", "default", diff --git a/src/web/session.ts b/src/web/session.ts index dcf0e253fa..9e877d8db1 100644 --- a/src/web/session.ts +++ b/src/web/session.ts @@ -114,7 +114,7 @@ export async function createWaSocket( version, logger, printQRInTerminal: false, - browser: ["moltbot", "cli", VERSION], + browser: ["openclaw", "cli", VERSION], syncFullHistory: false, markOnlineOnConnect: false, }); @@ -137,7 +137,7 @@ export async function createWaSocket( if (status === DisconnectReason.loggedOut) { console.error( danger( - `WhatsApp session logged out. Run: ${formatCliCommand("moltbot channels login")}`, + `WhatsApp session logged out. Run: ${formatCliCommand("openclaw channels login")}`, ), ); } diff --git a/src/web/test-helpers.ts b/src/web/test-helpers.ts index 2bb58e8a60..4e66f6475d 100644 --- a/src/web/test-helpers.ts +++ b/src/web/test-helpers.ts @@ -4,7 +4,7 @@ import type { MockBaileysSocket } from "../../test/mocks/baileys.js"; import { createMockBaileys } from "../../test/mocks/baileys.js"; // Use globalThis to store the mock config so it survives vi.mock hoisting -const CONFIG_KEY = Symbol.for("moltbot:testConfigMock"); +const CONFIG_KEY = Symbol.for("openclaw:testConfigMock"); const DEFAULT_CONFIG = { channels: { whatsapp: { @@ -54,7 +54,7 @@ vi.mock("../media/store.js", () => ({ vi.mock("@whiskeysockets/baileys", () => { const created = createMockBaileys(); - (globalThis as Record)[Symbol.for("moltbot:lastSocket")] = + (globalThis as Record)[Symbol.for("openclaw:lastSocket")] = created.lastSocket; return created.mod; }); @@ -74,7 +74,7 @@ export const baileys = export function resetBaileysMocks() { const recreated = createMockBaileys(); - (globalThis as Record)[Symbol.for("moltbot:lastSocket")] = + (globalThis as Record)[Symbol.for("openclaw:lastSocket")] = recreated.lastSocket; baileys.makeWASocket.mockImplementation(recreated.mod.makeWASocket); baileys.useMultiFileAuthState.mockImplementation(recreated.mod.useMultiFileAuthState); @@ -83,7 +83,7 @@ export function resetBaileysMocks() { } export function getLastSocket(): MockBaileysSocket { - const getter = (globalThis as Record)[Symbol.for("moltbot:lastSocket")]; + const getter = (globalThis as Record)[Symbol.for("openclaw:lastSocket")]; if (typeof getter === "function") return (getter as () => MockBaileysSocket)(); if (!getter) throw new Error("Baileys mock not initialized"); throw new Error("Invalid Baileys socket getter"); diff --git a/src/wizard/onboarding.finalize.ts b/src/wizard/onboarding.finalize.ts index 96a4a4bf6f..c5b01d6bf3 100644 --- a/src/wizard/onboarding.finalize.ts +++ b/src/wizard/onboarding.finalize.ts @@ -20,7 +20,7 @@ import { } from "../commands/onboard-helpers.js"; import { formatCliCommand } from "../cli/command-format.js"; import type { OnboardOptions } from "../commands/onboard-types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveGatewayService } from "../daemon/service.js"; import { isSystemdUserServiceAvailable } from "../daemon/systemd.js"; import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js"; @@ -37,8 +37,8 @@ import type { WizardPrompter } from "./prompts.js"; type FinalizeOnboardingOptions = { flow: WizardFlow; opts: OnboardOptions; - baseConfig: MoltbotConfig; - nextConfig: MoltbotConfig; + baseConfig: OpenClawConfig; + nextConfig: OpenClawConfig; workspaceDir: string; settings: GatewayWizardSettings; prompter: WizardPrompter; @@ -214,8 +214,8 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption await prompter.note( [ "Docs:", - "https://docs.molt.bot/gateway/health", - "https://docs.molt.bot/gateway/troubleshooting", + "https://docs.openclaw.ai/gateway/health", + "https://docs.openclaw.ai/gateway/troubleshooting", ].join("\n"), "Health check help", ); @@ -277,7 +277,7 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption tokenParam ? `Web UI (with token): ${authedUrl}` : undefined, `Gateway WS: ${links.wsUrl}`, gatewayStatusLine, - "Docs: https://docs.molt.bot/web/control-ui", + "Docs: https://docs.openclaw.ai/web/control-ui", ] .filter(Boolean) .join("\n"), @@ -305,9 +305,9 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption await prompter.note( [ "Gateway token: shared auth for the Gateway + Control UI.", - "Stored in: ~/.clawdbot/moltbot.json (gateway.auth.token) or CLAWDBOT_GATEWAY_TOKEN.", - "Web UI stores a copy in this browser's localStorage (moltbot.control.settings.v1).", - `Get the tokenized link anytime: ${formatCliCommand("moltbot dashboard --no-open")}`, + "Stored in: ~/.openclaw/openclaw.json (gateway.auth.token) or OPENCLAW_GATEWAY_TOKEN.", + "Web UI stores a copy in this browser's localStorage (openclaw.control.settings.v1).", + `Get the tokenized link anytime: ${formatCliCommand("openclaw dashboard --no-open")}`, ].join("\n"), "Token", ); @@ -337,7 +337,7 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption if (seededInBackground) { await prompter.note( `Web UI seeded in the background. Open later with: ${formatCliCommand( - "moltbot dashboard --no-open", + "openclaw dashboard --no-open", )}`, "Web UI", ); @@ -364,8 +364,8 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption [ `Dashboard link (with token): ${authedUrl}`, controlUiOpened - ? "Opened in your browser. Keep that tab to control Moltbot." - : "Copy/paste this URL in a browser on this machine to control Moltbot.", + ? "Opened in your browser. Keep that tab to control OpenClaw." + : "Copy/paste this URL in a browser on this machine to control OpenClaw.", controlUiOpenHint, ] .filter(Boolean) @@ -374,7 +374,7 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption ); } else { await prompter.note( - `When you're ready: ${formatCliCommand("moltbot dashboard --no-open")}`, + `When you're ready: ${formatCliCommand("openclaw dashboard --no-open")}`, "Later", ); } @@ -383,14 +383,15 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption } await prompter.note( - ["Back up your agent workspace.", "Docs: https://docs.molt.bot/concepts/agent-workspace"].join( - "\n", - ), + [ + "Back up your agent workspace.", + "Docs: https://docs.openclaw.ai/concepts/agent-workspace", + ].join("\n"), "Workspace backup", ); await prompter.note( - "Running agents on your computer is risky — harden your setup: https://docs.molt.bot/security", + "Running agents on your computer is risky — harden your setup: https://docs.openclaw.ai/security", "Security", ); @@ -422,8 +423,8 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption [ `Dashboard link (with token): ${authedUrl}`, controlUiOpened - ? "Opened in your browser. Keep that tab to control Moltbot." - : "Copy/paste this URL in a browser on this machine to control Moltbot.", + ? "Opened in your browser. Keep that tab to control OpenClaw." + : "Copy/paste this URL in a browser on this machine to control OpenClaw.", controlUiOpenHint, ] .filter(Boolean) @@ -443,33 +444,33 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption webSearchKey ? "API key: stored in config (tools.web.search.apiKey)." : "API key: provided via BRAVE_API_KEY env var (Gateway environment).", - "Docs: https://docs.molt.bot/tools/web", + "Docs: https://docs.openclaw.ai/tools/web", ].join("\n") : [ "If you want your agent to be able to search the web, you’ll need an API key.", "", - "Moltbot uses Brave Search for the `web_search` tool. Without a Brave Search API key, web search won’t work.", + "OpenClaw uses Brave Search for the `web_search` tool. Without a Brave Search API key, web search won’t work.", "", "Set it up interactively:", - `- Run: ${formatCliCommand("moltbot configure --section web")}`, + `- Run: ${formatCliCommand("openclaw configure --section web")}`, "- Enable web_search and paste your Brave Search API key", "", "Alternative: set BRAVE_API_KEY in the Gateway environment (no config changes).", - "Docs: https://docs.molt.bot/tools/web", + "Docs: https://docs.openclaw.ai/tools/web", ].join("\n"), "Web search (optional)", ); await prompter.note( - 'What now: https://molt.bot/showcase ("What People Are Building").', + 'What now: https://openclaw.ai/showcase ("What People Are Building").', "What now", ); await prompter.outro( controlUiOpened - ? "Onboarding complete. Dashboard opened with your token; keep that tab to control Moltbot." + ? "Onboarding complete. Dashboard opened with your token; keep that tab to control OpenClaw." : seededInBackground ? "Onboarding complete. Web UI seeded in the background; open it anytime with the tokenized link above." - : "Onboarding complete. Use the tokenized dashboard link above to control Moltbot.", + : "Onboarding complete. Use the tokenized dashboard link above to control OpenClaw.", ); } diff --git a/src/wizard/onboarding.gateway-config.ts b/src/wizard/onboarding.gateway-config.ts index 1a097f42ec..d7dceae243 100644 --- a/src/wizard/onboarding.gateway-config.ts +++ b/src/wizard/onboarding.gateway-config.ts @@ -1,6 +1,6 @@ import { randomToken } from "../commands/onboard-helpers.js"; import type { GatewayAuthChoice } from "../commands/onboard-types.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { findTailscaleBinary } from "../infra/tailscale.js"; import type { RuntimeEnv } from "../runtime.js"; import type { @@ -12,8 +12,8 @@ import type { WizardPrompter } from "./prompts.js"; type ConfigureGatewayOptions = { flow: WizardFlow; - baseConfig: MoltbotConfig; - nextConfig: MoltbotConfig; + baseConfig: OpenClawConfig; + nextConfig: OpenClawConfig; localPort: number; quickstartGateway: QuickstartGatewayDefaults; prompter: WizardPrompter; @@ -21,7 +21,7 @@ type ConfigureGatewayOptions = { }; type ConfigureGatewayResult = { - nextConfig: MoltbotConfig; + nextConfig: OpenClawConfig; settings: GatewayWizardSettings; }; @@ -145,7 +145,9 @@ export async function configureGatewayForOnboarding( let tailscaleResetOnExit = flow === "quickstart" ? quickstartGateway.tailscaleResetOnExit : false; if (tailscaleMode !== "off" && flow !== "quickstart") { await prompter.note( - ["Docs:", "https://docs.molt.bot/gateway/tailscale", "https://docs.molt.bot/web"].join("\n"), + ["Docs:", "https://docs.openclaw.ai/gateway/tailscale", "https://docs.openclaw.ai/web"].join( + "\n", + ), "Tailscale", ); tailscaleResetOnExit = Boolean( diff --git a/src/wizard/onboarding.test.ts b/src/wizard/onboarding.test.ts index df832391ec..3756335b63 100644 --- a/src/wizard/onboarding.test.ts +++ b/src/wizard/onboarding.test.ts @@ -77,7 +77,7 @@ vi.mock("../tui/tui.js", () => ({ describe("runOnboardingWizard", () => { it("exits when config is invalid", async () => { readConfigFileSnapshot.mockResolvedValueOnce({ - path: "/tmp/.clawdbot/moltbot.json", + path: "/tmp/.openclaw/openclaw.json", exists: true, raw: "{}", parsed: {}, @@ -174,7 +174,7 @@ describe("runOnboardingWizard", () => { it("launches TUI without auto-delivery when hatching", async () => { runTui.mockClear(); - const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-onboard-")); + const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-onboard-")); await fs.writeFile(path.join(workspaceDir, DEFAULT_BOOTSTRAP_FILENAME), "{}"); const select: WizardPrompter["select"] = vi.fn(async (opts) => { @@ -230,7 +230,7 @@ describe("runOnboardingWizard", () => { it("offers TUI hatch even without BOOTSTRAP.md", async () => { runTui.mockClear(); - const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-onboard-")); + const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-onboard-")); const select: WizardPrompter["select"] = vi.fn(async (opts) => { if (opts.message === "How do you want to hatch your bot?") return "tui"; diff --git a/src/wizard/onboarding.ts b/src/wizard/onboarding.ts index 75543ca192..ef2e349c67 100644 --- a/src/wizard/onboarding.ts +++ b/src/wizard/onboarding.ts @@ -27,7 +27,7 @@ import type { ResetScope, } from "../commands/onboard-types.js"; import { formatCliCommand } from "../cli/command-format.js"; -import type { MoltbotConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { DEFAULT_GATEWAY_PORT, readConfigFileSnapshot, @@ -53,11 +53,11 @@ async function requireRiskAcknowledgement(params: { [ "Security warning — please read.", "", - "Moltbot is a hobby project and still in beta. Expect sharp edges.", + "OpenClaw is a hobby project and still in beta. Expect sharp edges.", "This bot can read files and run actions if tools are enabled.", "A bad prompt can trick it into doing unsafe things.", "", - "If you’re not comfortable with basic security and access control, don’t run Moltbot.", + "If you’re not comfortable with basic security and access control, don’t run OpenClaw.", "Ask someone experienced to help before enabling tools or exposing it to the internet.", "", "Recommended baseline:", @@ -67,10 +67,10 @@ async function requireRiskAcknowledgement(params: { "- Use the strongest available model for any bot with tools or untrusted inboxes.", "", "Run regularly:", - "moltbot security audit --deep", - "moltbot security audit --fix", + "openclaw security audit --deep", + "openclaw security audit --fix", "", - "Must read: https://docs.molt.bot/gateway/security", + "Must read: https://docs.openclaw.ai/gateway/security", ].join("\n"), "Security", ); @@ -90,11 +90,11 @@ export async function runOnboardingWizard( prompter: WizardPrompter, ) { printWizardHeader(runtime); - await prompter.intro("Moltbot onboarding"); + await prompter.intro("OpenClaw onboarding"); await requireRiskAcknowledgement({ opts, prompter }); const snapshot = await readConfigFileSnapshot(); - let baseConfig: MoltbotConfig = snapshot.valid ? snapshot.config : {}; + let baseConfig: OpenClawConfig = snapshot.valid ? snapshot.config : {}; if (snapshot.exists && !snapshot.valid) { await prompter.note(summarizeExistingConfig(baseConfig), "Invalid config"); @@ -103,19 +103,19 @@ export async function runOnboardingWizard( [ ...snapshot.issues.map((iss) => `- ${iss.path}: ${iss.message}`), "", - "Docs: https://docs.molt.bot/gateway/configuration", + "Docs: https://docs.openclaw.ai/gateway/configuration", ].join("\n"), "Config issues", ); } await prompter.outro( - `Config invalid. Run \`${formatCliCommand("moltbot doctor")}\` to repair it, then re-run onboarding.`, + `Config invalid. Run \`${formatCliCommand("openclaw doctor")}\` to repair it, then re-run onboarding.`, ); runtime.exit(1); return; } - const quickstartHint = `Configure details later via ${formatCliCommand("moltbot configure")}.`; + const quickstartHint = `Configure details later via ${formatCliCommand("openclaw configure")}.`; const manualHint = "Configure port, network, Tailscale, and auth options."; const explicitFlowRaw = opts.flow?.trim(); const normalizedExplicitFlow = explicitFlowRaw === "manual" ? "advanced" : explicitFlowRaw; @@ -278,8 +278,8 @@ export async function runOnboardingWizard( const localUrl = `ws://127.0.0.1:${localPort}`; const localProbe = await probeGatewayReachable({ url: localUrl, - token: baseConfig.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN, - password: baseConfig.gateway?.auth?.password ?? process.env.CLAWDBOT_GATEWAY_PASSWORD, + token: baseConfig.gateway?.auth?.token ?? process.env.OPENCLAW_GATEWAY_TOKEN, + password: baseConfig.gateway?.auth?.password ?? process.env.OPENCLAW_GATEWAY_PASSWORD, }); const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? ""; const remoteProbe = remoteUrl @@ -335,7 +335,7 @@ export async function runOnboardingWizard( const workspaceDir = resolveUserPath(workspaceInput.trim() || DEFAULT_WORKSPACE); - let nextConfig: MoltbotConfig = { + let nextConfig: OpenClawConfig = { ...baseConfig, agents: { ...baseConfig.agents, diff --git a/test/gateway.multi.e2e.test.ts b/test/gateway.multi.e2e.test.ts index 3885dfc02a..76da865a84 100644 --- a/test/gateway.multi.e2e.test.ts +++ b/test/gateway.multi.e2e.test.ts @@ -95,10 +95,10 @@ const spawnGatewayInstance = async (name: string): Promise => { const port = await getFreePort(); const hookToken = `token-${name}-${randomUUID()}`; const gatewayToken = `gateway-${name}-${randomUUID()}`; - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), `moltbot-e2e-${name}-`)); - const configDir = path.join(homeDir, ".clawdbot"); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), `openclaw-e2e-${name}-`)); + const configDir = path.join(homeDir, ".openclaw"); await fs.mkdir(configDir, { recursive: true }); - const configPath = path.join(configDir, "moltbot.json"); + const configPath = path.join(configDir, "openclaw.json"); const stateDir = path.join(configDir, "state"); const config = { gateway: { port, auth: { mode: "token", token: gatewayToken } }, @@ -127,13 +127,13 @@ const spawnGatewayInstance = async (name: string): Promise => { env: { ...process.env, HOME: homeDir, - CLAWDBOT_CONFIG_PATH: configPath, - CLAWDBOT_STATE_DIR: stateDir, - CLAWDBOT_GATEWAY_TOKEN: "", - CLAWDBOT_GATEWAY_PASSWORD: "", - CLAWDBOT_SKIP_CHANNELS: "1", - CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER: "1", - CLAWDBOT_SKIP_CANVAS_HOST: "1", + OPENCLAW_CONFIG_PATH: configPath, + OPENCLAW_STATE_DIR: stateDir, + OPENCLAW_GATEWAY_TOKEN: "", + OPENCLAW_GATEWAY_PASSWORD: "", + OPENCLAW_SKIP_CHANNELS: "1", + OPENCLAW_SKIP_BROWSER_CONTROL_SERVER: "1", + OPENCLAW_SKIP_CANVAS_HOST: "1", }, stdio: ["ignore", "pipe", "pipe"], }, @@ -335,8 +335,8 @@ const waitForNodeStatus = async (inst: GatewayInstance, nodeId: string, timeoutM const list = (await runCliJson( ["nodes", "status", "--json", "--url", `ws://127.0.0.1:${inst.port}`], { - CLAWDBOT_GATEWAY_TOKEN: inst.gatewayToken, - CLAWDBOT_GATEWAY_PASSWORD: "", + OPENCLAW_GATEWAY_TOKEN: inst.gatewayToken, + OPENCLAW_GATEWAY_PASSWORD: "", }, )) as NodeListPayload; const match = list.nodes?.find((n) => n.nodeId === nodeId); @@ -370,14 +370,14 @@ describe("gateway multi-instance e2e", () => { const [healthA, healthB] = (await Promise.all([ runCliJson(["health", "--json", "--timeout", "10000"], { - CLAWDBOT_GATEWAY_PORT: String(gwA.port), - CLAWDBOT_GATEWAY_TOKEN: gwA.gatewayToken, - CLAWDBOT_GATEWAY_PASSWORD: "", + OPENCLAW_GATEWAY_PORT: String(gwA.port), + OPENCLAW_GATEWAY_TOKEN: gwA.gatewayToken, + OPENCLAW_GATEWAY_PASSWORD: "", }), runCliJson(["health", "--json", "--timeout", "10000"], { - CLAWDBOT_GATEWAY_PORT: String(gwB.port), - CLAWDBOT_GATEWAY_TOKEN: gwB.gatewayToken, - CLAWDBOT_GATEWAY_PASSWORD: "", + OPENCLAW_GATEWAY_PORT: String(gwB.port), + OPENCLAW_GATEWAY_TOKEN: gwB.gatewayToken, + OPENCLAW_GATEWAY_PASSWORD: "", }), ])) as [HealthPayload, HealthPayload]; expect(healthA.ok).toBe(true); diff --git a/test/helpers/temp-home.ts b/test/helpers/temp-home.ts index b33716d631..6c1962fb15 100644 --- a/test/helpers/temp-home.ts +++ b/test/helpers/temp-home.ts @@ -18,7 +18,7 @@ function snapshotEnv(): EnvSnapshot { userProfile: process.env.USERPROFILE, homeDrive: process.env.HOMEDRIVE, homePath: process.env.HOMEPATH, - stateDir: process.env.CLAWDBOT_STATE_DIR, + stateDir: process.env.OPENCLAW_STATE_DIR, }; } @@ -31,7 +31,7 @@ function restoreEnv(snapshot: EnvSnapshot) { restoreKey("USERPROFILE", snapshot.userProfile); restoreKey("HOMEDRIVE", snapshot.homeDrive); restoreKey("HOMEPATH", snapshot.homePath); - restoreKey("CLAWDBOT_STATE_DIR", snapshot.stateDir); + restoreKey("OPENCLAW_STATE_DIR", snapshot.stateDir); } function snapshotExtraEnv(keys: string[]): Record { @@ -50,7 +50,7 @@ function restoreExtraEnv(snapshot: Record) { function setTempHome(base: string) { process.env.HOME = base; process.env.USERPROFILE = base; - process.env.CLAWDBOT_STATE_DIR = path.join(base, ".clawdbot"); + process.env.OPENCLAW_STATE_DIR = path.join(base, ".openclaw"); if (process.platform !== "win32") return; const match = base.match(/^([A-Za-z]:)(.*)$/); @@ -63,7 +63,7 @@ export async function withTempHome( fn: (home: string) => Promise, opts: { env?: Record; prefix?: string } = {}, ): Promise { - const base = await fs.mkdtemp(path.join(os.tmpdir(), opts.prefix ?? "moltbot-test-home-")); + const base = await fs.mkdtemp(path.join(os.tmpdir(), opts.prefix ?? "openclaw-test-home-")); const snapshot = snapshotEnv(); const envKeys = Object.keys(opts.env ?? {}); for (const key of envKeys) { @@ -74,7 +74,7 @@ export async function withTempHome( const envSnapshot = snapshotExtraEnv(envKeys); setTempHome(base); - await fs.mkdir(path.join(base, ".clawdbot", "agents", "main", "sessions"), { recursive: true }); + await fs.mkdir(path.join(base, ".openclaw", "agents", "main", "sessions"), { recursive: true }); if (opts.env) { for (const [key, raw] of Object.entries(opts.env)) { const value = typeof raw === "function" ? raw(base) : raw; diff --git a/test/media-understanding.auto.e2e.test.ts b/test/media-understanding.auto.e2e.test.ts index dafc6d42fd..8f4761f4db 100644 --- a/test/media-understanding.auto.e2e.test.ts +++ b/test/media-understanding.auto.e2e.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { MoltbotConfig } from "../src/config/config.js"; +import type { OpenClawConfig } from "../src/config/config.js"; import type { MsgContext } from "../src/auto-reply/templating.js"; const makeTempDir = async (prefix: string) => await fs.mkdtemp(path.join(os.tmpdir(), prefix)); @@ -16,7 +16,7 @@ const writeExecutable = async (dir: string, name: string, content: string) => { }; const makeTempMedia = async (ext: string) => { - const dir = await makeTempDir("moltbot-media-e2e-"); + const dir = await makeTempDir("openclaw-media-e2e-"); const filePath = path.join(dir, `sample${ext}`); await fs.writeFile(filePath, "audio"); return { dir, filePath }; @@ -52,8 +52,8 @@ describe("media understanding auto-detect (e2e)", () => { it("uses sherpa-onnx-offline when available", async () => { const snapshot = envSnapshot(); try { - const binDir = await makeTempDir("moltbot-bin-sherpa-"); - const modelDir = await makeTempDir("moltbot-sherpa-model-"); + const binDir = await makeTempDir("openclaw-bin-sherpa-"); + const modelDir = await makeTempDir("openclaw-sherpa-model-"); tempPaths.push(binDir, modelDir); await fs.writeFile(path.join(modelDir, "tokens.txt"), "a"); @@ -79,7 +79,7 @@ describe("media understanding auto-detect (e2e)", () => { MediaPath: filePath, MediaType: "audio/wav", }; - const cfg: MoltbotConfig = { tools: { media: { audio: {} } } }; + const cfg: OpenClawConfig = { tools: { media: { audio: {} } } }; await applyMediaUnderstanding({ ctx, cfg }); @@ -92,8 +92,8 @@ describe("media understanding auto-detect (e2e)", () => { it("uses whisper-cli when sherpa is missing", async () => { const snapshot = envSnapshot(); try { - const binDir = await makeTempDir("moltbot-bin-whispercpp-"); - const modelDir = await makeTempDir("moltbot-whispercpp-model-"); + const binDir = await makeTempDir("openclaw-bin-whispercpp-"); + const modelDir = await makeTempDir("openclaw-whispercpp-model-"); tempPaths.push(binDir, modelDir); const modelPath = path.join(modelDir, "tiny.bin"); @@ -124,7 +124,7 @@ describe("media understanding auto-detect (e2e)", () => { MediaPath: filePath, MediaType: "audio/wav", }; - const cfg: MoltbotConfig = { tools: { media: { audio: {} } } }; + const cfg: OpenClawConfig = { tools: { media: { audio: {} } } }; await applyMediaUnderstanding({ ctx, cfg }); @@ -137,7 +137,7 @@ describe("media understanding auto-detect (e2e)", () => { it("uses gemini CLI for images when available", async () => { const snapshot = envSnapshot(); try { - const binDir = await makeTempDir("moltbot-bin-gemini-"); + const binDir = await makeTempDir("openclaw-bin-gemini-"); tempPaths.push(binDir); await writeExecutable( @@ -157,7 +157,7 @@ describe("media understanding auto-detect (e2e)", () => { MediaPath: filePath, MediaType: "image/png", }; - const cfg: MoltbotConfig = { tools: { media: { image: {} } } }; + const cfg: OpenClawConfig = { tools: { media: { image: {} } } }; await applyMediaUnderstanding({ ctx, cfg }); diff --git a/test/provider-timeout.e2e.test.ts b/test/provider-timeout.e2e.test.ts index 458c2136a8..66adb880b9 100644 --- a/test/provider-timeout.e2e.test.ts +++ b/test/provider-timeout.e2e.test.ts @@ -118,12 +118,12 @@ describe("provider timeouts (e2e)", () => { async () => { const prev = { home: process.env.HOME, - configPath: process.env.CLAWDBOT_CONFIG_PATH, - token: process.env.CLAWDBOT_GATEWAY_TOKEN, - skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS, - skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER, - skipCron: process.env.CLAWDBOT_SKIP_CRON, - skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST, + configPath: process.env.OPENCLAW_CONFIG_PATH, + token: process.env.OPENCLAW_GATEWAY_TOKEN, + skipChannels: process.env.OPENCLAW_SKIP_CHANNELS, + skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER, + skipCron: process.env.OPENCLAW_SKIP_CRON, + skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST, }; const originalFetch = globalThis.fetch; @@ -151,19 +151,19 @@ describe("provider timeouts (e2e)", () => { }; (globalThis as unknown as { fetch: unknown }).fetch = fetchImpl; - const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-timeout-e2e-")); + const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-timeout-e2e-")); process.env.HOME = tempHome; - process.env.CLAWDBOT_SKIP_CHANNELS = "1"; - process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1"; - process.env.CLAWDBOT_SKIP_CRON = "1"; - process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1"; + process.env.OPENCLAW_SKIP_CHANNELS = "1"; + process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1"; + process.env.OPENCLAW_SKIP_CRON = "1"; + process.env.OPENCLAW_SKIP_CANVAS_HOST = "1"; const token = `test-${randomUUID()}`; - process.env.CLAWDBOT_GATEWAY_TOKEN = token; + process.env.OPENCLAW_GATEWAY_TOKEN = token; - const configDir = path.join(tempHome, ".clawdbot"); + const configDir = path.join(tempHome, ".openclaw"); await fs.mkdir(configDir, { recursive: true }); - const configPath = path.join(configDir, "moltbot.json"); + const configPath = path.join(configDir, "openclaw.json"); const cfg = { agents: { @@ -217,7 +217,7 @@ describe("provider timeouts (e2e)", () => { }; await fs.writeFile(configPath, `${JSON.stringify(cfg, null, 2)}\n`); - process.env.CLAWDBOT_CONFIG_PATH = configPath; + process.env.OPENCLAW_CONFIG_PATH = configPath; const port = await getFreeGatewayPort(); const server = await startGatewayServer(port, { @@ -265,18 +265,18 @@ describe("provider timeouts (e2e)", () => { (globalThis as unknown as { fetch: unknown }).fetch = originalFetch; if (prev.home === undefined) delete process.env.HOME; else process.env.HOME = prev.home; - if (prev.configPath === undefined) delete process.env.CLAWDBOT_CONFIG_PATH; - else process.env.CLAWDBOT_CONFIG_PATH = prev.configPath; - if (prev.token === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN; - else process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token; - if (prev.skipChannels === undefined) delete process.env.CLAWDBOT_SKIP_CHANNELS; - else process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels; - if (prev.skipGmail === undefined) delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; - else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail; - if (prev.skipCron === undefined) delete process.env.CLAWDBOT_SKIP_CRON; - else process.env.CLAWDBOT_SKIP_CRON = prev.skipCron; - if (prev.skipCanvas === undefined) delete process.env.CLAWDBOT_SKIP_CANVAS_HOST; - else process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas; + if (prev.configPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH; + else process.env.OPENCLAW_CONFIG_PATH = prev.configPath; + if (prev.token === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN; + else process.env.OPENCLAW_GATEWAY_TOKEN = prev.token; + if (prev.skipChannels === undefined) delete process.env.OPENCLAW_SKIP_CHANNELS; + else process.env.OPENCLAW_SKIP_CHANNELS = prev.skipChannels; + if (prev.skipGmail === undefined) delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER; + else process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prev.skipGmail; + if (prev.skipCron === undefined) delete process.env.OPENCLAW_SKIP_CRON; + else process.env.OPENCLAW_SKIP_CRON = prev.skipCron; + if (prev.skipCanvas === undefined) delete process.env.OPENCLAW_SKIP_CANVAS_HOST; + else process.env.OPENCLAW_SKIP_CANVAS_HOST = prev.skipCanvas; } }, ); diff --git a/test/setup.ts b/test/setup.ts index 3d2e3ecffd..80671a6484 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -8,7 +8,7 @@ import type { ChannelOutboundAdapter, ChannelPlugin, } from "../src/channels/plugins/types.js"; -import type { MoltbotConfig } from "../src/config/config.js"; +import type { OpenClawConfig } from "../src/config/config.js"; import type { OutboundSendDeps } from "../src/infra/outbound/deliver.js"; import { installProcessWarningFilter } from "../src/infra/warnings.js"; import { setActivePluginRegistry } from "../src/plugins/runtime.js"; @@ -80,7 +80,7 @@ const createStubPlugin = (params: { }, capabilities: { chatTypes: ["direct", "group"] }, config: { - listAccountIds: (cfg: MoltbotConfig) => { + listAccountIds: (cfg: OpenClawConfig) => { const channels = cfg.channels as Record | undefined; const entry = channels?.[params.id]; if (!entry || typeof entry !== "object") return []; @@ -88,7 +88,7 @@ const createStubPlugin = (params: { const ids = accounts ? Object.keys(accounts).filter(Boolean) : []; return ids.length > 0 ? ids : ["default"]; }, - resolveAccount: (cfg: MoltbotConfig, accountId: string) => { + resolveAccount: (cfg: OpenClawConfig, accountId: string) => { const channels = cfg.channels as Record | undefined; const entry = channels?.[params.id]; if (!entry || typeof entry !== "object") return {}; @@ -96,7 +96,7 @@ const createStubPlugin = (params: { const match = accounts?.[accountId]; return (match && typeof match === "object") || typeof match === "string" ? match : entry; }, - isConfigured: async (_account, cfg: MoltbotConfig) => { + isConfigured: async (_account, cfg: OpenClawConfig) => { const channels = cfg.channels as Record | undefined; return Boolean(channels?.[params.id]); }, diff --git a/test/test-env.ts b/test/test-env.ts index 308170f35e..d75ed97261 100644 --- a/test/test-env.ts +++ b/test/test-env.ts @@ -43,8 +43,8 @@ function loadProfileEnv(): void { export function installTestEnv(): { cleanup: () => void; tempHome: string } { const live = process.env.LIVE === "1" || - process.env.CLAWDBOT_LIVE_TEST === "1" || - process.env.CLAWDBOT_LIVE_GATEWAY === "1"; + process.env.OPENCLAW_LIVE_TEST === "1" || + process.env.OPENCLAW_LIVE_GATEWAY === "1"; // Live tests must use the real user environment (keys, profiles, config). // The default test env isolates HOME to avoid touching real state. @@ -54,21 +54,21 @@ export function installTestEnv(): { cleanup: () => void; tempHome: string } { } const restore: RestoreEntry[] = [ - { key: "CLAWDBOT_TEST_FAST", value: process.env.CLAWDBOT_TEST_FAST }, + { key: "OPENCLAW_TEST_FAST", value: process.env.OPENCLAW_TEST_FAST }, { key: "HOME", value: process.env.HOME }, { key: "USERPROFILE", value: process.env.USERPROFILE }, { key: "XDG_CONFIG_HOME", value: process.env.XDG_CONFIG_HOME }, { key: "XDG_DATA_HOME", value: process.env.XDG_DATA_HOME }, { key: "XDG_STATE_HOME", value: process.env.XDG_STATE_HOME }, { key: "XDG_CACHE_HOME", value: process.env.XDG_CACHE_HOME }, - { key: "CLAWDBOT_STATE_DIR", value: process.env.CLAWDBOT_STATE_DIR }, - { key: "CLAWDBOT_CONFIG_PATH", value: process.env.CLAWDBOT_CONFIG_PATH }, - { key: "CLAWDBOT_GATEWAY_PORT", value: process.env.CLAWDBOT_GATEWAY_PORT }, - { key: "CLAWDBOT_BRIDGE_ENABLED", value: process.env.CLAWDBOT_BRIDGE_ENABLED }, - { key: "CLAWDBOT_BRIDGE_HOST", value: process.env.CLAWDBOT_BRIDGE_HOST }, - { key: "CLAWDBOT_BRIDGE_PORT", value: process.env.CLAWDBOT_BRIDGE_PORT }, - { key: "CLAWDBOT_CANVAS_HOST_PORT", value: process.env.CLAWDBOT_CANVAS_HOST_PORT }, - { key: "CLAWDBOT_TEST_HOME", value: process.env.CLAWDBOT_TEST_HOME }, + { key: "OPENCLAW_STATE_DIR", value: process.env.OPENCLAW_STATE_DIR }, + { key: "OPENCLAW_CONFIG_PATH", value: process.env.OPENCLAW_CONFIG_PATH }, + { key: "OPENCLAW_GATEWAY_PORT", value: process.env.OPENCLAW_GATEWAY_PORT }, + { key: "OPENCLAW_BRIDGE_ENABLED", value: process.env.OPENCLAW_BRIDGE_ENABLED }, + { key: "OPENCLAW_BRIDGE_HOST", value: process.env.OPENCLAW_BRIDGE_HOST }, + { key: "OPENCLAW_BRIDGE_PORT", value: process.env.OPENCLAW_BRIDGE_PORT }, + { key: "OPENCLAW_CANVAS_HOST_PORT", value: process.env.OPENCLAW_CANVAS_HOST_PORT }, + { key: "OPENCLAW_TEST_HOME", value: process.env.OPENCLAW_TEST_HOME }, { key: "TELEGRAM_BOT_TOKEN", value: process.env.TELEGRAM_BOT_TOKEN }, { key: "DISCORD_BOT_TOKEN", value: process.env.DISCORD_BOT_TOKEN }, { key: "SLACK_BOT_TOKEN", value: process.env.SLACK_BOT_TOKEN }, @@ -80,23 +80,23 @@ export function installTestEnv(): { cleanup: () => void; tempHome: string } { { key: "NODE_OPTIONS", value: process.env.NODE_OPTIONS }, ]; - const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-test-home-")); + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-test-home-")); process.env.HOME = tempHome; process.env.USERPROFILE = tempHome; - process.env.CLAWDBOT_TEST_HOME = tempHome; - process.env.CLAWDBOT_TEST_FAST = "1"; + process.env.OPENCLAW_TEST_HOME = tempHome; + process.env.OPENCLAW_TEST_FAST = "1"; // Ensure test runs never touch the developer's real config/state, even if they have overrides set. - delete process.env.CLAWDBOT_CONFIG_PATH; + delete process.env.OPENCLAW_CONFIG_PATH; // Prefer deriving state dir from HOME so nested tests that change HOME also isolate correctly. - delete process.env.CLAWDBOT_STATE_DIR; + delete process.env.OPENCLAW_STATE_DIR; // Prefer test-controlled ports over developer overrides (avoid port collisions across tests/workers). - delete process.env.CLAWDBOT_GATEWAY_PORT; - delete process.env.CLAWDBOT_BRIDGE_ENABLED; - delete process.env.CLAWDBOT_BRIDGE_HOST; - delete process.env.CLAWDBOT_BRIDGE_PORT; - delete process.env.CLAWDBOT_CANVAS_HOST_PORT; + delete process.env.OPENCLAW_GATEWAY_PORT; + delete process.env.OPENCLAW_BRIDGE_ENABLED; + delete process.env.OPENCLAW_BRIDGE_HOST; + delete process.env.OPENCLAW_BRIDGE_PORT; + delete process.env.OPENCLAW_CANVAS_HOST_PORT; // Avoid leaking real GitHub/Copilot tokens into non-live test runs. delete process.env.TELEGRAM_BOT_TOKEN; delete process.env.DISCORD_BOT_TOKEN; @@ -109,9 +109,9 @@ export function installTestEnv(): { cleanup: () => void; tempHome: string } { // Avoid leaking local dev tooling flags into tests (e.g. --inspect). delete process.env.NODE_OPTIONS; - // Windows: prefer the legacy default state dir so auth/profile tests match real paths. + // Windows: prefer the default state dir so auth/profile tests match real paths. if (process.platform === "win32") { - process.env.CLAWDBOT_STATE_DIR = path.join(tempHome, ".clawdbot"); + process.env.OPENCLAW_STATE_DIR = path.join(tempHome, ".openclaw"); } process.env.XDG_CONFIG_HOME = path.join(tempHome, ".config"); diff --git a/ui/index.html b/ui/index.html index 3100a19739..d42804f47b 100644 --- a/ui/index.html +++ b/ui/index.html @@ -3,12 +3,12 @@ - Moltbot Control + OpenClaw Control - + diff --git a/ui/package.json b/ui/package.json index 3376e10295..bf1340f937 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,5 +1,5 @@ { - "name": "moltbot-control-ui", + "name": "openclaw-control-ui", "private": true, "type": "module", "scripts": { diff --git a/ui/src/styles/base.css b/ui/src/styles/base.css index f77cff9ed4..54a2c62885 100644 --- a/ui/src/styles/base.css +++ b/ui/src/styles/base.css @@ -239,7 +239,7 @@ html.theme-transition::view-transition-new(theme) { } } -moltbot-app { +openclaw-app { display: block; position: relative; z-index: 1; diff --git a/ui/src/ui/app-channels.ts b/ui/src/ui/app-channels.ts index 91ff734ed9..ad5bd29290 100644 --- a/ui/src/ui/app-channels.ts +++ b/ui/src/ui/app-channels.ts @@ -5,32 +5,32 @@ import { waitWhatsAppLogin, } from "./controllers/channels"; import { loadConfig, saveConfig } from "./controllers/config"; -import type { MoltbotApp } from "./app"; +import type { OpenClawApp } from "./app"; import type { NostrProfile } from "./types"; import { createNostrProfileFormState } from "./views/channels.nostr-profile-form"; -export async function handleWhatsAppStart(host: MoltbotApp, force: boolean) { +export async function handleWhatsAppStart(host: OpenClawApp, force: boolean) { await startWhatsAppLogin(host, force); await loadChannels(host, true); } -export async function handleWhatsAppWait(host: MoltbotApp) { +export async function handleWhatsAppWait(host: OpenClawApp) { await waitWhatsAppLogin(host); await loadChannels(host, true); } -export async function handleWhatsAppLogout(host: MoltbotApp) { +export async function handleWhatsAppLogout(host: OpenClawApp) { await logoutWhatsApp(host); await loadChannels(host, true); } -export async function handleChannelConfigSave(host: MoltbotApp) { +export async function handleChannelConfigSave(host: OpenClawApp) { await saveConfig(host); await loadConfig(host); await loadChannels(host, true); } -export async function handleChannelConfigReload(host: MoltbotApp) { +export async function handleChannelConfigReload(host: OpenClawApp) { await loadConfig(host); await loadChannels(host, true); } @@ -49,7 +49,7 @@ function parseValidationErrors(details: unknown): Record { return errors; } -function resolveNostrAccountId(host: MoltbotApp): string { +function resolveNostrAccountId(host: OpenClawApp): string { const accounts = host.channelsSnapshot?.channelAccounts?.nostr ?? []; return accounts[0]?.accountId ?? host.nostrProfileAccountId ?? "default"; } @@ -59,7 +59,7 @@ function buildNostrProfileUrl(accountId: string, suffix = ""): string { } export function handleNostrProfileEdit( - host: MoltbotApp, + host: OpenClawApp, accountId: string, profile: NostrProfile | null, ) { @@ -67,13 +67,13 @@ export function handleNostrProfileEdit( host.nostrProfileFormState = createNostrProfileFormState(profile ?? undefined); } -export function handleNostrProfileCancel(host: MoltbotApp) { +export function handleNostrProfileCancel(host: OpenClawApp) { host.nostrProfileFormState = null; host.nostrProfileAccountId = null; } export function handleNostrProfileFieldChange( - host: MoltbotApp, + host: OpenClawApp, field: keyof NostrProfile, value: string, ) { @@ -92,7 +92,7 @@ export function handleNostrProfileFieldChange( }; } -export function handleNostrProfileToggleAdvanced(host: MoltbotApp) { +export function handleNostrProfileToggleAdvanced(host: OpenClawApp) { const state = host.nostrProfileFormState; if (!state) return; host.nostrProfileFormState = { @@ -101,7 +101,7 @@ export function handleNostrProfileToggleAdvanced(host: MoltbotApp) { }; } -export async function handleNostrProfileSave(host: MoltbotApp) { +export async function handleNostrProfileSave(host: OpenClawApp) { const state = host.nostrProfileFormState; if (!state || state.saving) return; const accountId = resolveNostrAccountId(host); @@ -167,7 +167,7 @@ export async function handleNostrProfileSave(host: MoltbotApp) { } } -export async function handleNostrProfileImport(host: MoltbotApp) { +export async function handleNostrProfileImport(host: OpenClawApp) { const state = host.nostrProfileFormState; if (!state || state.importing) return; const accountId = resolveNostrAccountId(host); diff --git a/ui/src/ui/app-chat.ts b/ui/src/ui/app-chat.ts index 0b35fb445b..d7a5165c5b 100644 --- a/ui/src/ui/app-chat.ts +++ b/ui/src/ui/app-chat.ts @@ -7,7 +7,7 @@ import { setLastActiveSessionKey } from "./app-settings"; import { normalizeBasePath } from "./navigation"; import type { GatewayHelloOk } from "./gateway"; import { parseAgentSessionKey } from "../../../src/sessions/session-key-utils.js"; -import type { MoltbotApp } from "./app"; +import type { OpenClawApp } from "./app"; import type { ChatAttachment, ChatQueueItem } from "./ui-types"; type ChatHost = { @@ -53,7 +53,7 @@ function isChatResetCommand(text: string) { export async function handleAbortChat(host: ChatHost) { if (!host.connected) return; host.chatMessage = ""; - await abortChatRun(host as unknown as MoltbotApp); + await abortChatRun(host as unknown as OpenClawApp); } function enqueueChatMessage(host: ChatHost, text: string, attachments?: ChatAttachment[]) { @@ -84,7 +84,7 @@ async function sendChatMessageNow( }, ) { resetToolStream(host as unknown as Parameters[0]); - const ok = await sendChatMessage(host as unknown as MoltbotApp, message, opts?.attachments); + const ok = await sendChatMessage(host as unknown as OpenClawApp, message, opts?.attachments); if (!ok && opts?.previousDraft != null) { host.chatMessage = opts.previousDraft; } @@ -169,8 +169,8 @@ export async function handleSendChat( export async function refreshChat(host: ChatHost) { await Promise.all([ - loadChatHistory(host as unknown as MoltbotApp), - loadSessions(host as unknown as MoltbotApp, { activeMinutes: 0 }), + loadChatHistory(host as unknown as OpenClawApp), + loadSessions(host as unknown as OpenClawApp, { activeMinutes: 0 }), refreshChatAvatar(host), ]); scheduleChatScroll(host as unknown as Parameters[0], true); diff --git a/ui/src/ui/app-gateway.ts b/ui/src/ui/app-gateway.ts index ba1df61e10..d4c8339c90 100644 --- a/ui/src/ui/app-gateway.ts +++ b/ui/src/ui/app-gateway.ts @@ -23,7 +23,7 @@ import { parseExecApprovalResolved, removeExecApproval, } from "./controllers/exec-approval"; -import type { MoltbotApp } from "./app"; +import type { OpenClawApp } from "./app"; import type { ExecApprovalRequest } from "./controllers/exec-approval"; import { loadAssistantIdentity } from "./controllers/assistant-identity"; import { loadSessions } from "./controllers/sessions"; @@ -122,7 +122,7 @@ export function connectGateway(host: GatewayHost) { url: host.settings.gatewayUrl, token: host.settings.token.trim() ? host.settings.token : undefined, password: host.password.trim() ? host.password : undefined, - clientName: "moltbot-control-ui", + clientName: "openclaw-control-ui", mode: "webchat", onHello: (hello) => { host.connected = true; @@ -135,10 +135,10 @@ export function connectGateway(host: GatewayHost) { (host as unknown as { chatStream: string | null }).chatStream = null; (host as unknown as { chatStreamStartedAt: number | null }).chatStreamStartedAt = null; resetToolStream(host as unknown as Parameters[0]); - void loadAssistantIdentity(host as unknown as MoltbotApp); - void loadAgents(host as unknown as MoltbotApp); - void loadNodes(host as unknown as MoltbotApp, { quiet: true }); - void loadDevices(host as unknown as MoltbotApp, { quiet: true }); + void loadAssistantIdentity(host as unknown as OpenClawApp); + void loadAgents(host as unknown as OpenClawApp); + void loadNodes(host as unknown as OpenClawApp, { quiet: true }); + void loadDevices(host as unknown as OpenClawApp, { quiet: true }); void refreshActiveTab(host as unknown as Parameters[0]); }, onClose: ({ code, reason }) => { @@ -190,7 +190,7 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) { payload.sessionKey, ); } - const state = handleChatEvent(host as unknown as MoltbotApp, payload); + const state = handleChatEvent(host as unknown as OpenClawApp, payload); if (state === "final" || state === "error" || state === "aborted") { resetToolStream(host as unknown as Parameters[0]); void flushChatQueueForEvent( @@ -199,11 +199,11 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) { if (host.refreshSessionsAfterChat) { host.refreshSessionsAfterChat = false; if (state === "final") { - void loadSessions(host as unknown as MoltbotApp, { activeMinutes: 0 }); + void loadSessions(host as unknown as OpenClawApp, { activeMinutes: 0 }); } } } - if (state === "final") void loadChatHistory(host as unknown as MoltbotApp); + if (state === "final") void loadChatHistory(host as unknown as OpenClawApp); return; } @@ -222,7 +222,7 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) { } if (evt.event === "device.pair.requested" || evt.event === "device.pair.resolved") { - void loadDevices(host as unknown as MoltbotApp, { quiet: true }); + void loadDevices(host as unknown as OpenClawApp, { quiet: true }); } if (evt.event === "exec.approval.requested") { diff --git a/ui/src/ui/app-polling.ts b/ui/src/ui/app-polling.ts index 3255bdaebd..f35beef723 100644 --- a/ui/src/ui/app-polling.ts +++ b/ui/src/ui/app-polling.ts @@ -1,7 +1,7 @@ import { loadLogs } from "./controllers/logs"; import { loadNodes } from "./controllers/nodes"; import { loadDebug } from "./controllers/debug"; -import type { MoltbotApp } from "./app"; +import type { OpenClawApp } from "./app"; type PollingHost = { nodesPollInterval: number | null; @@ -13,7 +13,7 @@ type PollingHost = { export function startNodesPolling(host: PollingHost) { if (host.nodesPollInterval != null) return; host.nodesPollInterval = window.setInterval( - () => void loadNodes(host as unknown as MoltbotApp, { quiet: true }), + () => void loadNodes(host as unknown as OpenClawApp, { quiet: true }), 5000, ); } @@ -28,7 +28,7 @@ export function startLogsPolling(host: PollingHost) { if (host.logsPollInterval != null) return; host.logsPollInterval = window.setInterval(() => { if (host.tab !== "logs") return; - void loadLogs(host as unknown as MoltbotApp, { quiet: true }); + void loadLogs(host as unknown as OpenClawApp, { quiet: true }); }, 2000); } @@ -42,7 +42,7 @@ export function startDebugPolling(host: PollingHost) { if (host.debugPollInterval != null) return; host.debugPollInterval = window.setInterval(() => { if (host.tab !== "debug") return; - void loadDebug(host as unknown as MoltbotApp); + void loadDebug(host as unknown as OpenClawApp); }, 3000); } diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index 422af68633..d692693cb8 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -130,10 +130,10 @@ export function renderApp(state: AppViewState) {
    -
    MOLTBOT
    +
    OPENCLAW
    Gateway Dashboard
    @@ -181,7 +181,7 @@ export function renderApp(state: AppViewState) {