refactor: rename clawdbot to moltbot with legacy compat

This commit is contained in:
Peter Steinberger
2026-01-27 12:19:58 +00:00
parent 83460df96f
commit 6d16a658e5
1839 changed files with 11250 additions and 11199 deletions

View File

@@ -1,6 +1,6 @@
import SwiftUI
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct AppCoverageTests {
@Test @MainActor func nodeAppModelUpdatesBackgroundedState() {

View File

@@ -1,5 +1,5 @@
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct CameraControllerClampTests {
@Test func clampQualityDefaultsAndBounds() {

View File

@@ -1,5 +1,5 @@
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct CameraControllerErrorTests {
@Test func errorDescriptionsAreStable() {

View File

@@ -1,15 +1,15 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import Testing
@Suite struct DeepLinkParserTests {
@Test func parseRejectsUnknownHost() {
let url = URL(string: "clawdbot://nope?message=hi")!
let url = URL(string: "moltbot://nope?message=hi")!
#expect(DeepLinkParser.parse(url) == nil)
}
@Test func parseHostIsCaseInsensitive() {
let url = URL(string: "clawdbot://AGENT?message=Hello")!
let url = URL(string: "moltbot://AGENT?message=Hello")!
#expect(DeepLinkParser.parse(url) == .agent(.init(
message: "Hello",
sessionKey: nil,
@@ -21,19 +21,19 @@ import Testing
key: nil)))
}
@Test func parseRejectsNonClawdbotScheme() {
@Test func parseRejectsNonMoltbotScheme() {
let url = URL(string: "https://example.com/agent?message=hi")!
#expect(DeepLinkParser.parse(url) == nil)
}
@Test func parseRejectsEmptyMessage() {
let url = URL(string: "clawdbot://agent?message=%20%20%0A")!
let url = URL(string: "moltbot://agent?message=%20%20%0A")!
#expect(DeepLinkParser.parse(url) == nil)
}
@Test func parseAgentLinkParsesCommonFields() {
let url =
URL(string: "clawdbot://agent?message=Hello&deliver=1&sessionKey=node-test&thinking=low&timeoutSeconds=30")!
URL(string: "moltbot://agent?message=Hello&deliver=1&sessionKey=node-test&thinking=low&timeoutSeconds=30")!
#expect(
DeepLinkParser.parse(url) == .agent(
.init(
@@ -50,7 +50,7 @@ import Testing
@Test func parseAgentLinkParsesTargetRoutingFields() {
let url =
URL(
string: "clawdbot://agent?message=Hello%20World&deliver=1&to=%2B15551234567&channel=whatsapp&key=secret")!
string: "moltbot://agent?message=Hello%20World&deliver=1&to=%2B15551234567&channel=whatsapp&key=secret")!
#expect(
DeepLinkParser.parse(url) == .agent(
.init(
@@ -65,7 +65,7 @@ import Testing
}
@Test func parseRejectsNegativeTimeoutSeconds() {
let url = URL(string: "clawdbot://agent?message=Hello&timeoutSeconds=-1")!
let url = URL(string: "moltbot://agent?message=Hello&timeoutSeconds=-1")!
#expect(DeepLinkParser.parse(url) == .agent(.init(
message: "Hello",
sessionKey: nil,

View File

@@ -1,8 +1,8 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import Testing
import UIKit
@testable import Clawdbot
@testable import Moltbot
private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws -> T) rethrows -> T {
let defaults = UserDefaults.standard
@@ -49,31 +49,31 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
"node.instanceId": "ios-test",
"node.displayName": "Test Node",
"camera.enabled": true,
"location.enabledMode": ClawdbotLocationMode.always.rawValue,
"location.enabledMode": MoltbotLocationMode.always.rawValue,
VoiceWakePreferences.enabledKey: true,
]) {
let appModel = NodeAppModel()
let controller = GatewayConnectionController(appModel: appModel, startDiscovery: false)
let caps = Set(controller._test_currentCaps())
#expect(caps.contains(ClawdbotCapability.canvas.rawValue))
#expect(caps.contains(ClawdbotCapability.screen.rawValue))
#expect(caps.contains(ClawdbotCapability.camera.rawValue))
#expect(caps.contains(ClawdbotCapability.location.rawValue))
#expect(caps.contains(ClawdbotCapability.voiceWake.rawValue))
#expect(caps.contains(MoltbotCapability.canvas.rawValue))
#expect(caps.contains(MoltbotCapability.screen.rawValue))
#expect(caps.contains(MoltbotCapability.camera.rawValue))
#expect(caps.contains(MoltbotCapability.location.rawValue))
#expect(caps.contains(MoltbotCapability.voiceWake.rawValue))
}
}
@Test @MainActor func currentCommandsIncludeLocationWhenEnabled() {
withUserDefaults([
"node.instanceId": "ios-test",
"location.enabledMode": ClawdbotLocationMode.whileUsing.rawValue,
"location.enabledMode": MoltbotLocationMode.whileUsing.rawValue,
]) {
let appModel = NodeAppModel()
let controller = GatewayConnectionController(appModel: appModel, startDiscovery: false)
let commands = Set(controller._test_currentCommands())
#expect(commands.contains(ClawdbotLocationCommand.get.rawValue))
#expect(commands.contains(MoltbotLocationCommand.get.rawValue))
}
}
}

View File

@@ -1,5 +1,5 @@
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite(.serialized) struct GatewayDiscoveryModelTests {
@Test @MainActor func debugLoggingCapturesLifecycleAndResets() {

View File

@@ -1,17 +1,17 @@
import ClawdbotKit
import MoltbotKit
import Network
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct GatewayEndpointIDTests {
@Test func stableIDForServiceDecodesAndNormalizesName() {
let endpoint = NWEndpoint.service(
name: "Clawdbot\\032Gateway \\032 Node\n",
type: "_clawdbot-gw._tcp",
name: "Moltbot\\032Gateway \\032 Node\n",
type: "_moltbot-gw._tcp",
domain: "local.",
interface: nil)
#expect(GatewayEndpointID.stableID(endpoint) == "_clawdbot-gw._tcp|local.|Clawdbot Gateway Node")
#expect(GatewayEndpointID.stableID(endpoint) == "_moltbot-gw._tcp|local.|Moltbot Gateway Node")
}
@Test func stableIDForNonServiceUsesEndpointDescription() {
@@ -21,8 +21,8 @@ import Testing
@Test func prettyDescriptionDecodesBonjourEscapes() {
let endpoint = NWEndpoint.service(
name: "Clawdbot\\032Gateway",
type: "_clawdbot-gw._tcp",
name: "Moltbot\\032Gateway",
type: "_moltbot-gw._tcp",
domain: "local.",
interface: nil)

View File

@@ -1,6 +1,6 @@
import Foundation
import Testing
@testable import Clawdbot
@testable import Moltbot
private struct KeychainEntry: Hashable {
let service: String

View File

@@ -1,6 +1,6 @@
import ClawdbotKit
import MoltbotKit
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct IOSGatewayChatTransportTests {
@Test func requestsFailFastWhenGatewayNotConnected() async {

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>ClawdbotTests</string>
<string>MoltbotTests</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@@ -1,6 +1,6 @@
import Foundation
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct KeychainStoreTests {
@Test func saveLoadUpdateDeleteRoundTrip() {

View File

@@ -1,8 +1,8 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import Testing
import UIKit
@testable import Clawdbot
@testable import Moltbot
private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws -> T) rethrows -> T {
let defaults = UserDefaults.standard
@@ -32,7 +32,7 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Suite(.serialized) struct NodeAppModelInvokeTests {
@Test @MainActor func decodeParamsFailsWithoutJSON() {
#expect(throws: Error.self) {
_ = try NodeAppModel._test_decodeParams(ClawdbotCanvasNavigateParams.self, from: nil)
_ = try NodeAppModel._test_decodeParams(MoltbotCanvasNavigateParams.self, from: nil)
}
}
@@ -48,7 +48,7 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
let appModel = NodeAppModel()
appModel.setScenePhase(.background)
let req = BridgeInvokeRequest(id: "bg", command: ClawdbotCanvasCommand.present.rawValue)
let req = BridgeInvokeRequest(id: "bg", command: MoltbotCanvasCommand.present.rawValue)
let res = await appModel._test_handleInvoke(req)
#expect(res.ok == false)
#expect(res.error?.code == .backgroundUnavailable)
@@ -56,7 +56,7 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Test @MainActor func handleInvokeRejectsCameraWhenDisabled() async {
let appModel = NodeAppModel()
let req = BridgeInvokeRequest(id: "cam", command: ClawdbotCameraCommand.snap.rawValue)
let req = BridgeInvokeRequest(id: "cam", command: MoltbotCameraCommand.snap.rawValue)
let defaults = UserDefaults.standard
let key = "camera.enabled"
@@ -78,13 +78,13 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Test @MainActor func handleInvokeRejectsInvalidScreenFormat() async {
let appModel = NodeAppModel()
let params = ClawdbotScreenRecordParams(format: "gif")
let params = MoltbotScreenRecordParams(format: "gif")
let data = try? JSONEncoder().encode(params)
let json = data.flatMap { String(data: $0, encoding: .utf8) }
let req = BridgeInvokeRequest(
id: "screen",
command: ClawdbotScreenCommand.record.rawValue,
command: MoltbotScreenCommand.record.rawValue,
paramsJSON: json)
let res = await appModel._test_handleInvoke(req)
@@ -96,28 +96,28 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
let appModel = NodeAppModel()
appModel.screen.navigate(to: "http://example.com")
let present = BridgeInvokeRequest(id: "present", command: ClawdbotCanvasCommand.present.rawValue)
let present = BridgeInvokeRequest(id: "present", command: MoltbotCanvasCommand.present.rawValue)
let presentRes = await appModel._test_handleInvoke(present)
#expect(presentRes.ok == true)
#expect(appModel.screen.urlString.isEmpty)
let navigateParams = ClawdbotCanvasNavigateParams(url: "http://localhost:18789/")
let navigateParams = MoltbotCanvasNavigateParams(url: "http://localhost:18789/")
let navData = try JSONEncoder().encode(navigateParams)
let navJSON = String(decoding: navData, as: UTF8.self)
let navigate = BridgeInvokeRequest(
id: "nav",
command: ClawdbotCanvasCommand.navigate.rawValue,
command: MoltbotCanvasCommand.navigate.rawValue,
paramsJSON: navJSON)
let navRes = await appModel._test_handleInvoke(navigate)
#expect(navRes.ok == true)
#expect(appModel.screen.urlString == "http://localhost:18789/")
let evalParams = ClawdbotCanvasEvalParams(javaScript: "1+1")
let evalParams = MoltbotCanvasEvalParams(javaScript: "1+1")
let evalData = try JSONEncoder().encode(evalParams)
let evalJSON = String(decoding: evalData, as: UTF8.self)
let eval = BridgeInvokeRequest(
id: "eval",
command: ClawdbotCanvasCommand.evalJS.rawValue,
command: MoltbotCanvasCommand.evalJS.rawValue,
paramsJSON: evalJSON)
let evalRes = await appModel._test_handleInvoke(eval)
#expect(evalRes.ok == true)
@@ -129,18 +129,18 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Test @MainActor func handleInvokeA2UICommandsFailWhenHostMissing() async throws {
let appModel = NodeAppModel()
let reset = BridgeInvokeRequest(id: "reset", command: ClawdbotCanvasA2UICommand.reset.rawValue)
let reset = BridgeInvokeRequest(id: "reset", command: MoltbotCanvasA2UICommand.reset.rawValue)
let resetRes = await appModel._test_handleInvoke(reset)
#expect(resetRes.ok == false)
#expect(resetRes.error?.message.contains("A2UI_HOST_NOT_CONFIGURED") == true)
let jsonl = "{\"beginRendering\":{}}"
let pushParams = ClawdbotCanvasA2UIPushJSONLParams(jsonl: jsonl)
let pushParams = MoltbotCanvasA2UIPushJSONLParams(jsonl: jsonl)
let pushData = try JSONEncoder().encode(pushParams)
let pushJSON = String(decoding: pushData, as: UTF8.self)
let push = BridgeInvokeRequest(
id: "push",
command: ClawdbotCanvasA2UICommand.pushJSONL.rawValue,
command: MoltbotCanvasA2UICommand.pushJSONL.rawValue,
paramsJSON: pushJSON)
let pushRes = await appModel._test_handleInvoke(push)
#expect(pushRes.ok == false)
@@ -157,7 +157,7 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Test @MainActor func handleDeepLinkSetsErrorWhenNotConnected() async {
let appModel = NodeAppModel()
let url = URL(string: "clawdbot://agent?message=hello")!
let url = URL(string: "moltbot://agent?message=hello")!
await appModel.handleDeepLink(url: url)
#expect(appModel.screen.errorText?.contains("Gateway not connected") == true)
}
@@ -165,7 +165,7 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
@Test @MainActor func handleDeepLinkRejectsOversizedMessage() async {
let appModel = NodeAppModel()
let msg = String(repeating: "a", count: 20001)
let url = URL(string: "clawdbot://agent?message=\(msg)")!
let url = URL(string: "moltbot://agent?message=\(msg)")!
await appModel.handleDeepLink(url: url)
#expect(appModel.screen.errorText?.contains("Deep link too large") == true)
}

View File

@@ -1,6 +1,6 @@
import Testing
import WebKit
@testable import Clawdbot
@testable import Moltbot
@Suite struct ScreenControllerTests {
@Test @MainActor func canvasModeConfiguresWebViewForTouch() {

View File

@@ -1,5 +1,5 @@
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite(.serialized) struct ScreenRecordServiceTests {
@Test func clampDefaultsAndBounds() {

View File

@@ -1,5 +1,5 @@
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct SettingsNetworkingHelpersTests {
@Test func parseHostPortParsesIPv4() {

View File

@@ -1,8 +1,8 @@
import ClawdbotKit
import MoltbotKit
import SwiftUI
import Testing
import UIKit
@testable import Clawdbot
@testable import Moltbot
@Suite struct SwiftUIRenderSmokeTests {
@MainActor private static func host(_ view: some View) -> UIWindow {
@@ -75,7 +75,7 @@ import UIKit
}
@Test @MainActor func voiceWakeToastBuildsAViewHierarchy() {
let root = VoiceWakeToast(command: "clawdbot: do something")
let root = VoiceWakeToast(command: "moltbot: do something")
_ = Self.host(root)
}
}

View File

@@ -1,6 +1,6 @@
import Foundation
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct VoiceWakeGatewaySyncTests {
@Test func decodeGatewayTriggersFromJSONSanitizes() {

View File

@@ -1,7 +1,7 @@
import Foundation
import SwabbleKit
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct VoiceWakeManagerExtractCommandTests {
@Test func extractCommandReturnsNilWhenNoTriggerFound() {

View File

@@ -1,7 +1,7 @@
import Foundation
import SwabbleKit
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite(.serialized) struct VoiceWakeManagerStateTests {
@Test @MainActor func suspendAndResumeCycleUpdatesState() async {

View File

@@ -1,6 +1,6 @@
import Foundation
import Testing
@testable import Clawdbot
@testable import Moltbot
@Suite struct VoiceWakePreferencesTests {
@Test func sanitizeTriggerWordsTrimsAndDropsEmpty() {