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

@@ -6,8 +6,8 @@
{
"layers" : [
{
"image-name" : "clawdbot-mac.png",
"name" : "clawdbot-mac",
"image-name" : "moltbot-mac.png",
"name" : "moltbot-mac",
"position" : {
"scale" : 1.07,
"translation-in-points" : [

View File

@@ -1,18 +1,18 @@
// swift-tools-version: 6.2
// Package manifest for the Clawdbot macOS companion (menu bar app + IPC library).
// Package manifest for the Moltbot macOS companion (menu bar app + IPC library).
import PackageDescription
let package = Package(
name: "Clawdbot",
name: "Moltbot",
platforms: [
.macOS(.v15),
],
products: [
.library(name: "ClawdbotIPC", targets: ["ClawdbotIPC"]),
.library(name: "ClawdbotDiscovery", targets: ["ClawdbotDiscovery"]),
.executable(name: "Clawdbot", targets: ["Clawdbot"]),
.executable(name: "clawdbot-mac", targets: ["ClawdbotMacCLI"]),
.library(name: "MoltbotIPC", targets: ["MoltbotIPC"]),
.library(name: "MoltbotDiscovery", targets: ["MoltbotDiscovery"]),
.executable(name: "Moltbot", targets: ["Moltbot"]),
.executable(name: "moltbot-mac", targets: ["MoltbotMacCLI"]),
],
dependencies: [
.package(url: "https://github.com/orchetect/MenuBarExtraAccess", exact: "1.2.2"),
@@ -25,28 +25,28 @@ let package = Package(
],
targets: [
.target(
name: "ClawdbotIPC",
name: "MoltbotIPC",
dependencies: [],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.target(
name: "ClawdbotDiscovery",
name: "MoltbotDiscovery",
dependencies: [
.product(name: "ClawdbotKit", package: "ClawdbotKit"),
.product(name: "MoltbotKit", package: "MoltbotKit"),
],
path: "Sources/ClawdbotDiscovery",
path: "Sources/MoltbotDiscovery",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.executableTarget(
name: "Clawdbot",
name: "Moltbot",
dependencies: [
"ClawdbotIPC",
"ClawdbotDiscovery",
.product(name: "ClawdbotKit", package: "ClawdbotKit"),
.product(name: "ClawdbotChatUI", package: "ClawdbotKit"),
.product(name: "ClawdbotProtocol", package: "ClawdbotKit"),
"MoltbotIPC",
"MoltbotDiscovery",
.product(name: "MoltbotKit", package: "MoltbotKit"),
.product(name: "MoltbotChatUI", package: "MoltbotKit"),
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
.product(name: "SwabbleKit", package: "swabble"),
.product(name: "MenuBarExtraAccess", package: "MenuBarExtraAccess"),
.product(name: "Subprocess", package: "swift-subprocess"),
@@ -59,30 +59,30 @@ let package = Package(
"Resources/Info.plist",
],
resources: [
.copy("Resources/Clawdbot.icns"),
.copy("Resources/Moltbot.icns"),
.copy("Resources/DeviceModels"),
],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.executableTarget(
name: "ClawdbotMacCLI",
name: "MoltbotMacCLI",
dependencies: [
"ClawdbotDiscovery",
.product(name: "ClawdbotKit", package: "ClawdbotKit"),
.product(name: "ClawdbotProtocol", package: "ClawdbotKit"),
"MoltbotDiscovery",
.product(name: "MoltbotKit", package: "MoltbotKit"),
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
],
path: "Sources/ClawdbotMacCLI",
path: "Sources/MoltbotMacCLI",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.testTarget(
name: "ClawdbotIPCTests",
name: "MoltbotIPCTests",
dependencies: [
"ClawdbotIPC",
"Clawdbot",
"ClawdbotDiscovery",
.product(name: "ClawdbotProtocol", package: "ClawdbotKit"),
"MoltbotIPC",
"Moltbot",
"MoltbotDiscovery",
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
.product(name: "SwabbleKit", package: "swabble"),
],
swiftSettings: [

View File

@@ -10,7 +10,7 @@ struct AboutSettings: View {
VStack(spacing: 8) {
let appIcon = NSApplication.shared.applicationIconImage ?? CritterIconRenderer.makeIcon(blink: 0)
Button {
if let url = URL(string: "https://github.com/clawdbot/clawdbot") {
if let url = URL(string: "https://github.com/moltbot/moltbot") {
NSWorkspace.shared.open(url)
}
} label: {
@@ -29,7 +29,7 @@ struct AboutSettings: View {
}
VStack(spacing: 3) {
Text("Clawdbot")
Text("Moltbot")
.font(.title3.bold())
Text("Version \(self.versionString)")
.foregroundStyle(.secondary)
@@ -49,7 +49,7 @@ struct AboutSettings: View {
AboutLinkRow(
icon: "chevron.left.slash.chevron.right",
title: "GitHub",
url: "https://github.com/clawdbot/clawdbot")
url: "https://github.com/moltbot/moltbot")
AboutLinkRow(icon: "globe", title: "Website", url: "https://steipete.me")
AboutLinkRow(icon: "bird", title: "Twitter", url: "https://twitter.com/steipete")
AboutLinkRow(icon: "envelope", title: "Email", url: "mailto:peter@steipete.me")
@@ -108,7 +108,7 @@ struct AboutSettings: View {
}
private var buildTimestamp: String? {
guard let raw = Bundle.main.object(forInfoDictionaryKey: "ClawdbotBuildTimestamp") as? String
guard let raw = Bundle.main.object(forInfoDictionaryKey: "MoltbotBuildTimestamp") as? String
else { return nil }
let parser = ISO8601DateFormatter()
parser.formatOptions = [.withInternetDateTime]
@@ -122,7 +122,7 @@ struct AboutSettings: View {
}
private var gitCommit: String {
Bundle.main.object(forInfoDictionaryKey: "ClawdbotGitCommit") as? String ?? "unknown"
Bundle.main.object(forInfoDictionaryKey: "MoltbotGitCommit") as? String ?? "unknown"
}
private var bundleID: String {

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import SwiftUI
@MainActor
@@ -81,7 +81,7 @@ private struct EventRow: View {
return f.string(from: date)
}
private func prettyJSON(_ dict: [String: ClawdbotProtocol.AnyCodable]) -> String? {
private func prettyJSON(_ dict: [String: MoltbotProtocol.AnyCodable]) -> String? {
let normalized = dict.mapValues { $0.value }
guard JSONSerialization.isValidJSONObject(normalized),
let data = try? JSONSerialization.data(withJSONObject: normalized, options: [.prettyPrinted]),
@@ -99,8 +99,8 @@ struct AgentEventsWindow_Previews: PreviewProvider {
stream: "tool",
ts: Date().timeIntervalSince1970 * 1000,
data: [
"phase": ClawdbotProtocol.AnyCodable("start"),
"name": ClawdbotProtocol.AnyCodable("bash"),
"phase": MoltbotProtocol.AnyCodable("start"),
"name": MoltbotProtocol.AnyCodable("bash"),
],
summary: nil)
AgentEventStore.shared.append(sample)

View File

@@ -34,7 +34,7 @@ enum AgentWorkspace {
static func resolveWorkspaceURL(from userInput: String?) -> URL {
let trimmed = userInput?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if trimmed.isEmpty { return ClawdbotConfigFile.defaultWorkspaceURL() }
if trimmed.isEmpty { return MoltbotConfigFile.defaultWorkspaceURL() }
let expanded = (trimmed as NSString).expandingTildeInPath
return URL(fileURLWithPath: expanded, isDirectory: true)
}
@@ -154,7 +154,7 @@ enum AgentWorkspace {
static func defaultTemplate() -> String {
let fallback = """
# AGENTS.md - Clawdbot Workspace
# AGENTS.md - Moltbot Workspace
This folder is the assistant's working directory.
@@ -265,7 +265,7 @@ enum AgentWorkspace {
- Timezone (optional)
- Notes
3) ~/.clawdbot/clawdbot.json
3) ~/.clawdbot/moltbot.json
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
## Cleanup

View File

@@ -6,7 +6,7 @@ import SwiftUI
struct AnthropicAuthControls: View {
let connectionMode: AppState.ConnectionMode
@State private var oauthStatus: ClawdbotOAuthStore.AnthropicOAuthStatus = ClawdbotOAuthStore.anthropicOAuthStatus()
@State private var oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus = MoltbotOAuthStore.anthropicOAuthStatus()
@State private var pkce: AnthropicOAuth.PKCE?
@State private var code: String = ""
@State private var busy = false
@@ -42,10 +42,10 @@ struct AnthropicAuthControls: View {
.foregroundStyle(.secondary)
Spacer()
Button("Reveal") {
NSWorkspace.shared.activateFileViewerSelecting([ClawdbotOAuthStore.oauthURL()])
NSWorkspace.shared.activateFileViewerSelecting([MoltbotOAuthStore.oauthURL()])
}
.buttonStyle(.bordered)
.disabled(!FileManager().fileExists(atPath: ClawdbotOAuthStore.oauthURL().path))
.disabled(!FileManager().fileExists(atPath: MoltbotOAuthStore.oauthURL().path))
Button("Refresh") {
self.refresh()
@@ -53,7 +53,7 @@ struct AnthropicAuthControls: View {
.buttonStyle(.bordered)
}
Text(ClawdbotOAuthStore.oauthURL().path)
Text(MoltbotOAuthStore.oauthURL().path)
.font(.caption.monospaced())
.foregroundStyle(.secondary)
.lineLimit(1)
@@ -130,8 +130,8 @@ struct AnthropicAuthControls: View {
}
private func refresh() {
let imported = ClawdbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = ClawdbotOAuthStore.anthropicOAuthStatus()
let imported = MoltbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = MoltbotOAuthStore.anthropicOAuthStatus()
if imported != nil {
self.statusText = "Imported existing OAuth credentials."
}
@@ -172,11 +172,11 @@ struct AnthropicAuthControls: View {
code: parsed.code,
state: parsed.state,
verifier: pkce.verifier)
try ClawdbotOAuthStore.saveAnthropicOAuth(creds)
try MoltbotOAuthStore.saveAnthropicOAuth(creds)
self.refresh()
self.pkce = nil
self.code = ""
self.statusText = "Connected. Clawdbot can now use Claude via OAuth."
self.statusText = "Connected. Moltbot can now use Claude via OAuth."
} catch {
self.statusText = "OAuth failed: \(error.localizedDescription)"
}
@@ -212,7 +212,7 @@ struct AnthropicAuthControls: View {
extension AnthropicAuthControls {
init(
connectionMode: AppState.ConnectionMode,
oauthStatus: ClawdbotOAuthStore.AnthropicOAuthStatus,
oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus,
pkce: AnthropicOAuth.PKCE? = nil,
code: String = "",
busy: Bool = false,

View File

@@ -18,7 +18,7 @@ enum AnthropicAuthMode: Equatable {
var shortLabel: String {
switch self {
case .oauthFile: "OAuth (Clawdbot token file)"
case .oauthFile: "OAuth (Moltbot token file)"
case .oauthEnv: "OAuth (env var)"
case .apiKeyEnv: "API key (env var)"
case .missing: "Missing credentials"
@@ -36,7 +36,7 @@ enum AnthropicAuthMode: Equatable {
enum AnthropicAuthResolver {
static func resolve(
environment: [String: String] = ProcessInfo.processInfo.environment,
oauthStatus: ClawdbotOAuthStore.AnthropicOAuthStatus = ClawdbotOAuthStore
oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus = MoltbotOAuthStore
.anthropicOAuthStatus()) -> AnthropicAuthMode
{
if oauthStatus.isConnected { return .oauthFile }
@@ -194,10 +194,10 @@ enum AnthropicOAuth {
}
}
enum ClawdbotOAuthStore {
enum MoltbotOAuthStore {
static let oauthFilename = "oauth.json"
private static let providerKey = "anthropic"
private static let clawdbotOAuthDirEnv = "CLAWDBOT_OAUTH_DIR"
private static let moltbotOAuthDirEnv = "CLAWDBOT_OAUTH_DIR"
private static let legacyPiDirEnv = "PI_CODING_AGENT_DIR"
enum AnthropicOAuthStatus: Equatable {
@@ -215,12 +215,12 @@ enum ClawdbotOAuthStore {
var shortDescription: String {
switch self {
case .missingFile: "Clawdbot OAuth token file not found"
case .unreadableFile: "Clawdbot OAuth token file not readable"
case .invalidJSON: "Clawdbot OAuth token file invalid"
case .missingProviderEntry: "No Anthropic entry in Clawdbot OAuth token file"
case .missingFile: "Moltbot OAuth token file not found"
case .unreadableFile: "Moltbot OAuth token file not readable"
case .invalidJSON: "Moltbot OAuth token file invalid"
case .missingProviderEntry: "No Anthropic entry in Moltbot OAuth token file"
case .missingTokens: "Anthropic entry missing tokens"
case .connected: "Clawdbot OAuth credentials found"
case .connected: "Moltbot OAuth credentials found"
}
}
}

View File

@@ -1,10 +1,10 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
// Prefer the ClawdbotKit wrapper to keep gateway request payloads consistent.
typealias AnyCodable = ClawdbotKit.AnyCodable
typealias InstanceIdentity = ClawdbotKit.InstanceIdentity
// Prefer the MoltbotKit wrapper to keep gateway request payloads consistent.
typealias AnyCodable = MoltbotKit.AnyCodable
typealias InstanceIdentity = MoltbotKit.InstanceIdentity
extension AnyCodable {
var stringValue: String? { self.value as? String }
@@ -26,19 +26,19 @@ extension AnyCodable {
}
}
extension ClawdbotProtocol.AnyCodable {
extension MoltbotProtocol.AnyCodable {
var stringValue: String? { self.value as? String }
var boolValue: Bool? { self.value as? Bool }
var intValue: Int? { self.value as? Int }
var doubleValue: Double? { self.value as? Double }
var dictionaryValue: [String: ClawdbotProtocol.AnyCodable]? { self.value as? [String: ClawdbotProtocol.AnyCodable] }
var arrayValue: [ClawdbotProtocol.AnyCodable]? { self.value as? [ClawdbotProtocol.AnyCodable] }
var dictionaryValue: [String: MoltbotProtocol.AnyCodable]? { self.value as? [String: MoltbotProtocol.AnyCodable] }
var arrayValue: [MoltbotProtocol.AnyCodable]? { self.value as? [MoltbotProtocol.AnyCodable] }
var foundationValue: Any {
switch self.value {
case let dict as [String: ClawdbotProtocol.AnyCodable]:
case let dict as [String: MoltbotProtocol.AnyCodable]:
dict.mapValues { $0.foundationValue }
case let array as [ClawdbotProtocol.AnyCodable]:
case let array as [MoltbotProtocol.AnyCodable]:
array.map(\.foundationValue)
default:
self.value

View File

@@ -41,13 +41,13 @@ final class AppState {
}
var onboardingSeen: Bool {
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: "clawdbot.onboardingSeen") }
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: "moltbot.onboardingSeen") }
}
}
var debugPaneEnabled: Bool {
didSet {
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "clawdbot.debugPaneEnabled") }
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "moltbot.debugPaneEnabled") }
CanvasManager.shared.refreshDebugStatus()
}
}
@@ -229,11 +229,11 @@ final class AppState {
init(preview: Bool = false) {
self.isPreview = preview || ProcessInfo.processInfo.isRunningTests
let onboardingSeen = UserDefaults.standard.bool(forKey: "clawdbot.onboardingSeen")
let onboardingSeen = UserDefaults.standard.bool(forKey: "moltbot.onboardingSeen")
self.isPaused = UserDefaults.standard.bool(forKey: pauseDefaultsKey)
self.launchAtLogin = false
self.onboardingSeen = onboardingSeen
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: "clawdbot.debugPaneEnabled")
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: "moltbot.debugPaneEnabled")
let savedVoiceWake = UserDefaults.standard.bool(forKey: swabbleEnabledKey)
self.swabbleEnabled = voiceWakeSupported ? savedVoiceWake : false
self.swabbleTriggerWords = UserDefaults.standard
@@ -275,7 +275,7 @@ final class AppState {
UserDefaults.standard.set(IconOverrideSelection.system.rawValue, forKey: iconOverrideKey)
}
let configRoot = ClawdbotConfigFile.loadDict()
let configRoot = MoltbotConfigFile.loadDict()
let configRemoteUrl = GatewayRemoteConfig.resolveUrlString(root: configRoot)
let configRemoteTransport = GatewayRemoteConfig.resolveTransport(root: configRoot)
let resolvedConnectionMode = ConnectionModeResolver.resolve(root: configRoot).mode
@@ -353,7 +353,7 @@ final class AppState {
}
private func startConfigWatcher() {
let configUrl = ClawdbotConfigFile.url()
let configUrl = MoltbotConfigFile.url()
self.configWatcher = ConfigFileWatcher(url: configUrl) { [weak self] in
Task { @MainActor in
self?.applyConfigFromDisk()
@@ -363,7 +363,7 @@ final class AppState {
}
private func applyConfigFromDisk() {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
self.applyConfigOverrides(root)
}
@@ -451,7 +451,7 @@ final class AppState {
Task { @MainActor in
// Keep app-only connection settings local to avoid overwriting remote gateway config.
var root = ClawdbotConfigFile.loadDict()
var root = MoltbotConfigFile.loadDict()
var gateway = root["gateway"] as? [String: Any] ?? [:]
var changed = false
@@ -541,7 +541,7 @@ final class AppState {
} else {
root["gateway"] = gateway
}
ClawdbotConfigFile.saveDict(root)
MoltbotConfigFile.saveDict(root)
}
}
@@ -685,7 +685,7 @@ extension AppState {
state.remoteTarget = "user@example.com"
state.remoteUrl = "wss://gateway.example.ts.net"
state.remoteIdentity = "~/.ssh/id_ed25519"
state.remoteProjectRoot = "~/Projects/clawdbot"
state.remoteProjectRoot = "~/Projects/moltbot"
state.remoteCliPath = ""
return state
}

View File

@@ -15,7 +15,7 @@ final class CLIInstallPrompter {
UserDefaults.standard.set(version, forKey: cliInstallPromptedVersionKey)
let alert = NSAlert()
alert.messageText = "Install Clawdbot CLI?"
alert.messageText = "Install Moltbot CLI?"
alert.informativeText = "Local mode needs the CLI so launchd can run the gateway."
alert.addButton(withTitle: "Install CLI")
alert.addButton(withTitle: "Not now")

View File

@@ -13,7 +13,7 @@ enum CLIInstaller {
fileManager: FileManager) -> String?
{
for basePath in searchPaths {
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("clawdbot").path
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("moltbot").path
var isDirectory: ObjCBool = false
guard fileManager.fileExists(atPath: candidate, isDirectory: &isDirectory),
@@ -37,14 +37,14 @@ enum CLIInstaller {
static func install(statusHandler: @escaping @MainActor @Sendable (String) async -> Void) async {
let expected = GatewayEnvironment.expectedGatewayVersionString() ?? "latest"
let prefix = Self.installPrefix()
await statusHandler("Installing clawdbot CLI…")
await statusHandler("Installing moltbot CLI…")
let cmd = self.installScriptCommand(version: expected, prefix: prefix)
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: nil, timeout: 900)
if response.success {
let parsed = self.parseInstallEvents(response.stdout)
let installedVersion = parsed.last { $0.event == "done" }?.version
let summary = installedVersion.map { "Installed clawdbot \($0)." } ?? "Installed clawdbot."
let summary = installedVersion.map { "Installed moltbot \($0)." } ?? "Installed moltbot."
await statusHandler(summary)
return
}

View File

@@ -1,6 +1,6 @@
import AVFoundation
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import CoreGraphics
import Foundation
import OSLog
@@ -168,7 +168,7 @@ actor CameraCaptureService {
await Self.warmUpCaptureSession()
let tmpMovURL = FileManager().temporaryDirectory
.appendingPathComponent("clawdbot-camera-\(UUID().uuidString).mov")
.appendingPathComponent("moltbot-camera-\(UUID().uuidString).mov")
defer { try? FileManager().removeItem(at: tmpMovURL) }
let outputURL: URL = {
@@ -176,7 +176,7 @@ actor CameraCaptureService {
return URL(fileURLWithPath: outPath)
}
return FileManager().temporaryDirectory
.appendingPathComponent("clawdbot-camera-\(UUID().uuidString).mp4")
.appendingPathComponent("moltbot-camera-\(UUID().uuidString).mp4")
}()
// Ensure we don't fail exporting due to an existing file.

View File

@@ -1,11 +1,11 @@
import AppKit
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import Foundation
import WebKit
final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
static let messageName = "clawdbotCanvasA2UIAction"
static let messageName = "moltbotCanvasA2UIAction"
private let sessionKey: String
@@ -52,7 +52,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
}()
guard !userAction.isEmpty else { return }
guard let name = ClawdbotCanvasA2UIAction.extractActionName(userAction) else { return }
guard let name = MoltbotCanvasA2UIAction.extractActionName(userAction) else { return }
let actionId =
(userAction["id"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
?? UUID().uuidString
@@ -64,15 +64,15 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
let sourceComponentId = (userAction["sourceComponentId"] as? String)?
.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty ?? "-"
let instanceId = InstanceIdentity.instanceId.lowercased()
let contextJSON = ClawdbotCanvasA2UIAction.compactJSON(userAction["context"])
let contextJSON = MoltbotCanvasA2UIAction.compactJSON(userAction["context"])
// Token-efficient and unambiguous. The agent should treat this as a UI event and (by default) update Canvas.
let messageContext = ClawdbotCanvasA2UIAction.AgentMessageContext(
let messageContext = MoltbotCanvasA2UIAction.AgentMessageContext(
actionName: name,
session: .init(key: self.sessionKey, surfaceId: surfaceId),
component: .init(id: sourceComponentId, host: InstanceIdentity.displayName, instanceId: instanceId),
contextJSON: contextJSON)
let text = ClawdbotCanvasA2UIAction.formatAgentMessage(messageContext)
let text = MoltbotCanvasA2UIAction.formatAgentMessage(messageContext)
Task { [weak webView] in
if AppStateStore.shared.connectionMode == .local {
@@ -91,7 +91,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
await MainActor.run {
guard let webView else { return }
let js = ClawdbotCanvasA2UIAction.jsDispatchA2UIActionStatus(
let js = MoltbotCanvasA2UIAction.jsDispatchA2UIActionStatus(
actionId: actionId,
ok: result.ok,
error: result.error)
@@ -144,5 +144,5 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
return false
}
// Formatting helpers live in ClawdbotKit (`ClawdbotCanvasA2UIAction`).
// Formatting helpers live in MoltbotKit (`MoltbotCanvasA2UIAction`).
}

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import Foundation
import OSLog
@@ -26,7 +26,7 @@ final class CanvasManager {
private nonisolated static let canvasRoot: URL = {
let base = FileManager().urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return base.appendingPathComponent("Clawdbot/canvas", isDirectory: true)
return base.appendingPathComponent("Moltbot/canvas", isDirectory: true)
}()
func show(sessionKey: String, path: String? = nil, placement: CanvasPlacement? = nil) throws -> String {
@@ -231,7 +231,7 @@ final class CanvasManager {
private static func resolveA2UIHostUrl(from raw: String?) -> String? {
let trimmed = raw?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
guard !trimmed.isEmpty, let base = URL(string: trimmed) else { return nil }
return base.appendingPathComponent("__clawdbot__/a2ui/").absoluteString + "?platform=macos"
return base.appendingPathComponent("__moltbot__/a2ui/").absoluteString + "?platform=macos"
}
// MARK: - Anchoring

View File

@@ -1,7 +1,7 @@
import Foundation
enum CanvasScheme {
static let scheme = "clawdbot-canvas"
static let scheme = "moltbot-canvas"
static func makeURL(session: String, path: String? = nil) -> URL? {
var comps = URLComponents()

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import OSLog
import WebKit
@@ -222,7 +222,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
let name = fileURL.deletingPathExtension().lastPathComponent
guard !name.isEmpty, !ext.isEmpty else { return nil }
let bundle = ClawdbotKitResources.bundle
let bundle = MoltbotKitResources.bundle
let resourceURL =
bundle.url(forResource: name, withExtension: ext, subdirectory: subdirectory)
?? bundle.url(forResource: name, withExtension: ext)

View File

@@ -23,7 +23,7 @@ extension CanvasWindowController {
}
static func storedFrameDefaultsKey(sessionKey: String) -> String {
"clawdbot.canvas.frame.\(self.sanitizeSessionKey(sessionKey))"
"moltbot.canvas.frame.\(self.sanitizeSessionKey(sessionKey))"
}
static func loadRestoredFrame(sessionKey: String) -> NSRect? {

View File

@@ -17,7 +17,7 @@ extension CanvasWindowController {
let scheme = url.scheme?.lowercased()
// Deep links: allow local Canvas content to invoke the agent without bouncing through NSWorkspace.
if scheme == "clawdbot" {
if scheme == "moltbot" {
if self.webView.url?.scheme == CanvasScheme.scheme {
Task { await DeepLinkHandler.shared.handle(url: url) }
} else {

View File

@@ -1,5 +1,5 @@
import AppKit
import ClawdbotIPC
import MoltbotIPC
extension CanvasWindowController {
// MARK: - Window
@@ -12,7 +12,7 @@ extension CanvasWindowController {
styleMask: [.titled, .closable, .resizable, .miniaturizable],
backing: .buffered,
defer: false)
window.title = "Clawdbot Canvas"
window.title = "Moltbot Canvas"
window.isReleasedWhenClosed = false
window.contentView = contentView
window.center()

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import Foundation
import WebKit
@@ -57,8 +57,8 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
(() => {
try {
if (location.protocol !== '\(CanvasScheme.scheme):') return;
if (globalThis.__clawdbotA2UIBridgeInstalled) return;
globalThis.__clawdbotA2UIBridgeInstalled = true;
if (globalThis.__moltbotA2UIBridgeInstalled) return;
globalThis.__moltbotA2UIBridgeInstalled = true;
const deepLinkKey = \(Self.jsStringLiteral(deepLinkKey));
const sessionKey = \(Self.jsStringLiteral(injectedSessionKey));
@@ -89,7 +89,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
// If the bundled A2UI shell is present, let it forward actions so we keep its richer
// context resolution (data model path lookups, surface detection, etc.).
const hasBundledA2UIHost = !!globalThis.clawdbotA2UI || !!document.querySelector('clawdbot-a2ui-host');
const hasBundledA2UIHost = !!globalThis.clawdbotA2UI || !!document.querySelector('moltbot-a2ui-host');
if (hasBundledA2UIHost && handler?.postMessage) return;
// Otherwise, forward directly when possible.
@@ -115,7 +115,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
params.set('deliver', 'false');
params.set('channel', 'last');
params.set('key', deepLinkKey);
location.href = 'clawdbot://agent?' + params.toString();
location.href = 'moltbot://agent?' + params.toString();
} catch {}
}, true);
} catch {}
@@ -268,7 +268,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
let js = """
(() => {
try {
const api = globalThis.__clawdbot;
const api = globalThis.__moltbot;
if (!api) return;
if (typeof api.setDebugStatusEnabled === 'function') {
api.setDebugStatusEnabled(\(enabled ? "true" : "false"));
@@ -336,7 +336,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
path = outPath
} else {
let ts = Int(Date().timeIntervalSince1970)
path = "/tmp/clawdbot-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
path = "/tmp/moltbot-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
}
try png.write(to: URL(fileURLWithPath: path), options: [.atomic])

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import SwiftUI
extension ChannelsSettings {

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
extension ChannelsStore {
@@ -28,7 +28,7 @@ extension ChannelsStore {
params: nil,
timeoutMs: 10000)
self.configStatus = snap.valid == false
? "Config invalid; fix it in ~/.clawdbot/clawdbot.json."
? "Config invalid; fix it in ~/.clawdbot/moltbot.json."
: nil
self.configRoot = snap.config?.mapValues { $0.foundationValue } ?? [:]
self.configDraft = cloneConfigValue(self.configRoot) as? [String: Any] ?? self.configRoot

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
extension ChannelsStore {

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
import Observation

View File

@@ -1,19 +1,19 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
enum ClawdbotConfigFile {
enum MoltbotConfigFile {
private static let logger = Logger(subsystem: "com.clawdbot", category: "config")
static func url() -> URL {
ClawdbotPaths.configURL
MoltbotPaths.configURL
}
static func stateDirURL() -> URL {
ClawdbotPaths.stateDirURL
MoltbotPaths.stateDirURL
}
static func defaultWorkspaceURL() -> URL {
ClawdbotPaths.workspaceURL
MoltbotPaths.workspaceURL
}
static func loadDict() -> [String: Any] {

View File

@@ -1,6 +1,6 @@
import Foundation
enum ClawdbotEnv {
enum MoltbotEnv {
static func path(_ key: String) -> String? {
// Normalize env overrides once so UI + file IO stay consistent.
guard let raw = getenv(key) else { return nil }
@@ -13,12 +13,12 @@ enum ClawdbotEnv {
}
}
enum ClawdbotPaths {
enum MoltbotPaths {
private static let configPathEnv = "CLAWDBOT_CONFIG_PATH"
private static let stateDirEnv = "CLAWDBOT_STATE_DIR"
static var stateDirURL: URL {
if let override = ClawdbotEnv.path(self.stateDirEnv) {
if let override = MoltbotEnv.path(self.stateDirEnv) {
return URL(fileURLWithPath: override, isDirectory: true)
}
return FileManager().homeDirectoryForCurrentUser
@@ -26,10 +26,10 @@ enum ClawdbotPaths {
}
static var configURL: URL {
if let override = ClawdbotEnv.path(self.configPathEnv) {
if let override = MoltbotEnv.path(self.configPathEnv) {
return URL(fileURLWithPath: override)
}
return self.stateDirURL.appendingPathComponent("clawdbot.json")
return self.stateDirURL.appendingPathComponent("moltbot.json")
}
static var workspaceURL: URL {

View File

@@ -1,13 +1,13 @@
import Foundation
enum CommandResolver {
private static let projectRootDefaultsKey = "clawdbot.gatewayProjectRootPath"
private static let helperName = "clawdbot"
private static let projectRootDefaultsKey = "moltbot.gatewayProjectRootPath"
private static let helperName = "moltbot"
static func gatewayEntrypoint(in root: URL) -> String? {
let distEntry = root.appendingPathComponent("dist/index.js").path
if FileManager().isReadableFile(atPath: distEntry) { return distEntry }
let binEntry = root.appendingPathComponent("bin/clawdbot.js").path
let binEntry = root.appendingPathComponent("bin/moltbot.js").path
if FileManager().isReadableFile(atPath: binEntry) { return binEntry }
return nil
}
@@ -52,7 +52,7 @@ enum CommandResolver {
return url
}
let fallback = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Projects/clawdbot")
.appendingPathComponent("Projects/moltbot")
if FileManager().fileExists(atPath: fallback.path) {
return fallback
}
@@ -87,17 +87,17 @@ enum CommandResolver {
// Dev-only convenience. Avoid project-local PATH hijacking in release builds.
extras.insert(projectRoot.appendingPathComponent("node_modules/.bin").path, at: 0)
#endif
let clawdbotPaths = self.clawdbotManagedPaths(home: home)
if !clawdbotPaths.isEmpty {
extras.insert(contentsOf: clawdbotPaths, at: 1)
let moltbotPaths = self.clawdbotManagedPaths(home: home)
if !moltbotPaths.isEmpty {
extras.insert(contentsOf: moltbotPaths, at: 1)
}
extras.insert(contentsOf: self.nodeManagerBinPaths(home: home), at: 1 + clawdbotPaths.count)
extras.insert(contentsOf: self.nodeManagerBinPaths(home: home), at: 1 + moltbotPaths.count)
var seen = Set<String>()
// Preserve order while stripping duplicates so PATH lookups remain deterministic.
return (extras + current).filter { seen.insert($0).inserted }
}
private static func clawdbotManagedPaths(home: URL) -> [String] {
private static func moltbotManagedPaths(home: URL) -> [String] {
let base = home.appendingPathComponent(".clawdbot")
let bin = base.appendingPathComponent("bin")
let nodeBin = base.appendingPathComponent("tools/node/bin")
@@ -187,11 +187,11 @@ enum CommandResolver {
return nil
}
static func clawdbotExecutable(searchPaths: [String]? = nil) -> String? {
static func moltbotExecutable(searchPaths: [String]? = nil) -> String? {
self.findExecutable(named: self.helperName, searchPaths: searchPaths)
}
static func projectClawdbotExecutable(projectRoot: URL? = nil) -> String? {
static func projectMoltbotExecutable(projectRoot: URL? = nil) -> String? {
#if DEBUG
let root = projectRoot ?? self.projectRoot()
let candidate = root.appendingPathComponent("node_modules/.bin").appendingPathComponent(self.helperName).path
@@ -202,11 +202,11 @@ enum CommandResolver {
}
static func nodeCliPath() -> String? {
let candidate = self.projectRoot().appendingPathComponent("bin/clawdbot.js").path
let candidate = self.projectRoot().appendingPathComponent("bin/moltbot.js").path
return FileManager().isReadableFile(atPath: candidate) ? candidate : nil
}
static func hasAnyClawdbotInvoker(searchPaths: [String]? = nil) -> Bool {
static func hasAnyMoltbotInvoker(searchPaths: [String]? = nil) -> Bool {
if self.clawdbotExecutable(searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "pnpm", searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "node", searchPaths: searchPaths) != nil,
@@ -217,7 +217,7 @@ enum CommandResolver {
return false
}
static func clawdbotNodeCommand(
static func moltbotNodeCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
@@ -238,8 +238,8 @@ enum CommandResolver {
switch runtimeResult {
case let .success(runtime):
let root = self.projectRoot()
if let clawdbotPath = self.projectClawdbotExecutable(projectRoot: root) {
return [clawdbotPath, subcommand] + extraArgs
if let moltbotPath = self.projectMoltbotExecutable(projectRoot: root) {
return [moltbotPath, subcommand] + extraArgs
}
if let entry = self.gatewayEntrypoint(in: root) {
@@ -251,14 +251,14 @@ enum CommandResolver {
}
if let pnpm = self.findExecutable(named: "pnpm", searchPaths: searchPaths) {
// Use --silent to avoid pnpm lifecycle banners that would corrupt JSON outputs.
return [pnpm, "--silent", "clawdbot", subcommand] + extraArgs
return [pnpm, "--silent", "moltbot", subcommand] + extraArgs
}
if let clawdbotPath = self.clawdbotExecutable(searchPaths: searchPaths) {
return [clawdbotPath, subcommand] + extraArgs
if let moltbotPath = self.clawdbotExecutable(searchPaths: searchPaths) {
return [moltbotPath, subcommand] + extraArgs
}
let missingEntry = """
clawdbot entrypoint missing (looked for dist/index.js or bin/clawdbot.js); run pnpm build.
moltbot entrypoint missing (looked for dist/index.js or bin/moltbot.js); run pnpm build.
"""
return self.errorCommand(with: missingEntry)
@@ -267,8 +267,8 @@ enum CommandResolver {
}
}
// Existing callers still refer to clawdbotCommand; keep it as node alias.
static func clawdbotCommand(
// Existing callers still refer to moltbotCommand; keep it as node alias.
static func moltbotCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
@@ -289,7 +289,7 @@ enum CommandResolver {
guard !settings.target.isEmpty else { return nil }
guard let parsed = self.parseSSHTarget(settings.target) else { return nil }
// Run the real clawdbot CLI on the remote host.
// Run the real moltbot CLI on the remote host.
let exportedPath = [
"/opt/homebrew/bin",
"/usr/local/bin",
@@ -306,7 +306,7 @@ enum CommandResolver {
let projectSection = if userPRJ.isEmpty {
"""
DEFAULT_PRJ="$HOME/Projects/clawdbot"
DEFAULT_PRJ="$HOME/Projects/moltbot"
if [ -d "$DEFAULT_PRJ" ]; then
PRJ="$DEFAULT_PRJ"
cd "$PRJ" || { echo "Project root not found: $PRJ"; exit 127; }
@@ -345,9 +345,9 @@ enum CommandResolver {
CLI="";
\(cliSection)
\(projectSection)
if command -v clawdbot >/dev/null 2>&1; then
CLI="$(command -v clawdbot)"
clawdbot \(quotedArgs);
if command -v moltbot >/dev/null 2>&1; then
CLI="$(command -v moltbot)"
moltbot \(quotedArgs);
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/dist/index.js" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/dist/index.js"
@@ -355,18 +355,18 @@ enum CommandResolver {
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/clawdbot.js" ]; then
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/moltbot.js" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/bin/clawdbot.js"
node "$PRJ/bin/clawdbot.js" \(quotedArgs);
CLI="node $PRJ/bin/moltbot.js"
node "$PRJ/bin/moltbot.js" \(quotedArgs);
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif command -v pnpm >/dev/null 2>&1; then
CLI="pnpm --silent clawdbot"
pnpm --silent clawdbot \(quotedArgs);
CLI="pnpm --silent moltbot"
pnpm --silent moltbot \(quotedArgs);
else
echo "clawdbot CLI missing on remote host"; exit 127;
echo "moltbot CLI missing on remote host"; exit 127;
fi
"""
let options: [String] = [
@@ -394,7 +394,7 @@ enum CommandResolver {
defaults: UserDefaults = .standard,
configRoot: [String: Any]? = nil) -> RemoteSettings
{
let root = configRoot ?? ClawdbotConfigFile.loadDict()
let root = configRoot ?? MoltbotConfigFile.loadDict()
let mode = ConnectionModeResolver.resolve(root: root, defaults: defaults).mode
let target = defaults.string(forKey: remoteTargetKey) ?? ""
let identity = defaults.string(forKey: remoteIdentityKey) ?? ""

View File

@@ -153,7 +153,7 @@ extension ConfigSettings {
.font(.title3.weight(.semibold))
Text(self.isNixMode
? "This tab is read-only in Nix mode. Edit config via Nix and rebuild."
: "Edit ~/.clawdbot/clawdbot.json using the schema-driven form.")
: "Edit ~/.clawdbot/moltbot.json using the schema-driven form.")
.font(.callout)
.foregroundStyle(.secondary)
}

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
enum ConfigStore {
@@ -44,7 +44,7 @@ enum ConfigStore {
if let gateway = await self.loadFromGateway() {
return gateway
}
return ClawdbotConfigFile.loadDict()
return MoltbotConfigFile.loadDict()
}
@MainActor
@@ -63,7 +63,7 @@ enum ConfigStore {
do {
try await self.saveToGateway(root)
} catch {
ClawdbotConfigFile.saveDict(root)
MoltbotConfigFile.saveDict(root)
}
}
}

View File

@@ -43,7 +43,7 @@ enum ConnectionModeResolver {
return EffectiveConnectionMode(mode: storedMode, source: .userDefaults)
}
let seen = defaults.bool(forKey: "clawdbot.onboardingSeen")
let seen = defaults.bool(forKey: "moltbot.onboardingSeen")
return EffectiveConnectionMode(mode: seen ? .local : .unconfigured, source: .onboarding)
}
}

View File

@@ -2,43 +2,43 @@ import Foundation
let launchdLabel = "com.clawdbot.mac"
let gatewayLaunchdLabel = "com.clawdbot.gateway"
let onboardingVersionKey = "clawdbot.onboardingVersion"
let onboardingVersionKey = "moltbot.onboardingVersion"
let currentOnboardingVersion = 7
let pauseDefaultsKey = "clawdbot.pauseEnabled"
let iconAnimationsEnabledKey = "clawdbot.iconAnimationsEnabled"
let swabbleEnabledKey = "clawdbot.swabbleEnabled"
let swabbleTriggersKey = "clawdbot.swabbleTriggers"
let voiceWakeTriggerChimeKey = "clawdbot.voiceWakeTriggerChime"
let voiceWakeSendChimeKey = "clawdbot.voiceWakeSendChime"
let showDockIconKey = "clawdbot.showDockIcon"
let pauseDefaultsKey = "moltbot.pauseEnabled"
let iconAnimationsEnabledKey = "moltbot.iconAnimationsEnabled"
let swabbleEnabledKey = "moltbot.swabbleEnabled"
let swabbleTriggersKey = "moltbot.swabbleTriggers"
let voiceWakeTriggerChimeKey = "moltbot.voiceWakeTriggerChime"
let voiceWakeSendChimeKey = "moltbot.voiceWakeSendChime"
let showDockIconKey = "moltbot.showDockIcon"
let defaultVoiceWakeTriggers = ["clawd", "claude"]
let voiceWakeMaxWords = 32
let voiceWakeMaxWordLength = 64
let voiceWakeMicKey = "clawdbot.voiceWakeMicID"
let voiceWakeMicNameKey = "clawdbot.voiceWakeMicName"
let voiceWakeLocaleKey = "clawdbot.voiceWakeLocaleID"
let voiceWakeAdditionalLocalesKey = "clawdbot.voiceWakeAdditionalLocaleIDs"
let voicePushToTalkEnabledKey = "clawdbot.voicePushToTalkEnabled"
let talkEnabledKey = "clawdbot.talkEnabled"
let iconOverrideKey = "clawdbot.iconOverride"
let connectionModeKey = "clawdbot.connectionMode"
let remoteTargetKey = "clawdbot.remoteTarget"
let remoteIdentityKey = "clawdbot.remoteIdentity"
let remoteProjectRootKey = "clawdbot.remoteProjectRoot"
let remoteCliPathKey = "clawdbot.remoteCliPath"
let canvasEnabledKey = "clawdbot.canvasEnabled"
let cameraEnabledKey = "clawdbot.cameraEnabled"
let systemRunPolicyKey = "clawdbot.systemRunPolicy"
let systemRunAllowlistKey = "clawdbot.systemRunAllowlist"
let systemRunEnabledKey = "clawdbot.systemRunEnabled"
let locationModeKey = "clawdbot.locationMode"
let locationPreciseKey = "clawdbot.locationPreciseEnabled"
let peekabooBridgeEnabledKey = "clawdbot.peekabooBridgeEnabled"
let deepLinkKeyKey = "clawdbot.deepLinkKey"
let modelCatalogPathKey = "clawdbot.modelCatalogPath"
let modelCatalogReloadKey = "clawdbot.modelCatalogReload"
let cliInstallPromptedVersionKey = "clawdbot.cliInstallPromptedVersion"
let heartbeatsEnabledKey = "clawdbot.heartbeatsEnabled"
let debugFileLogEnabledKey = "clawdbot.debug.fileLogEnabled"
let appLogLevelKey = "clawdbot.debug.appLogLevel"
let voiceWakeMicKey = "moltbot.voiceWakeMicID"
let voiceWakeMicNameKey = "moltbot.voiceWakeMicName"
let voiceWakeLocaleKey = "moltbot.voiceWakeLocaleID"
let voiceWakeAdditionalLocalesKey = "moltbot.voiceWakeAdditionalLocaleIDs"
let voicePushToTalkEnabledKey = "moltbot.voicePushToTalkEnabled"
let talkEnabledKey = "moltbot.talkEnabled"
let iconOverrideKey = "moltbot.iconOverride"
let connectionModeKey = "moltbot.connectionMode"
let remoteTargetKey = "moltbot.remoteTarget"
let remoteIdentityKey = "moltbot.remoteIdentity"
let remoteProjectRootKey = "moltbot.remoteProjectRoot"
let remoteCliPathKey = "moltbot.remoteCliPath"
let canvasEnabledKey = "moltbot.canvasEnabled"
let cameraEnabledKey = "moltbot.cameraEnabled"
let systemRunPolicyKey = "moltbot.systemRunPolicy"
let systemRunAllowlistKey = "moltbot.systemRunAllowlist"
let systemRunEnabledKey = "moltbot.systemRunEnabled"
let locationModeKey = "moltbot.locationMode"
let locationPreciseKey = "moltbot.locationPreciseEnabled"
let peekabooBridgeEnabledKey = "moltbot.peekabooBridgeEnabled"
let deepLinkKeyKey = "moltbot.deepLinkKey"
let modelCatalogPathKey = "moltbot.modelCatalogPath"
let modelCatalogReloadKey = "moltbot.modelCatalogReload"
let cliInstallPromptedVersionKey = "moltbot.cliInstallPromptedVersion"
let heartbeatsEnabledKey = "moltbot.heartbeatsEnabled"
let debugFileLogEnabledKey = "moltbot.debug.fileLogEnabled"
let appLogLevelKey = "moltbot.debug.appLogLevel"
let voiceWakeSupported: Bool = ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 26

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import SwiftUI
@@ -20,7 +20,7 @@ struct ControlAgentEvent: Codable, Sendable, Identifiable {
let seq: Int
let stream: String
let ts: Double
let data: [String: ClawdbotProtocol.AnyCodable]
let data: [String: MoltbotProtocol.AnyCodable]
let summary: String?
}
@@ -163,8 +163,8 @@ final class ControlChannel {
timeoutMs: Double? = nil) async throws -> Data
{
do {
let rawParams = params?.reduce(into: [String: ClawdbotKit.AnyCodable]()) {
$0[$1.key] = ClawdbotKit.AnyCodable($1.value.base)
let rawParams = params?.reduce(into: [String: MoltbotKit.AnyCodable]()) {
$0[$1.key] = MoltbotKit.AnyCodable($1.value.base)
}
let data = try await GatewayConnection.shared.request(
method: method,
@@ -400,20 +400,20 @@ final class ControlChannel {
}
private static func bridgeToProtocolArgs(
_ value: ClawdbotProtocol.AnyCodable?) -> [String: ClawdbotProtocol.AnyCodable]?
_ value: MoltbotProtocol.AnyCodable?) -> [String: MoltbotProtocol.AnyCodable]?
{
guard let value else { return nil }
if let dict = value.value as? [String: ClawdbotProtocol.AnyCodable] {
if let dict = value.value as? [String: MoltbotProtocol.AnyCodable] {
return dict
}
if let dict = value.value as? [String: ClawdbotKit.AnyCodable],
if let dict = value.value as? [String: MoltbotKit.AnyCodable],
let data = try? JSONEncoder().encode(dict),
let decoded = try? JSONDecoder().decode([String: ClawdbotProtocol.AnyCodable].self, from: data)
let decoded = try? JSONDecoder().decode([String: MoltbotProtocol.AnyCodable].self, from: data)
{
return decoded
}
if let data = try? JSONEncoder().encode(value),
let decoded = try? JSONDecoder().decode([String: ClawdbotProtocol.AnyCodable].self, from: data)
let decoded = try? JSONDecoder().decode([String: MoltbotProtocol.AnyCodable].self, from: data)
{
return decoded
}
@@ -422,6 +422,6 @@ final class ControlChannel {
}
extension Notification.Name {
static let controlHeartbeat = Notification.Name("clawdbot.control.heartbeat")
static let controlAgentEvent = Notification.Name("clawdbot.control.agent")
static let controlHeartbeat = Notification.Name("moltbot.control.heartbeat")
static let controlAgentEvent = Notification.Name("moltbot.control.agent")
}

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
import SwiftUI

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Observation
import SwiftUI

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import OSLog

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
extension CronSettings {

View File

@@ -57,7 +57,7 @@ extension CronSettings {
static func exerciseForTesting() {
let store = CronJobsStore(isPreview: true)
store.schedulerEnabled = false
store.schedulerStorePath = "/tmp/clawdbot-cron-store.json"
store.schedulerStorePath = "/tmp/moltbot-cron-store.json"
let job = CronJob(
id: "job-1",

View File

@@ -3,9 +3,9 @@ import Foundation
import SwiftUI
enum DebugActions {
private static let verboseDefaultsKey = "clawdbot.debug.verboseMain"
private static let verboseDefaultsKey = "moltbot.debug.verboseMain"
private static let sessionMenuLimit = 12
private static let onboardingSeenKey = "clawdbot.onboardingSeen"
private static let onboardingSeenKey = "moltbot.onboardingSeen"
@MainActor
static func openAgentEventsWindow() {
@@ -63,7 +63,7 @@ enum DebugActions {
}
static func sendTestNotification() async {
_ = await NotificationManager().send(title: "Clawdbot", body: "Test notification", sound: nil)
_ = await NotificationManager().send(title: "Moltbot", body: "Test notification", sound: nil)
}
static func sendDebugVoice() async -> Result<String, DebugActionError> {
@@ -196,7 +196,7 @@ enum DebugActions {
private static func resolveSessionStorePath() -> String {
let defaultPath = SessionLoader.defaultStorePath
let configURL = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot/clawdbot.json")
.appendingPathComponent(".clawdbot/moltbot.json")
guard
let data = try? Data(contentsOf: configURL),
let parsed = try? JSONSerialization.jsonObject(with: data) as? [String: Any],

View File

@@ -103,7 +103,7 @@ struct DebugSettings: View {
}
Text(
"When enabled, Clawdbot won't install or manage \(gatewayLaunchdLabel). " +
"When enabled, Moltbot won't install or manage \(gatewayLaunchdLabel). " +
"It will only attach to an existing Gateway.")
.font(.caption)
.foregroundStyle(.secondary)
@@ -203,7 +203,7 @@ struct DebugSettings: View {
Button("Copy sample URL") {
let msg = "Hello from deep link"
let encoded = msg.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? msg
let url = "clawdbot://agent?message=\(encoded)&key=\(key)"
let url = "moltbot://agent?message=\(encoded)&key=\(key)"
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(url, forType: .string)
}
@@ -211,7 +211,7 @@ struct DebugSettings: View {
Spacer(minLength: 0)
}
Text("Deep links (clawdbot://…) are always enabled; the key controls unattended runs.")
Text("Deep links (moltbot://…) are always enabled; the key controls unattended runs.")
.font(.caption2)
.foregroundStyle(.secondary)
@@ -274,7 +274,7 @@ struct DebugSettings: View {
Toggle("Write rolling diagnostics log (JSONL)", isOn: self.$diagnosticsFileLogEnabled)
.toggleStyle(.checkbox)
.help(
"Writes a rotating, local-only log under ~/Library/Logs/Clawdbot/. " +
"Writes a rotating, local-only log under ~/Library/Logs/Moltbot/. " +
"Enable only while actively debugging.")
HStack(spacing: 8) {
@@ -382,10 +382,10 @@ struct DebugSettings: View {
GroupBox("Paths") {
VStack(alignment: .leading, spacing: 12) {
VStack(alignment: .leading, spacing: 6) {
Text("Clawdbot project root")
Text("Moltbot project root")
.font(.caption.weight(.semibold))
HStack(spacing: 8) {
TextField("Path to clawdbot repo", text: self.$gatewayRootInput)
TextField("Path to moltbot repo", text: self.$gatewayRootInput)
.textFieldStyle(.roundedBorder)
.font(.caption.monospaced())
.onSubmit { self.saveRelayRoot() }
@@ -393,7 +393,7 @@ struct DebugSettings: View {
.buttonStyle(.borderedProminent)
Button("Reset") {
let def = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Projects/clawdbot").path
.appendingPathComponent("Projects/moltbot").path
self.gatewayRootInput = def
self.saveRelayRoot()
}
@@ -423,7 +423,7 @@ struct DebugSettings: View {
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Used by the CLI session loader; stored in ~/.clawdbot/clawdbot.json.")
Text("Used by the CLI session loader; stored in ~/.clawdbot/moltbot.json.")
.font(.footnote)
.foregroundStyle(.secondary)
}
@@ -524,15 +524,15 @@ struct DebugSettings: View {
VStack(alignment: .leading, spacing: 6) {
Text(
"Note: macOS may require restarting Clawdbot after enabling Accessibility or Screen Recording.")
"Note: macOS may require restarting Moltbot after enabling Accessibility or Screen Recording.")
.font(.caption)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
Button {
LaunchdManager.startClawdbot()
LaunchdManager.startMoltbot()
} label: {
Label("Restart Clawdbot", systemImage: "arrow.counterclockwise")
Label("Restart Moltbot", systemImage: "arrow.counterclockwise")
}
.buttonStyle(.bordered)
.controlSize(.small)
@@ -832,7 +832,7 @@ struct DebugSettings: View {
private func configURL() -> URL {
FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot")
.appendingPathComponent("clawdbot.json")
.appendingPathComponent("moltbot.json")
}
}
@@ -981,7 +981,7 @@ extension DebugSettings {
view.modelsCount = 3
view.modelsLoading = false
view.modelsError = "Failed to load models"
view.gatewayRootInput = "/tmp/clawdbot"
view.gatewayRootInput = "/tmp/moltbot"
view.sessionStorePath = "/tmp/sessions.json"
view.sessionStoreSaveError = "Save failed"
view.debugSendInFlight = true

View File

@@ -1,5 +1,5 @@
import AppKit
import ClawdbotKit
import MoltbotKit
import Foundation
import OSLog
import Security
@@ -23,7 +23,7 @@ final class DeepLinkHandler {
return
}
guard !AppStateStore.shared.isPaused else {
self.presentAlert(title: "Clawdbot is paused", message: "Unpause Clawdbot to run agent actions.")
self.presentAlert(title: "Moltbot is paused", message: "Unpause Moltbot to run agent actions.")
return
}
@@ -51,7 +51,7 @@ final class DeepLinkHandler {
let trimmed = messagePreview.count > 240 ? "\(messagePreview.prefix(240))" : messagePreview
let body =
"Run the agent with this message?\n\n\(trimmed)\n\nURL:\n\(originalURL.absoluteString)"
guard self.confirm(title: "Run Clawdbot agent?", message: body) else { return }
guard self.confirm(title: "Run Moltbot agent?", message: body) else { return }
}
if AppStateStore.shared.connectionMode == .local {

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import OSLog

View File

@@ -24,7 +24,7 @@ actor DiagnosticsFileLog {
?? FileManager().homeDirectoryForCurrentUser.appendingPathComponent("Library", isDirectory: true)
return library
.appendingPathComponent("Logs", isDirectory: true)
.appendingPathComponent("Clawdbot", isDirectory: true)
.appendingPathComponent("Moltbot", isDirectory: true)
}
nonisolated static func logFileURL() -> URL {

View File

@@ -197,11 +197,11 @@ enum ExecApprovalsStore {
private static let defaultAutoAllowSkills = false
static func fileURL() -> URL {
ClawdbotPaths.stateDirURL.appendingPathComponent("exec-approvals.json")
MoltbotPaths.stateDirURL.appendingPathComponent("exec-approvals.json")
}
static func socketPath() -> String {
ClawdbotPaths.stateDirURL.appendingPathComponent("exec-approvals.sock").path
MoltbotPaths.stateDirURL.appendingPathComponent("exec-approvals.sock").path
}
static func normalizeIncoming(_ file: ExecApprovalsFile) -> ExecApprovalsFile {

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import CoreGraphics
import Foundation
import OSLog

View File

@@ -1,5 +1,5 @@
import AppKit
import ClawdbotKit
import MoltbotKit
import CryptoKit
import Darwin
import Foundation

View File

@@ -1,6 +1,6 @@
import ClawdbotChatUI
import ClawdbotKit
import ClawdbotProtocol
import MoltbotChatUI
import MoltbotKit
import MoltbotProtocol
import Foundation
import OSLog
@@ -272,7 +272,7 @@ actor GatewayConnection {
return trimmed.isEmpty ? nil : trimmed
}
private func sessionDefaultString(_ defaults: [String: ClawdbotProtocol.AnyCodable]?, key: String) -> String {
private func sessionDefaultString(_ defaults: [String: MoltbotProtocol.AnyCodable]?, key: String) -> String {
let raw = defaults?[key]?.value as? String
return (raw ?? "").trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
@@ -503,7 +503,7 @@ extension GatewayConnection {
func healthOK(timeoutMs: Int = 8000) async throws -> Bool {
let data = try await self.requestRaw(method: .health, timeoutMs: Double(timeoutMs))
return (try? self.decoder.decode(ClawdbotGatewayHealthOK.self, from: data))?.ok ?? true
return (try? self.decoder.decode(MoltbotGatewayHealthOK.self, from: data))?.ok ?? true
}
// MARK: - Skills
@@ -548,13 +548,13 @@ extension GatewayConnection {
keys: [String],
limit: Int? = nil,
maxChars: Int? = nil,
timeoutMs: Int? = nil) async throws -> ClawdbotSessionsPreviewPayload
timeoutMs: Int? = nil) async throws -> MoltbotSessionsPreviewPayload
{
let resolvedKeys = keys
.map { self.canonicalizeSessionKey($0) }
.filter { !$0.isEmpty }
if resolvedKeys.isEmpty {
return ClawdbotSessionsPreviewPayload(ts: 0, previews: [])
return MoltbotSessionsPreviewPayload(ts: 0, previews: [])
}
var params: [String: AnyCodable] = ["keys": AnyCodable(resolvedKeys)]
if let limit { params["limit"] = AnyCodable(limit) }
@@ -571,7 +571,7 @@ extension GatewayConnection {
func chatHistory(
sessionKey: String,
limit: Int? = nil,
timeoutMs: Int? = nil) async throws -> ClawdbotChatHistoryPayload
timeoutMs: Int? = nil) async throws -> MoltbotChatHistoryPayload
{
let resolvedKey = self.canonicalizeSessionKey(sessionKey)
var params: [String: AnyCodable] = ["sessionKey": AnyCodable(resolvedKey)]
@@ -588,8 +588,8 @@ extension GatewayConnection {
message: String,
thinking: String,
idempotencyKey: String,
attachments: [ClawdbotChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> ClawdbotChatSendResponse
attachments: [MoltbotChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> MoltbotChatSendResponse
{
let resolvedKey = self.canonicalizeSessionKey(sessionKey)
var params: [String: AnyCodable] = [

View File

@@ -1,4 +1,4 @@
import ClawdbotDiscovery
import MoltbotDiscovery
import Foundation
enum GatewayDiscoveryHelpers {

View File

@@ -1,4 +1,4 @@
import ClawdbotDiscovery
import MoltbotDiscovery
import SwiftUI
struct GatewayDiscoveryInlineList: View {
@@ -134,6 +134,6 @@ struct GatewayDiscoveryMenu: View {
} label: {
Image(systemName: "dot.radiowaves.left.and.right")
}
.help("Discover Clawdbot gateways on your LAN")
.help("Discover Moltbot gateways on your LAN")
}
}

View File

@@ -43,7 +43,7 @@ actor GatewayEndpointStore {
static let live = Deps(
mode: { await MainActor.run { AppStateStore.shared.connectionMode } },
token: {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
let isRemote = ConnectionModeResolver.resolve(root: root).mode == .remote
return GatewayEndpointStore.resolveGatewayToken(
isRemote: isRemote,
@@ -52,7 +52,7 @@ actor GatewayEndpointStore {
launchdSnapshot: GatewayLaunchAgentManager.launchdConfigSnapshot())
},
password: {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
let isRemote = ConnectionModeResolver.resolve(root: root).mode == .remote
return GatewayEndpointStore.resolveGatewayPassword(
isRemote: isRemote,
@@ -62,7 +62,7 @@ actor GatewayEndpointStore {
},
localPort: { GatewayEnvironment.gatewayPort() },
localHost: {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: root,
env: ProcessInfo.processInfo.environment)
@@ -243,17 +243,17 @@ actor GatewayEndpointStore {
if let modeRaw {
initialMode = AppState.ConnectionMode(rawValue: modeRaw) ?? .local
} else {
let seen = UserDefaults.standard.bool(forKey: "clawdbot.onboardingSeen")
let seen = UserDefaults.standard.bool(forKey: "moltbot.onboardingSeen")
initialMode = seen ? .local : .unconfigured
}
let port = deps.localPort()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: ClawdbotConfigFile.loadDict(),
root: MoltbotConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let customBindHost = GatewayEndpointStore.resolveGatewayCustomBindHost(root: ClawdbotConfigFile.loadDict())
let customBindHost = GatewayEndpointStore.resolveGatewayCustomBindHost(root: MoltbotConfigFile.loadDict())
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: ClawdbotConfigFile.loadDict(),
root: MoltbotConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let host = GatewayEndpointStore.resolveLocalGatewayHost(
bindMode: bind,
@@ -303,7 +303,7 @@ actor GatewayEndpointStore {
let port = self.deps.localPort()
let host = await self.deps.localHost()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: ClawdbotConfigFile.loadDict(),
root: MoltbotConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
self.setState(.ready(
mode: .local,
@@ -311,7 +311,7 @@ actor GatewayEndpointStore {
token: token,
password: password))
case .remote:
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
self.cancelRemoteEnsure()
@@ -332,7 +332,7 @@ actor GatewayEndpointStore {
}
self.cancelRemoteEnsure()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: ClawdbotConfigFile.loadDict(),
root: MoltbotConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
self.setState(.ready(
mode: .remote,
@@ -354,7 +354,7 @@ actor GatewayEndpointStore {
code: 1,
userInfo: [NSLocalizedDescriptionKey: "Remote mode is not enabled"])
}
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
throw NSError(
@@ -433,7 +433,7 @@ actor GatewayEndpointStore {
userInfo: [NSLocalizedDescriptionKey: "Remote mode is not enabled"])
}
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
throw NSError(
@@ -470,7 +470,7 @@ actor GatewayEndpointStore {
let token = self.deps.token()
let password = self.deps.password()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: ClawdbotConfigFile.loadDict(),
root: MoltbotConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let url = URL(string: "\(scheme)://127.0.0.1:\(Int(forwarded))")!
self.setState(.ready(mode: .remote, url: url, token: token, password: password))
@@ -525,7 +525,7 @@ actor GatewayEndpointStore {
let mode = await self.deps.mode()
guard mode == .local else { return nil }
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: root,
env: ProcessInfo.processInfo.environment)

View File

@@ -1,4 +1,4 @@
import ClawdbotIPC
import MoltbotIPC
import Foundation
import OSLog
@@ -76,7 +76,7 @@ enum GatewayEnvironment {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if let parsed = Int(trimmed), parsed > 0 { return parsed }
}
if let configPort = ClawdbotConfigFile.gatewayPort(), configPort > 0 {
if let configPort = MoltbotConfigFile.gatewayPort(), configPort > 0 {
return configPort
}
let stored = UserDefaults.standard.integer(forKey: "gatewayPort")
@@ -131,7 +131,7 @@ enum GatewayEnvironment {
nodeVersion: runtime.version.description,
gatewayVersion: nil,
requiredGateway: expectedString,
message: "clawdbot CLI not found in PATH; install the CLI.")
message: "moltbot CLI not found in PATH; install the CLI.")
}
let installed = gatewayBin.flatMap { self.readGatewayVersion(binary: $0) }
@@ -217,7 +217,7 @@ enum GatewayEnvironment {
}
}
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
if let gateway = root["gateway"] as? [String: Any],
let bind = gateway["bind"] as? String
{
@@ -247,16 +247,16 @@ enum GatewayEnvironment {
let bun = CommandResolver.findExecutable(named: "bun")
let (label, cmd): (String, [String]) =
if let npm {
("npm", [npm, "install", "-g", "clawdbot@\(target)"])
("npm", [npm, "install", "-g", "moltbot@\(target)"])
} else if let pnpm {
("pnpm", [pnpm, "add", "-g", "clawdbot@\(target)"])
("pnpm", [pnpm, "add", "-g", "moltbot@\(target)"])
} else if let bun {
("bun", [bun, "add", "-g", "clawdbot@\(target)"])
("bun", [bun, "add", "-g", "moltbot@\(target)"])
} else {
("npm", ["npm", "install", "-g", "clawdbot@\(target)"])
("npm", ["npm", "install", "-g", "moltbot@\(target)"])
}
statusHandler("Installing clawdbot@\(target) via \(label)")
statusHandler("Installing moltbot@\(target) via \(label)")
func summarize(_ text: String) -> String? {
let lines = text
@@ -270,7 +270,7 @@ enum GatewayEnvironment {
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: ["PATH": preferred], timeout: 300)
if response.success {
statusHandler("Installed clawdbot@\(target)")
statusHandler("Installed moltbot@\(target)")
} else {
if response.timedOut {
statusHandler("Install failed: timed out. Check your internet connection and try again.")

View File

@@ -1,7 +1,7 @@
import AppKit
import ClawdbotDiscovery
import ClawdbotIPC
import ClawdbotKit
import MoltbotDiscovery
import MoltbotIPC
import MoltbotKit
import Observation
import SwiftUI
@@ -24,8 +24,8 @@ struct GeneralSettings: View {
VStack(alignment: .leading, spacing: 18) {
VStack(alignment: .leading, spacing: 12) {
SettingsToggleRow(
title: "Clawdbot active",
subtitle: "Pause to stop the Clawdbot gateway; no messages will be processed.",
title: "Moltbot active",
subtitle: "Pause to stop the Moltbot gateway; no messages will be processed.",
binding: self.activeBinding)
self.connectionSection
@@ -34,12 +34,12 @@ struct GeneralSettings: View {
SettingsToggleRow(
title: "Launch at login",
subtitle: "Automatically start Clawdbot after you sign in.",
subtitle: "Automatically start Moltbot after you sign in.",
binding: self.$state.launchAtLogin)
SettingsToggleRow(
title: "Show Dock icon",
subtitle: "Keep Clawdbot visible in the Dock instead of menu-bar-only mode.",
subtitle: "Keep Moltbot visible in the Dock instead of menu-bar-only mode.",
binding: self.$state.showDockIcon)
SettingsToggleRow(
@@ -71,7 +71,7 @@ struct GeneralSettings: View {
Spacer(minLength: 12)
HStack {
Spacer()
Button("Quit Clawdbot") { NSApp.terminate(nil) }
Button("Quit Moltbot") { NSApp.terminate(nil) }
.buttonStyle(.borderedProminent)
}
}
@@ -98,7 +98,7 @@ struct GeneralSettings: View {
private var connectionSection: some View {
VStack(alignment: .leading, spacing: 10) {
Text("Clawdbot runs")
Text("Moltbot runs")
.font(.title3.weight(.semibold))
.frame(maxWidth: .infinity, alignment: .leading)
@@ -167,12 +167,12 @@ struct GeneralSettings: View {
.frame(width: 280)
}
LabeledContent("Project root") {
TextField("/home/you/Projects/clawdbot", text: self.$state.remoteProjectRoot)
TextField("/home/you/Projects/moltbot", text: self.$state.remoteProjectRoot)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
LabeledContent("CLI path") {
TextField("/Applications/Clawdbot.app/.../clawdbot", text: self.$state.remoteCliPath)
TextField("/Applications/Moltbot.app/.../moltbot", text: self.$state.remoteCliPath)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
@@ -659,7 +659,7 @@ extension GeneralSettings {
let alert = NSAlert()
alert.messageText = "Log file not found"
alert.informativeText = """
Looked for clawdbot logs in /tmp/clawdbot/.
Looked for moltbot logs in /tmp/moltbot/.
Run a health check or send a message to generate activity, then try again.
"""
alert.alertStyle = .informational
@@ -683,7 +683,7 @@ extension GeneralSettings {
host: host,
port: gateway.sshPort)
self.state.remoteCliPath = gateway.cliPath ?? ""
ClawdbotConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
MoltbotConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
}
}
}
@@ -711,8 +711,8 @@ extension GeneralSettings {
state.remoteTarget = "user@host:2222"
state.remoteUrl = "wss://gateway.example.ts.net"
state.remoteIdentity = "/tmp/id_ed25519"
state.remoteProjectRoot = "/tmp/clawdbot"
state.remoteCliPath = "/tmp/clawdbot"
state.remoteProjectRoot = "/tmp/moltbot"
state.remoteCliPath = "/tmp/moltbot"
let view = GeneralSettings(state: state)
view.gatewayStatus = GatewayEnvironmentStatus(

View File

@@ -221,9 +221,9 @@ final class HealthStore {
if let fallback = self.resolveFallbackChannel(snap, excluding: link.id) {
let fallbackLabel = snap.channelLabels?[fallback.id] ?? fallback.id.capitalized
let fallbackState = (fallback.summary.probe?.ok ?? true) ? "ok" : "degraded"
return "\(fallbackLabel) \(fallbackState) · Not linked — run clawdbot login"
return "\(fallbackLabel) \(fallbackState) · Not linked — run moltbot login"
}
return "Not linked — run clawdbot login"
return "Not linked — run moltbot login"
}
let auth = link.summary.authAgeMs.map { msToAge($0) } ?? "unknown"
if let probe = link.summary.probe, probe.ok == false {
@@ -241,7 +241,7 @@ final class HealthStore {
if lower.contains("connection refused") {
let port = GatewayEnvironment.gatewayPort()
let host = GatewayConnectivityCoordinator.shared.localEndpointHostLabel ?? "127.0.0.1:\(port)"
return "The gateway control port (\(host)) isnt listening — restart Clawdbot to bring it back."
return "The gateway control port (\(host)) isnt listening — restart Moltbot to bring it back."
}
if lower.contains("timeout") {
return "Timed out waiting for the control server; the gateway may be crashed or still starting."
@@ -253,7 +253,7 @@ final class HealthStore {
func describeFailure(from snap: HealthSnapshot, fallback: String?) -> String {
if let link = self.resolveLinkChannel(snap), link.summary.linked != true {
return "Not linked — run clawdbot login"
return "Not linked — run moltbot login"
}
if let link = self.resolveLinkChannel(snap), let probe = link.summary.probe, probe.ok == false {
return Self.describeProbeFailure(probe)

View File

@@ -38,7 +38,7 @@ struct InstancesSettings: View {
VStack(alignment: .leading, spacing: 4) {
Text("Connected Instances")
.font(.headline)
Text("Latest presence beacons from Clawdbot nodes. Updated periodically.")
Text("Latest presence beacons from Moltbot nodes. Updated periodically.")
.font(.footnote)
.foregroundStyle(.secondary)
}

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Cocoa
import Foundation
import Observation
@@ -293,7 +293,7 @@ final class InstancesStore {
}
}
func handlePresenceEventPayload(_ payload: ClawdbotProtocol.AnyCodable) {
func handlePresenceEventPayload(_ payload: MoltbotProtocol.AnyCodable) {
do {
let wrapper = try GatewayPayloadDecoding.decode(payload, as: PresenceEventPayload.self)
self.applyPresence(wrapper.presence)

View File

@@ -43,7 +43,7 @@ enum LaunchAgentManager {
<string>com.clawdbot.mac</string>
<key>ProgramArguments</key>
<array>
<string>\(bundlePath)/Contents/MacOS/Clawdbot</string>
<string>\(bundlePath)/Contents/MacOS/Moltbot</string>
</array>
<key>WorkingDirectory</key>
<string>\(FileManager().homeDirectoryForCurrentUser.path)</string>

View File

@@ -8,12 +8,12 @@ enum LaunchdManager {
try? process.run()
}
static func startClawdbot() {
static func startMoltbot() {
let userTarget = "gui/\(getuid())/\(launchdLabel)"
self.runLaunchctl(["kickstart", "-k", userTarget])
}
static func stopClawdbot() {
static func stopMoltbot() {
let userTarget = "gui/\(getuid())/\(launchdLabel)"
self.runLaunchctl(["stop", userTarget])
}

View File

@@ -6,15 +6,15 @@ enum LogLocator {
return URL(fileURLWithPath: override)
}
return URL(fileURLWithPath: "/tmp/clawdbot")
return URL(fileURLWithPath: "/tmp/moltbot")
}
private static var stdoutLog: URL {
logDir.appendingPathComponent("clawdbot-stdout.log")
logDir.appendingPathComponent("moltbot-stdout.log")
}
private static var gatewayLog: URL {
logDir.appendingPathComponent("clawdbot-gateway.log")
logDir.appendingPathComponent("moltbot-gateway.log")
}
private static func ensureLogDirExists() {
@@ -25,7 +25,7 @@ enum LogLocator {
(try? url.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? .distantPast
}
/// Returns the newest log file under /tmp/clawdbot/ (rolling or stdout), or nil if none exist.
/// Returns the newest log file under /tmp/moltbot/ (rolling or stdout), or nil if none exist.
static func bestLogFile() -> URL? {
self.ensureLogDirExists()
let fm = FileManager()
@@ -35,7 +35,7 @@ enum LogLocator {
options: [.skipsHiddenFiles])) ?? []
return files
.filter { $0.lastPathComponent.hasPrefix("clawdbot") && $0.pathExtension == "log" }
.filter { $0.lastPathComponent.hasPrefix("moltbot") && $0.pathExtension == "log" }
.max { lhs, rhs in
self.modificationDate(for: lhs) < self.modificationDate(for: rhs)
}

View File

@@ -52,14 +52,14 @@ enum AppLogLevel: String, CaseIterable, Identifiable {
}
}
enum ClawdbotLogging {
enum MoltbotLogging {
private static let labelSeparator = "::"
private static let didBootstrap: Void = {
LoggingSystem.bootstrap { label in
let (subsystem, category) = Self.parseLabel(label)
let osHandler = ClawdbotOSLogHandler(subsystem: subsystem, category: category)
let fileHandler = ClawdbotFileLogHandler(label: label)
let osHandler = MoltbotOSLogHandler(subsystem: subsystem, category: category)
let fileHandler = MoltbotFileLogHandler(label: label)
return MultiplexLogHandler([osHandler, fileHandler])
}
}()
@@ -84,8 +84,8 @@ enum ClawdbotLogging {
extension Logging.Logger {
init(subsystem: String, category: String) {
ClawdbotLogging.bootstrapIfNeeded()
let label = ClawdbotLogging.makeLabel(subsystem: subsystem, category: category)
MoltbotLogging.bootstrapIfNeeded()
let label = MoltbotLogging.makeLabel(subsystem: subsystem, category: category)
self.init(label: label)
}
}
@@ -96,7 +96,7 @@ extension Logger.Message.StringInterpolation {
}
}
struct ClawdbotOSLogHandler: LogHandler {
struct MoltbotOSLogHandler: LogHandler {
private let osLogger: os.Logger
var metadata: Logger.Metadata = [:]
@@ -174,7 +174,7 @@ struct ClawdbotOSLogHandler: LogHandler {
}
}
struct ClawdbotFileLogHandler: LogHandler {
struct MoltbotFileLogHandler: LogHandler {
let label: String
var metadata: Logger.Metadata = [:]
@@ -198,7 +198,7 @@ struct ClawdbotFileLogHandler: LogHandler {
line: UInt)
{
guard AppLogSettings.fileLoggingEnabled() else { return }
let (subsystem, category) = ClawdbotLogging.parseLabel(self.label)
let (subsystem, category) = MoltbotLogging.parseLabel(self.label)
var fields: [String: String] = [
"subsystem": subsystem,
"category": category,

View File

@@ -8,7 +8,7 @@ import Security
import SwiftUI
@main
struct ClawdbotApp: App {
struct MoltbotApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var delegate
@State private var state: AppState
private static let logger = Logger(subsystem: "com.clawdbot", category: "app")
@@ -32,7 +32,7 @@ struct ClawdbotApp: App {
}
init() {
ClawdbotLogging.bootstrapIfNeeded()
MoltbotLogging.bootstrapIfNeeded()
Self.applyAttachOnlyOverrideIfNeeded()
_state = State(initialValue: AppStateStore.shared)
}

View File

@@ -4,7 +4,7 @@ import Foundation
import Observation
import SwiftUI
/// Menu contents for the Clawdbot menu bar extra.
/// Menu contents for the Moltbot menu bar extra.
struct MenuContent: View {
@Bindable var state: AppState
let updater: UpdaterProviding?
@@ -149,7 +149,7 @@ struct MenuContent: View {
Button("Settings…") { self.open(tab: .general) }
.keyboardShortcut(",", modifiers: [.command])
self.debugMenu
Button("About Clawdbot") { self.open(tab: .about) }
Button("About Moltbot") { self.open(tab: .about) }
if let updater, updater.isAvailable, self.updateStatus.isUpdateReady {
Button("Update ready, restart now?") { updater.checkForUpdates(nil) }
}
@@ -185,11 +185,11 @@ struct MenuContent: View {
private var connectionLabel: String {
switch self.state.connectionMode {
case .unconfigured:
"Clawdbot Not Configured"
"Moltbot Not Configured"
case .remote:
"Remote Clawdbot Active"
"Remote Moltbot Active"
case .local:
"Clawdbot Active"
"Moltbot Active"
}
}

View File

@@ -6,7 +6,7 @@ enum ModelCatalogLoader {
private static let logger = Logger(subsystem: "com.clawdbot", category: "models")
private nonisolated static let appSupportDir: URL = {
let base = FileManager().urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return base.appendingPathComponent("Clawdbot", isDirectory: true)
return base.appendingPathComponent("Moltbot", isDirectory: true)
}()
private static var cachePath: URL {

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import CoreLocation
import Foundation
@@ -30,7 +30,7 @@ final class MacNodeLocationService: NSObject, CLLocationManagerDelegate {
}
func currentLocation(
desiredAccuracy: ClawdbotLocationAccuracy,
desiredAccuracy: MoltbotLocationAccuracy,
maxAgeMs: Int?,
timeoutMs: Int?) async throws -> CLLocation
{
@@ -103,7 +103,7 @@ final class MacNodeLocationService: NSObject, CLLocationManagerDelegate {
}
}
private static func accuracyValue(_ accuracy: ClawdbotLocationAccuracy) -> CLLocationAccuracy {
private static func accuracyValue(_ accuracy: MoltbotLocationAccuracy) -> CLLocationAccuracy {
switch accuracy {
case .coarse:
kCLLocationAccuracyKilometer

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import OSLog
@@ -60,7 +60,7 @@ final class MacNodeModeCoordinator {
caps: caps,
commands: commands,
permissions: permissions,
clientId: "clawdbot-macos",
clientId: "moltbot-macos",
clientMode: "node",
clientDisplayName: InstanceIdentity.displayName)
let sessionBox = self.buildSessionBox(url: config.url)
@@ -91,7 +91,7 @@ final class MacNodeModeCoordinator {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(code: .unavailable, message: "UNAVAILABLE: node not ready"))
error: MoltbotNodeError(code: .unavailable, message: "UNAVAILABLE: node not ready"))
}
return await self.runtime.handleInvoke(req)
})
@@ -107,13 +107,13 @@ final class MacNodeModeCoordinator {
}
private func currentCaps() -> [String] {
var caps: [String] = [ClawdbotCapability.canvas.rawValue, ClawdbotCapability.screen.rawValue]
var caps: [String] = [MoltbotCapability.canvas.rawValue, MoltbotCapability.screen.rawValue]
if UserDefaults.standard.object(forKey: cameraEnabledKey) as? Bool ?? false {
caps.append(ClawdbotCapability.camera.rawValue)
caps.append(MoltbotCapability.camera.rawValue)
}
let rawLocationMode = UserDefaults.standard.string(forKey: locationModeKey) ?? "off"
if ClawdbotLocationMode(rawValue: rawLocationMode) != .off {
caps.append(ClawdbotCapability.location.rawValue)
if MoltbotLocationMode(rawValue: rawLocationMode) != .off {
caps.append(MoltbotCapability.location.rawValue)
}
return caps
}
@@ -125,30 +125,30 @@ final class MacNodeModeCoordinator {
private func currentCommands(caps: [String]) -> [String] {
var commands: [String] = [
ClawdbotCanvasCommand.present.rawValue,
ClawdbotCanvasCommand.hide.rawValue,
ClawdbotCanvasCommand.navigate.rawValue,
ClawdbotCanvasCommand.evalJS.rawValue,
ClawdbotCanvasCommand.snapshot.rawValue,
ClawdbotCanvasA2UICommand.push.rawValue,
ClawdbotCanvasA2UICommand.pushJSONL.rawValue,
ClawdbotCanvasA2UICommand.reset.rawValue,
MoltbotCanvasCommand.present.rawValue,
MoltbotCanvasCommand.hide.rawValue,
MoltbotCanvasCommand.navigate.rawValue,
MoltbotCanvasCommand.evalJS.rawValue,
MoltbotCanvasCommand.snapshot.rawValue,
MoltbotCanvasA2UICommand.push.rawValue,
MoltbotCanvasA2UICommand.pushJSONL.rawValue,
MoltbotCanvasA2UICommand.reset.rawValue,
MacNodeScreenCommand.record.rawValue,
ClawdbotSystemCommand.notify.rawValue,
ClawdbotSystemCommand.which.rawValue,
ClawdbotSystemCommand.run.rawValue,
ClawdbotSystemCommand.execApprovalsGet.rawValue,
ClawdbotSystemCommand.execApprovalsSet.rawValue,
MoltbotSystemCommand.notify.rawValue,
MoltbotSystemCommand.which.rawValue,
MoltbotSystemCommand.run.rawValue,
MoltbotSystemCommand.execApprovalsGet.rawValue,
MoltbotSystemCommand.execApprovalsSet.rawValue,
]
let capsSet = Set(caps)
if capsSet.contains(ClawdbotCapability.camera.rawValue) {
commands.append(ClawdbotCameraCommand.list.rawValue)
commands.append(ClawdbotCameraCommand.snap.rawValue)
commands.append(ClawdbotCameraCommand.clip.rawValue)
if capsSet.contains(MoltbotCapability.camera.rawValue) {
commands.append(MoltbotCameraCommand.list.rawValue)
commands.append(MoltbotCameraCommand.snap.rawValue)
commands.append(MoltbotCameraCommand.clip.rawValue)
}
if capsSet.contains(ClawdbotCapability.location.rawValue) {
commands.append(ClawdbotLocationCommand.get.rawValue)
if capsSet.contains(MoltbotCapability.location.rawValue) {
commands.append(MoltbotLocationCommand.get.rawValue)
}
return commands

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import Foundation
actor MacNodeRuntime {
@@ -34,39 +34,39 @@ actor MacNodeRuntime {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "CANVAS_DISABLED: enable Canvas in Settings"))
}
do {
switch command {
case ClawdbotCanvasCommand.present.rawValue,
ClawdbotCanvasCommand.hide.rawValue,
ClawdbotCanvasCommand.navigate.rawValue,
ClawdbotCanvasCommand.evalJS.rawValue,
ClawdbotCanvasCommand.snapshot.rawValue:
case MoltbotCanvasCommand.present.rawValue,
MoltbotCanvasCommand.hide.rawValue,
MoltbotCanvasCommand.navigate.rawValue,
MoltbotCanvasCommand.evalJS.rawValue,
MoltbotCanvasCommand.snapshot.rawValue:
return try await self.handleCanvasInvoke(req)
case ClawdbotCanvasA2UICommand.reset.rawValue,
ClawdbotCanvasA2UICommand.push.rawValue,
ClawdbotCanvasA2UICommand.pushJSONL.rawValue:
case MoltbotCanvasA2UICommand.reset.rawValue,
MoltbotCanvasA2UICommand.push.rawValue,
MoltbotCanvasA2UICommand.pushJSONL.rawValue:
return try await self.handleA2UIInvoke(req)
case ClawdbotCameraCommand.snap.rawValue,
ClawdbotCameraCommand.clip.rawValue,
ClawdbotCameraCommand.list.rawValue:
case MoltbotCameraCommand.snap.rawValue,
MoltbotCameraCommand.clip.rawValue,
MoltbotCameraCommand.list.rawValue:
return try await self.handleCameraInvoke(req)
case ClawdbotLocationCommand.get.rawValue:
case MoltbotLocationCommand.get.rawValue:
return try await self.handleLocationInvoke(req)
case MacNodeScreenCommand.record.rawValue:
return try await self.handleScreenRecordInvoke(req)
case ClawdbotSystemCommand.run.rawValue:
case MoltbotSystemCommand.run.rawValue:
return try await self.handleSystemRun(req)
case ClawdbotSystemCommand.which.rawValue:
case MoltbotSystemCommand.which.rawValue:
return try await self.handleSystemWhich(req)
case ClawdbotSystemCommand.notify.rawValue:
case MoltbotSystemCommand.notify.rawValue:
return try await self.handleSystemNotify(req)
case ClawdbotSystemCommand.execApprovalsGet.rawValue:
case MoltbotSystemCommand.execApprovalsGet.rawValue:
return try await self.handleSystemExecApprovalsGet(req)
case ClawdbotSystemCommand.execApprovalsSet.rawValue:
case MoltbotSystemCommand.execApprovalsSet.rawValue:
return try await self.handleSystemExecApprovalsSet(req)
default:
return Self.errorResponse(req, code: .invalidRequest, message: "INVALID_REQUEST: unknown command")
@@ -82,9 +82,9 @@ actor MacNodeRuntime {
private func handleCanvasInvoke(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
switch req.command {
case ClawdbotCanvasCommand.present.rawValue:
let params = (try? Self.decodeParams(ClawdbotCanvasPresentParams.self, from: req.paramsJSON)) ??
ClawdbotCanvasPresentParams()
case MoltbotCanvasCommand.present.rawValue:
let params = (try? Self.decodeParams(MoltbotCanvasPresentParams.self, from: req.paramsJSON)) ??
MoltbotCanvasPresentParams()
let urlTrimmed = params.url?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let url = urlTrimmed.isEmpty ? nil : urlTrimmed
let placement = params.placement.map {
@@ -98,29 +98,29 @@ actor MacNodeRuntime {
placement: placement)
}
return BridgeInvokeResponse(id: req.id, ok: true)
case ClawdbotCanvasCommand.hide.rawValue:
case MoltbotCanvasCommand.hide.rawValue:
let sessionKey = self.mainSessionKey
await MainActor.run {
CanvasManager.shared.hide(sessionKey: sessionKey)
}
return BridgeInvokeResponse(id: req.id, ok: true)
case ClawdbotCanvasCommand.navigate.rawValue:
let params = try Self.decodeParams(ClawdbotCanvasNavigateParams.self, from: req.paramsJSON)
case MoltbotCanvasCommand.navigate.rawValue:
let params = try Self.decodeParams(MoltbotCanvasNavigateParams.self, from: req.paramsJSON)
let sessionKey = self.mainSessionKey
try await MainActor.run {
_ = try CanvasManager.shared.show(sessionKey: sessionKey, path: params.url)
}
return BridgeInvokeResponse(id: req.id, ok: true)
case ClawdbotCanvasCommand.evalJS.rawValue:
let params = try Self.decodeParams(ClawdbotCanvasEvalParams.self, from: req.paramsJSON)
case MoltbotCanvasCommand.evalJS.rawValue:
let params = try Self.decodeParams(MoltbotCanvasEvalParams.self, from: req.paramsJSON)
let sessionKey = self.mainSessionKey
let result = try await CanvasManager.shared.eval(
sessionKey: sessionKey,
javaScript: params.javaScript)
let payload = try Self.encodePayload(["result": result] as [String: String])
return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload)
case ClawdbotCanvasCommand.snapshot.rawValue:
let params = try? Self.decodeParams(ClawdbotCanvasSnapshotParams.self, from: req.paramsJSON)
case MoltbotCanvasCommand.snapshot.rawValue:
let params = try? Self.decodeParams(MoltbotCanvasSnapshotParams.self, from: req.paramsJSON)
let format = params?.format ?? .jpeg
let maxWidth: Int? = {
if let raw = params?.maxWidth, raw > 0 { return raw }
@@ -155,10 +155,10 @@ actor MacNodeRuntime {
private func handleA2UIInvoke(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
switch req.command {
case ClawdbotCanvasA2UICommand.reset.rawValue:
case MoltbotCanvasA2UICommand.reset.rawValue:
try await self.handleA2UIReset(req)
case ClawdbotCanvasA2UICommand.push.rawValue,
ClawdbotCanvasA2UICommand.pushJSONL.rawValue:
case MoltbotCanvasA2UICommand.push.rawValue,
MoltbotCanvasA2UICommand.pushJSONL.rawValue:
try await self.handleA2UIPush(req)
default:
Self.errorResponse(req, code: .invalidRequest, message: "INVALID_REQUEST: unknown command")
@@ -170,14 +170,14 @@ actor MacNodeRuntime {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "CAMERA_DISABLED: enable Camera in Settings"))
}
switch req.command {
case ClawdbotCameraCommand.snap.rawValue:
let params = (try? Self.decodeParams(ClawdbotCameraSnapParams.self, from: req.paramsJSON)) ??
ClawdbotCameraSnapParams()
case MoltbotCameraCommand.snap.rawValue:
let params = (try? Self.decodeParams(MoltbotCameraSnapParams.self, from: req.paramsJSON)) ??
MoltbotCameraSnapParams()
let delayMs = min(10000, max(0, params.delayMs ?? 2000))
let res = try await self.cameraCapture.snap(
facing: CameraFacing(rawValue: params.facing?.rawValue ?? "") ?? .front,
@@ -197,9 +197,9 @@ actor MacNodeRuntime {
width: Int(res.size.width),
height: Int(res.size.height)))
return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload)
case ClawdbotCameraCommand.clip.rawValue:
let params = (try? Self.decodeParams(ClawdbotCameraClipParams.self, from: req.paramsJSON)) ??
ClawdbotCameraClipParams()
case MoltbotCameraCommand.clip.rawValue:
let params = (try? Self.decodeParams(MoltbotCameraClipParams.self, from: req.paramsJSON)) ??
MoltbotCameraClipParams()
let res = try await self.cameraCapture.clip(
facing: CameraFacing(rawValue: params.facing?.rawValue ?? "") ?? .front,
durationMs: params.durationMs,
@@ -220,7 +220,7 @@ actor MacNodeRuntime {
durationMs: res.durationMs,
hasAudio: res.hasAudio))
return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload)
case ClawdbotCameraCommand.list.rawValue:
case MoltbotCameraCommand.list.rawValue:
let devices = await self.cameraCapture.listDevices()
let payload = try Self.encodePayload(["devices": devices])
return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload)
@@ -235,12 +235,12 @@ actor MacNodeRuntime {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "LOCATION_DISABLED: enable Location in Settings"))
}
let params = (try? Self.decodeParams(ClawdbotLocationGetParams.self, from: req.paramsJSON)) ??
ClawdbotLocationGetParams()
let params = (try? Self.decodeParams(MoltbotLocationGetParams.self, from: req.paramsJSON)) ??
MoltbotLocationGetParams()
let desired = params.desiredAccuracy ??
(Self.locationPreciseEnabled() ? .precise : .balanced)
let services = await self.mainActorServices()
@@ -257,7 +257,7 @@ actor MacNodeRuntime {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "LOCATION_PERMISSION_REQUIRED: grant Location permission"))
}
@@ -267,7 +267,7 @@ actor MacNodeRuntime {
maxAgeMs: params.maxAgeMs,
timeoutMs: params.timeoutMs)
let isPrecise = await services.locationAccuracyAuthorization() == .fullAccuracy
let payload = ClawdbotLocationPayload(
let payload = MoltbotLocationPayload(
lat: location.coordinate.latitude,
lon: location.coordinate.longitude,
accuracyMeters: location.horizontalAccuracy,
@@ -283,14 +283,14 @@ actor MacNodeRuntime {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "LOCATION_TIMEOUT: no fix in time"))
} catch {
return BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(
error: MoltbotNodeError(
code: .unavailable,
message: "LOCATION_UNAVAILABLE: \(error.localizedDescription)"))
}
@@ -345,7 +345,7 @@ actor MacNodeRuntime {
let sessionKey = self.mainSessionKey
let json = try await CanvasManager.shared.eval(sessionKey: sessionKey, javaScript: """
(() => {
if (!globalThis.clawdbotA2UI) return JSON.stringify({ ok: false, error: "missing clawdbotA2UI" });
if (!globalThis.clawdbotA2UI) return JSON.stringify({ ok: false, error: "missing moltbotA2UI" });
return JSON.stringify(globalThis.clawdbotA2UI.reset());
})()
""")
@@ -354,27 +354,27 @@ actor MacNodeRuntime {
private func handleA2UIPush(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
let command = req.command
let messages: [ClawdbotKit.AnyCodable]
if command == ClawdbotCanvasA2UICommand.pushJSONL.rawValue {
let params = try Self.decodeParams(ClawdbotCanvasA2UIPushJSONLParams.self, from: req.paramsJSON)
messages = try ClawdbotCanvasA2UIJSONL.decodeMessagesFromJSONL(params.jsonl)
let messages: [MoltbotKit.AnyCodable]
if command == MoltbotCanvasA2UICommand.pushJSONL.rawValue {
let params = try Self.decodeParams(MoltbotCanvasA2UIPushJSONLParams.self, from: req.paramsJSON)
messages = try MoltbotCanvasA2UIJSONL.decodeMessagesFromJSONL(params.jsonl)
} else {
do {
let params = try Self.decodeParams(ClawdbotCanvasA2UIPushParams.self, from: req.paramsJSON)
let params = try Self.decodeParams(MoltbotCanvasA2UIPushParams.self, from: req.paramsJSON)
messages = params.messages
} catch {
let params = try Self.decodeParams(ClawdbotCanvasA2UIPushJSONLParams.self, from: req.paramsJSON)
messages = try ClawdbotCanvasA2UIJSONL.decodeMessagesFromJSONL(params.jsonl)
let params = try Self.decodeParams(MoltbotCanvasA2UIPushJSONLParams.self, from: req.paramsJSON)
messages = try MoltbotCanvasA2UIJSONL.decodeMessagesFromJSONL(params.jsonl)
}
}
try await self.ensureA2UIHost()
let messagesJSON = try ClawdbotCanvasA2UIJSONL.encodeMessagesJSONArray(messages)
let messagesJSON = try MoltbotCanvasA2UIJSONL.encodeMessagesJSONArray(messages)
let js = """
(() => {
try {
if (!globalThis.clawdbotA2UI) return JSON.stringify({ ok: false, error: "missing clawdbotA2UI" });
if (!globalThis.clawdbotA2UI) return JSON.stringify({ ok: false, error: "missing moltbotA2UI" });
const messages = \(messagesJSON);
return JSON.stringify(globalThis.clawdbotA2UI.applyMessages(messages));
} catch (e) {
@@ -408,7 +408,7 @@ actor MacNodeRuntime {
guard let raw = await GatewayConnection.shared.canvasHostUrl() else { return nil }
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, let baseUrl = URL(string: trimmed) else { return nil }
return baseUrl.appendingPathComponent("__clawdbot__/a2ui/").absoluteString + "?platform=macos"
return baseUrl.appendingPathComponent("__moltbot__/a2ui/").absoluteString + "?platform=macos"
}
private func isA2UIReady(poll: Bool = false) async -> Bool {
@@ -431,7 +431,7 @@ actor MacNodeRuntime {
}
private func handleSystemRun(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
let params = try Self.decodeParams(ClawdbotSystemRunParams.self, from: req.paramsJSON)
let params = try Self.decodeParams(MoltbotSystemRunParams.self, from: req.paramsJSON)
let command = params.command
guard !command.isEmpty else {
return Self.errorResponse(req, code: .invalidRequest, message: "INVALID_REQUEST: command required")
@@ -593,7 +593,7 @@ actor MacNodeRuntime {
}
private func handleSystemWhich(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
let params = try Self.decodeParams(ClawdbotSystemWhichParams.self, from: req.paramsJSON)
let params = try Self.decodeParams(MoltbotSystemWhichParams.self, from: req.paramsJSON)
let bins = params.bins
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
@@ -639,7 +639,7 @@ actor MacNodeRuntime {
private func resolveSystemRunApproval(
req: BridgeInvokeRequest,
params: ClawdbotSystemRunParams,
params: MoltbotSystemRunParams,
context: ExecRunContext) async -> ExecApprovalOutcome
{
let requiresAsk = ExecApprovalHelpers.requiresAsk(
@@ -790,7 +790,7 @@ actor MacNodeRuntime {
}
private func handleSystemNotify(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
let params = try Self.decodeParams(ClawdbotSystemNotifyParams.self, from: req.paramsJSON)
let params = try Self.decodeParams(MoltbotSystemNotifyParams.self, from: req.paramsJSON)
let title = params.title.trimmingCharacters(in: .whitespacesAndNewlines)
let body = params.body.trimmingCharacters(in: .whitespacesAndNewlines)
if title.isEmpty, body.isEmpty {
@@ -886,9 +886,9 @@ extension MacNodeRuntime {
return merged
}
private nonisolated static func locationMode() -> ClawdbotLocationMode {
private nonisolated static func locationMode() -> MoltbotLocationMode {
let raw = UserDefaults.standard.string(forKey: locationModeKey) ?? "off"
return ClawdbotLocationMode(rawValue: raw) ?? .off
return MoltbotLocationMode(rawValue: raw) ?? .off
}
private nonisolated static func locationPreciseEnabled() -> Bool {
@@ -898,18 +898,18 @@ extension MacNodeRuntime {
private static func errorResponse(
_ req: BridgeInvokeRequest,
code: ClawdbotNodeErrorCode,
code: MoltbotNodeErrorCode,
message: String) -> BridgeInvokeResponse
{
BridgeInvokeResponse(
id: req.id,
ok: false,
error: ClawdbotNodeError(code: code, message: message))
error: MoltbotNodeError(code: code, message: message))
}
private static func encodeCanvasSnapshot(
image: NSImage,
format: ClawdbotCanvasSnapshotFormat,
format: MoltbotCanvasSnapshotFormat,
maxWidth: Int?,
quality: Double) throws -> Data
{

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import CoreLocation
import Foundation
@@ -14,7 +14,7 @@ protocol MacNodeRuntimeMainActorServices: Sendable {
func locationAuthorizationStatus() -> CLAuthorizationStatus
func locationAccuracyAuthorization() -> CLAccuracyAuthorization
func currentLocation(
desiredAccuracy: ClawdbotLocationAccuracy,
desiredAccuracy: MoltbotLocationAccuracy,
maxAgeMs: Int?,
timeoutMs: Int?) async throws -> CLLocation
}
@@ -48,7 +48,7 @@ final class LiveMacNodeRuntimeMainActorServices: MacNodeRuntimeMainActorServices
}
func currentLocation(
desiredAccuracy: ClawdbotLocationAccuracy,
desiredAccuracy: MoltbotLocationAccuracy,
maxAgeMs: Int?,
timeoutMs: Int?) async throws -> CLLocation
{

View File

@@ -1,8 +1,8 @@
import AppKit
import ClawdbotDiscovery
import ClawdbotIPC
import ClawdbotKit
import ClawdbotProtocol
import MoltbotDiscovery
import MoltbotIPC
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import OSLog

View File

@@ -1,4 +1,4 @@
import ClawdbotIPC
import MoltbotIPC
import Foundation
import Security
import UserNotifications

View File

@@ -1,13 +1,13 @@
import AppKit
import ClawdbotChatUI
import ClawdbotDiscovery
import ClawdbotIPC
import MoltbotChatUI
import MoltbotDiscovery
import MoltbotIPC
import Combine
import Observation
import SwiftUI
enum UIStrings {
static let welcomeTitle = "Welcome to Clawdbot"
static let welcomeTitle = "Welcome to Moltbot"
}
@MainActor
@@ -18,7 +18,7 @@ final class OnboardingController {
func show() {
if ProcessInfo.processInfo.isNixMode {
// Nix mode is fully declarative; onboarding would suggest interactive setup that doesn't apply.
UserDefaults.standard.set(true, forKey: "clawdbot.onboardingSeen")
UserDefaults.standard.set(true, forKey: "moltbot.onboardingSeen")
UserDefaults.standard.set(currentOnboardingVersion, forKey: onboardingVersionKey)
AppStateStore.shared.onboardingSeen = true
return
@@ -79,7 +79,7 @@ struct OnboardingView: View {
@State var anthropicAuthVerificationAttempted = false
@State var anthropicAuthVerificationFailed = false
@State var anthropicAuthVerifiedAt: Date?
@State var anthropicAuthDetectedStatus: ClawdbotOAuthStore.AnthropicOAuthStatus = .missingFile
@State var anthropicAuthDetectedStatus: MoltbotOAuthStore.AnthropicOAuthStatus = .missingFile
@State var anthropicAuthAutoDetectClipboard = true
@State var anthropicAuthAutoConnectClipboard = true
@State var anthropicAuthLastPasteboardChangeCount = NSPasteboard.general.changeCount
@@ -90,7 +90,7 @@ struct OnboardingView: View {
@State var showAdvancedConnection = false
@State var preferredGatewayID: String?
@State var gatewayDiscovery: GatewayDiscoveryModel
@State var onboardingChatModel: ClawdbotChatViewModel
@State var onboardingChatModel: MoltbotChatViewModel
@State var onboardingSkillsModel = SkillsSettingsModel()
@State var onboardingWizard = OnboardingWizardModel()
@State var didLoadOnboardingSkills = false
@@ -156,7 +156,7 @@ struct OnboardingView: View {
var canAdvance: Bool { !self.isWizardBlocking }
var devLinkCommand: String {
let version = GatewayEnvironment.expectedGatewayVersionString() ?? "latest"
return "npm install -g clawdbot@\(version)"
return "npm install -g moltbot@\(version)"
}
struct LocalGatewayProbe: Equatable {
@@ -177,7 +177,7 @@ struct OnboardingView: View {
self.permissionMonitor = permissionMonitor
self._gatewayDiscovery = State(initialValue: discoveryModel)
self._onboardingChatModel = State(
initialValue: ClawdbotChatViewModel(
initialValue: MoltbotChatViewModel(
sessionKey: "onboarding",
transport: MacGatewayChatTransport()))
}

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdbotDiscovery
import ClawdbotIPC
import MoltbotDiscovery
import MoltbotIPC
import Foundation
import SwiftUI
@@ -35,7 +35,7 @@ extension OnboardingView {
user: user,
host: host,
port: gateway.sshPort)
ClawdbotConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
MoltbotConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
}
self.state.remoteCliPath = gateway.cliPath ?? ""
@@ -67,7 +67,7 @@ extension OnboardingView {
}
func finish() {
UserDefaults.standard.set(true, forKey: "clawdbot.onboardingSeen")
UserDefaults.standard.set(true, forKey: "moltbot.onboardingSeen")
UserDefaults.standard.set(currentOnboardingVersion, forKey: onboardingVersionKey)
OnboardingController.shared.close()
}
@@ -113,9 +113,9 @@ extension OnboardingView {
code: parsed.code,
state: parsed.state,
verifier: pkce.verifier)
try ClawdbotOAuthStore.saveAnthropicOAuth(creds)
try MoltbotOAuthStore.saveAnthropicOAuth(creds)
self.refreshAnthropicOAuthStatus()
self.anthropicAuthStatus = "Connected. Clawdbot can now use Claude."
self.anthropicAuthStatus = "Connected. Moltbot can now use Claude."
} catch {
self.anthropicAuthStatus = "OAuth failed: \(error.localizedDescription)"
}

View File

@@ -14,7 +14,7 @@ extension OnboardingView {
}
guard self.onboardingChatModel.messages.isEmpty else { return }
let kickoff =
"Hi! I just installed Clawdbot and youre my brandnew agent. " +
"Hi! I just installed Moltbot and youre my brandnew agent. " +
"Please start the firstrun ritual from BOOTSTRAP.md, ask one question at a time, " +
"and before we talk about WhatsApp/Telegram, visit soul.md with me to craft SOUL.md: " +
"ask what matters to me and how you should be. Then guide me through choosing " +

View File

@@ -4,7 +4,7 @@ import SwiftUI
extension OnboardingView {
var body: some View {
VStack(spacing: 0) {
GlowingClawdbotIcon(size: 130, glowIntensity: 0.28)
GlowingMoltbotIcon(size: 130, glowIntensity: 0.28)
.offset(y: 10)
.frame(height: 145)

View File

@@ -1,4 +1,4 @@
import ClawdbotIPC
import MoltbotIPC
import Foundation
extension OnboardingView {
@@ -115,7 +115,7 @@ extension OnboardingView {
return
}
let command = desc.command.trimmingCharacters(in: .whitespacesAndNewlines)
let expectedTokens = ["node", "clawdbot", "tsx", "pnpm", "bun"]
let expectedTokens = ["node", "moltbot", "tsx", "pnpm", "bun"]
let lower = command.lowercased()
let expected = expectedTokens.contains { lower.contains($0) }
self.localGatewayProbe = LocalGatewayProbe(
@@ -127,9 +127,9 @@ extension OnboardingView {
}
func refreshAnthropicOAuthStatus() {
_ = ClawdbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
_ = MoltbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
let previous = self.anthropicAuthDetectedStatus
let status = ClawdbotOAuthStore.anthropicOAuthStatus()
let status = MoltbotOAuthStore.anthropicOAuthStatus()
self.anthropicAuthDetectedStatus = status
self.anthropicAuthConnected = status.isConnected
@@ -154,7 +154,7 @@ extension OnboardingView {
self.anthropicAuthVerificationFailed = false
defer { self.anthropicAuthVerifying = false }
guard let refresh = ClawdbotOAuthStore.loadAnthropicOAuthRefreshToken(), !refresh.isEmpty else {
guard let refresh = MoltbotOAuthStore.loadAnthropicOAuthRefreshToken(), !refresh.isEmpty else {
self.anthropicAuthStatus = "OAuth verification failed: missing refresh token."
self.anthropicAuthVerificationFailed = true
return
@@ -162,7 +162,7 @@ extension OnboardingView {
do {
let updated = try await AnthropicOAuth.refresh(refreshToken: refresh)
try ClawdbotOAuthStore.saveAnthropicOAuth(updated)
try MoltbotOAuthStore.saveAnthropicOAuth(updated)
self.refreshAnthropicOAuthStatus()
self.anthropicAuthVerified = true
self.anthropicAuthVerifiedAt = Date()

View File

@@ -1,7 +1,7 @@
import AppKit
import ClawdbotChatUI
import ClawdbotDiscovery
import ClawdbotIPC
import MoltbotChatUI
import MoltbotDiscovery
import MoltbotIPC
import SwiftUI
extension OnboardingView {
@@ -32,9 +32,9 @@ extension OnboardingView {
func welcomePage() -> some View {
self.onboardingPage {
VStack(spacing: 22) {
Text("Welcome to Clawdbot")
Text("Welcome to Moltbot")
.font(.largeTitle.weight(.semibold))
Text("Clawdbot is a powerful personal AI assistant that can connect to WhatsApp or Telegram.")
Text("Moltbot is a powerful personal AI assistant that can connect to WhatsApp or Telegram.")
.font(.body)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
@@ -57,7 +57,7 @@ extension OnboardingView {
"The connected AI agent (e.g. Claude) can trigger powerful actions on your Mac, " +
"including running commands, reading/writing files, and capturing screenshots — " +
"depending on the permissions you grant.\n\n" +
"Only enable Clawdbot if you understand the risks and trust the prompts and " +
"Only enable Moltbot if you understand the risks and trust the prompts and " +
"integrations you use.")
.font(.subheadline)
.foregroundStyle(.secondary)
@@ -76,7 +76,7 @@ extension OnboardingView {
Text("Choose your Gateway")
.font(.largeTitle.weight(.semibold))
Text(
"Clawdbot uses a single Gateway that stays running. Pick this Mac, " +
"Moltbot uses a single Gateway that stays running. Pick this Mac, " +
"connect to a discovered gateway nearby, or configure later.")
.font(.body)
.foregroundStyle(.secondary)
@@ -228,7 +228,7 @@ extension OnboardingView {
Text("Project root")
.font(.callout.weight(.semibold))
.frame(width: labelWidth, alignment: .leading)
TextField("/home/you/Projects/clawdbot", text: self.$state.remoteProjectRoot)
TextField("/home/you/Projects/moltbot", text: self.$state.remoteProjectRoot)
.textFieldStyle(.roundedBorder)
.frame(width: fieldWidth)
}
@@ -237,7 +237,7 @@ extension OnboardingView {
.font(.callout.weight(.semibold))
.frame(width: labelWidth, alignment: .leading)
TextField(
"/Applications/Clawdbot.app/.../clawdbot",
"/Applications/Moltbot.app/.../moltbot",
text: self.$state.remoteCliPath)
.textFieldStyle(.roundedBorder)
.frame(width: fieldWidth)
@@ -335,7 +335,7 @@ extension OnboardingView {
.multilineTextAlignment(.center)
.frame(maxWidth: 540)
.fixedSize(horizontal: false, vertical: true)
Text("Clawdbot supports any model — we strongly recommend Opus 4.5 for the best experience.")
Text("Moltbot supports any model — we strongly recommend Opus 4.5 for the best experience.")
.font(.callout)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
@@ -375,14 +375,14 @@ extension OnboardingView {
}
Text(
"This lets Clawdbot use Claude immediately. Credentials are stored at " +
"This lets Moltbot use Claude immediately. Credentials are stored at " +
"`~/.clawdbot/credentials/oauth.json` (owner-only).")
.font(.subheadline)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
HStack(spacing: 12) {
Text(ClawdbotOAuthStore.oauthURL().path)
Text(MoltbotOAuthStore.oauthURL().path)
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(1)
@@ -391,7 +391,7 @@ extension OnboardingView {
Spacer()
Button("Reveal") {
NSWorkspace.shared.activateFileViewerSelecting([ClawdbotOAuthStore.oauthURL()])
NSWorkspace.shared.activateFileViewerSelecting([MoltbotOAuthStore.oauthURL()])
}
.buttonStyle(.bordered)
@@ -493,7 +493,7 @@ extension OnboardingView {
self.onboardingPage {
Text("Grant permissions")
.font(.largeTitle.weight(.semibold))
Text("These macOS permissions let Clawdbot automate apps and capture context on this Mac.")
Text("These macOS permissions let Moltbot automate apps and capture context on this Mac.")
.font(.body)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
@@ -534,7 +534,7 @@ extension OnboardingView {
self.onboardingPage {
Text("Install the CLI")
.font(.largeTitle.weight(.semibold))
Text("Required for local mode: installs `clawdbot` so launchd can run the gateway.")
Text("Required for local mode: installs `moltbot` so launchd can run the gateway.")
.font(.body)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
@@ -594,7 +594,7 @@ extension OnboardingView {
Text("Agent workspace")
.font(.largeTitle.weight(.semibold))
Text(
"Clawdbot runs the agent from a dedicated workspace so it can load `AGENTS.md` " +
"Moltbot runs the agent from a dedicated workspace so it can load `AGENTS.md` " +
"and write files there without mixing into your other projects.")
.font(.body)
.foregroundStyle(.secondary)
@@ -621,7 +621,7 @@ extension OnboardingView {
Text("Workspace folder")
.font(.headline)
TextField(
AgentWorkspace.displayPath(for: ClawdbotConfigFile.defaultWorkspaceURL()),
AgentWorkspace.displayPath(for: MoltbotConfigFile.defaultWorkspaceURL()),
text: self.$workspacePath)
.textFieldStyle(.roundedBorder)
@@ -651,7 +651,7 @@ extension OnboardingView {
let saved = await self.saveAgentWorkspace(AgentWorkspace.displayPath(for: url))
if saved {
self.workspaceStatus =
"Saved to ~/.clawdbot/clawdbot.json (agents.defaults.workspace)"
"Saved to ~/.clawdbot/moltbot.json (agents.defaults.workspace)"
}
}
}
@@ -693,7 +693,7 @@ extension OnboardingView {
.fixedSize(horizontal: false, vertical: true)
self.onboardingGlassCard(padding: 8) {
ClawdbotChatView(viewModel: self.onboardingChatModel, style: .onboarding)
MoltbotChatView(viewModel: self.onboardingChatModel, style: .onboarding)
.frame(maxHeight: .infinity)
}
.frame(maxHeight: .infinity)
@@ -719,7 +719,7 @@ extension OnboardingView {
self.featureRow(
title: "Remote gateway checklist",
subtitle: """
On your gateway host: install/update the `clawdbot` package and make sure credentials exist
On your gateway host: install/update the `moltbot` package and make sure credentials exist
(typically `~/.clawdbot/credentials/oauth.json`). Then connect again if needed.
""",
systemImage: "network")
@@ -728,7 +728,7 @@ extension OnboardingView {
}
self.featureRow(
title: "Open the menu bar panel",
subtitle: "Click the Clawdbot menu bar icon for quick chat and status.",
subtitle: "Click the Moltbot menu bar icon for quick chat and status.",
systemImage: "bubble.left.and.bubble.right")
self.featureActionRow(
title: "Connect WhatsApp or Telegram",

View File

@@ -1,4 +1,4 @@
import ClawdbotDiscovery
import MoltbotDiscovery
import SwiftUI
#if DEBUG
@@ -14,7 +14,7 @@ extension OnboardingView {
tailnetDns: "gateway.ts.net",
sshPort: 2222,
gatewayPort: 18789,
cliPath: "/usr/local/bin/clawdbot",
cliPath: "/usr/local/bin/moltbot",
stableID: "gateway-1",
debugID: "gateway-1",
isLocal: false)
@@ -28,14 +28,14 @@ extension OnboardingView {
view.localGatewayProbe = LocalGatewayProbe(
port: GatewayEnvironment.gatewayPort(),
pid: 123,
command: "clawdbot-gateway",
command: "moltbot-gateway",
expected: true)
view.showAdvancedConnection = true
view.preferredGatewayID = gateway.stableID
view.cliInstalled = true
view.cliInstallLocation = "/usr/local/bin/clawdbot"
view.cliInstallLocation = "/usr/local/bin/moltbot"
view.cliStatus = "Installed"
view.workspacePath = "/tmp/clawdbot"
view.workspacePath = "/tmp/moltbot"
view.workspaceStatus = "Saved workspace"
view.anthropicAuthPKCE = AnthropicOAuth.PKCE(verifier: "verifier", challenge: "challenge")
view.anthropicAuthCode = "code#state"

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Observation
import SwiftUI

View File

@@ -1,7 +1,7 @@
import AppKit
import SwiftUI
struct GlowingClawdbotIcon: View {
struct GlowingMoltbotIcon: View {
@Environment(\.scenePhase) private var scenePhase
let size: CGFloat

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import OSLog
@@ -9,10 +9,10 @@ private let onboardingWizardLogger = Logger(subsystem: "com.clawdbot", category:
// MARK: - Swift 6 AnyCodable Bridging Helpers
// Bridge between ClawdbotProtocol.AnyCodable and the local module to avoid
// Bridge between MoltbotProtocol.AnyCodable and the local module to avoid
// Swift 6 strict concurrency type conflicts.
private typealias ProtocolAnyCodable = ClawdbotProtocol.AnyCodable
private typealias ProtocolAnyCodable = MoltbotProtocol.AnyCodable
private func bridgeToLocal(_ value: ProtocolAnyCodable) -> AnyCodable {
if let data = try? JSONEncoder().encode(value),
@@ -187,7 +187,7 @@ final class OnboardingWizardModel {
}
private func shouldSkipWizard() -> Bool {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
if let wizard = root["wizard"] as? [String: Any], !wizard.isEmpty {
return true
}

View File

@@ -12,7 +12,7 @@ final class PeekabooBridgeHostCoordinator {
private let logger = Logger(subsystem: "com.clawdbot", category: "PeekabooBridge")
private var host: PeekabooBridgeHost?
private var services: ClawdbotPeekabooBridgeServices?
private var services: MoltbotPeekabooBridgeServices?
func setEnabled(_ enabled: Bool) async {
if enabled {
@@ -39,7 +39,7 @@ final class PeekabooBridgeHostCoordinator {
}
let allowlistedBundles: Set<String> = []
let services = ClawdbotPeekabooBridgeServices()
let services = MoltbotPeekabooBridgeServices()
let server = PeekabooBridgeServer(
services: services,
hostKind: .gui,
@@ -90,7 +90,7 @@ final class PeekabooBridgeHostCoordinator {
}
@MainActor
private final class ClawdbotPeekabooBridgeServices: PeekabooBridgeServiceProviding {
private final class MoltbotPeekabooBridgeServices: PeekabooBridgeServiceProviding {
let permissions: PermissionsService
let screenCapture: any ScreenCaptureServiceProtocol
let automation: any UIAutomationServiceProtocol

View File

@@ -1,7 +1,7 @@
import AppKit
import ApplicationServices
import AVFoundation
import ClawdbotIPC
import MoltbotIPC
import CoreGraphics
import CoreLocation
import Foundation
@@ -380,7 +380,7 @@ enum AppleScriptPermission {
static func isAuthorized() -> Bool {
let script = """
tell application "Terminal"
return "clawdbot-ok"
return "moltbot-ok"
end tell
"""

View File

@@ -1,5 +1,5 @@
import ClawdbotIPC
import ClawdbotKit
import MoltbotIPC
import MoltbotKit
import CoreLocation
import SwiftUI
@@ -12,7 +12,7 @@ struct PermissionsSettings: View {
VStack(alignment: .leading, spacing: 14) {
SystemRunSettingsView()
Text("Allow these so Clawdbot can notify and capture when needed.")
Text("Allow these so Moltbot can notify and capture when needed.")
.padding(.top, 4)
PermissionStatusList(status: self.status, refresh: self.refresh)
@@ -31,9 +31,9 @@ struct PermissionsSettings: View {
}
private struct LocationAccessSettings: View {
@AppStorage(locationModeKey) private var locationModeRaw: String = ClawdbotLocationMode.off.rawValue
@AppStorage(locationModeKey) private var locationModeRaw: String = MoltbotLocationMode.off.rawValue
@AppStorage(locationPreciseKey) private var locationPreciseEnabled: Bool = true
@State private var lastLocationModeRaw: String = ClawdbotLocationMode.off.rawValue
@State private var lastLocationModeRaw: String = MoltbotLocationMode.off.rawValue
var body: some View {
VStack(alignment: .leading, spacing: 6) {
@@ -41,9 +41,9 @@ private struct LocationAccessSettings: View {
.font(.body)
Picker("", selection: self.$locationModeRaw) {
Text("Off").tag(ClawdbotLocationMode.off.rawValue)
Text("While Using").tag(ClawdbotLocationMode.whileUsing.rawValue)
Text("Always").tag(ClawdbotLocationMode.always.rawValue)
Text("Off").tag(MoltbotLocationMode.off.rawValue)
Text("While Using").tag(MoltbotLocationMode.whileUsing.rawValue)
Text("Always").tag(MoltbotLocationMode.always.rawValue)
}
.labelsHidden()
.pickerStyle(.menu)
@@ -62,7 +62,7 @@ private struct LocationAccessSettings: View {
.onChange(of: self.locationModeRaw) { _, newValue in
let previous = self.lastLocationModeRaw
self.lastLocationModeRaw = newValue
guard let mode = ClawdbotLocationMode(rawValue: newValue) else { return }
guard let mode = MoltbotLocationMode(rawValue: newValue) else { return }
Task {
let granted = await self.requestLocationAuthorization(mode: mode)
if !granted {
@@ -75,11 +75,11 @@ private struct LocationAccessSettings: View {
}
}
private var locationMode: ClawdbotLocationMode {
ClawdbotLocationMode(rawValue: self.locationModeRaw) ?? .off
private var locationMode: MoltbotLocationMode {
MoltbotLocationMode(rawValue: self.locationModeRaw) ?? .off
}
private func requestLocationAuthorization(mode: ClawdbotLocationMode) async -> Bool {
private func requestLocationAuthorization(mode: MoltbotLocationMode) async -> Bool {
guard mode != .off else { return true }
guard CLLocationManager.locationServicesEnabled() else {
await MainActor.run { LocationPermissionHelper.openSettings() }

View File

@@ -25,7 +25,7 @@ actor PortGuardian {
private let logger = Logger(subsystem: "com.clawdbot", category: "portguard")
private nonisolated static let appSupportDir: URL = {
let base = FileManager().urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return base.appendingPathComponent("Clawdbot", isDirectory: true)
return base.appendingPathComponent("Moltbot", isDirectory: true)
}()
private nonisolated static var recordPath: URL {
@@ -263,7 +263,7 @@ actor PortGuardian {
{
let expectedDesc: String
let okPredicate: (Listener) -> Bool
let expectedCommands = ["node", "clawdbot", "tsx", "pnpm", "bun"]
let expectedCommands = ["node", "moltbot", "tsx", "pnpm", "bun"]
switch mode {
case .remote:
@@ -357,10 +357,10 @@ actor PortGuardian {
if port == GatewayEnvironment.gatewayPort() { return cmd.contains("ssh") }
return false
case .local:
// The gateway daemon may listen as `clawdbot` or as its runtime (`node`, `bun`, etc).
// The gateway daemon may listen as `moltbot` or as its runtime (`node`, `bun`, etc).
if full.contains("gateway-daemon") { return true }
// If args are unavailable, treat a clawdbot listener as expected.
if cmd.contains("clawdbot"), full == cmd { return true }
// If args are unavailable, treat a moltbot listener as expected.
if cmd.contains("moltbot"), full == cmd { return true }
return false
case .unconfigured:
return false

View File

@@ -8,7 +8,7 @@ extension ProcessInfo {
var isNixMode: Bool {
if let raw = getenv("CLAWDBOT_NIX_MODE"), String(cString: raw) == "1" { return true }
return UserDefaults.standard.bool(forKey: "clawdbot.nixMode")
return UserDefaults.standard.bool(forKey: "moltbot.nixMode")
}
var isRunningTests: Bool {

View File

@@ -136,7 +136,7 @@ final class RemotePortTunnel {
}
private static func resolveRemotePortOverride(for sshHost: String) -> Int? {
let root = ClawdbotConfigFile.loadDict()
let root = MoltbotConfigFile.loadDict()
guard let gateway = root["gateway"] as? [String: Any],
let remote = gateway["remote"] as? [String: Any],
let urlRaw = remote["url"] as? String

View File

@@ -31,7 +31,7 @@ actor RemoteTunnelManager {
tunnel.terminate()
self.controlTunnel = nil
}
// If a previous Clawdbot run already has an SSH listener on the expected port (common after restarts),
// If a previous Moltbot run already has an SSH listener on the expected port (common after restarts),
// reuse it instead of spawning new ssh processes that immediately fail with "Address already in use".
let desiredPort = UInt16(GatewayEnvironment.gatewayPort())
if let desc = await PortGuardian.shared.describe(port: Int(desiredPort)),

View File

@@ -5,13 +5,13 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>Clawdbot</string>
<string>Moltbot</string>
<key>CFBundleIdentifier</key>
<string>com.clawdbot.mac</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Clawdbot</string>
<string>Moltbot</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -19,7 +19,7 @@
<key>CFBundleVersion</key>
<string>202601260</string>
<key>CFBundleIconFile</key>
<string>Clawdbot</string>
<string>Moltbot</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
@@ -27,7 +27,7 @@
<string>com.clawdbot.mac.deeplink</string>
<key>CFBundleURLSchemes</key>
<array>
<string>clawdbot</string>
<string>moltbot</string>
</array>
</dict>
</array>
@@ -36,29 +36,29 @@
<key>LSUIElement</key>
<true/>
<key>ClawdbotBuildTimestamp</key>
<key>MoltbotBuildTimestamp</key>
<string></string>
<key>ClawdbotGitCommit</key>
<key>MoltbotGitCommit</key>
<string></string>
<key>NSUserNotificationUsageDescription</key>
<string>Clawdbot needs notification permission to show alerts for agent actions.</string>
<string>Moltbot needs notification permission to show alerts for agent actions.</string>
<key>NSScreenCaptureDescription</key>
<string>Clawdbot captures the screen when the agent needs screenshots for context.</string>
<string>Moltbot captures the screen when the agent needs screenshots for context.</string>
<key>NSCameraUsageDescription</key>
<string>Clawdbot can capture photos or short video clips when requested by the agent.</string>
<string>Moltbot can capture photos or short video clips when requested by the agent.</string>
<key>NSLocationUsageDescription</key>
<string>Clawdbot can share your location when requested by the agent.</string>
<string>Moltbot can share your location when requested by the agent.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Clawdbot can share your location when requested by the agent.</string>
<string>Moltbot can share your location when requested by the agent.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Clawdbot can share your location when requested by the agent.</string>
<string>Moltbot can share your location when requested by the agent.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Clawdbot needs the mic for Voice Wake tests and agent audio capture.</string>
<string>Moltbot needs the mic for Voice Wake tests and agent audio capture.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>Clawdbot uses speech recognition to detect your Voice Wake trigger phrase.</string>
<string>Moltbot uses speech recognition to detect your Voice Wake trigger phrase.</string>
<key>NSAppleEventsUsageDescription</key>
<string>Clawdbot needs Automation (AppleScript) permission to drive Terminal and other apps for agent actions.</string>
<string>Moltbot needs Automation (AppleScript) permission to drive Terminal and other apps for agent actions.</string>
<key>NSAppTransportSecurity</key>
<dict>

View File

@@ -89,7 +89,7 @@ enum RuntimeLocator {
switch error {
case let .notFound(searchPaths):
[
"clawdbot needs Node >=22.0.0 but found no runtime.",
"moltbot needs Node >=22.0.0 but found no runtime.",
"PATH searched: \(searchPaths.joined(separator: ":"))",
"Install Node: https://nodejs.org/en/download",
].joined(separator: "\n")
@@ -97,7 +97,7 @@ enum RuntimeLocator {
[
"Found \(kind.rawValue) \(found) at \(path) but need >= \(required).",
"PATH searched: \(searchPaths.joined(separator: ":"))",
"Upgrade Node and rerun clawdbot.",
"Upgrade Node and rerun moltbot.",
].joined(separator: "\n")
case let .versionParse(kind, raw, path, searchPaths):
[

View File

@@ -43,7 +43,7 @@ final class ScreenRecordService {
return URL(fileURLWithPath: outPath)
}
return FileManager().temporaryDirectory
.appendingPathComponent("clawdbot-screen-record-\(UUID().uuidString).mp4")
.appendingPathComponent("moltbot-screen-record-\(UUID().uuidString).mp4")
}()
try? FileManager().removeItem(at: outURL)

View File

@@ -1,6 +1,6 @@
import ClawdbotChatUI
import ClawdbotKit
import ClawdbotProtocol
import MoltbotChatUI
import MoltbotKit
import MoltbotProtocol
import OSLog
import SwiftUI
@@ -288,7 +288,7 @@ enum SessionMenuPreviewLoader {
private static func requestPreview(
keys: [String],
maxItems: Int) async throws -> ClawdbotSessionsPreviewPayload
maxItems: Int) async throws -> MoltbotSessionsPreviewPayload
{
let boundedItems = self.normalizeMaxItems(maxItems)
let timeoutMs = Int(self.previewTimeoutSeconds * 1000)
@@ -331,7 +331,7 @@ enum SessionMenuPreviewLoader {
}
private static func snapshot(
from entry: ClawdbotSessionPreviewEntry,
from entry: MoltbotSessionPreviewEntry,
maxItems: Int) -> SessionMenuPreviewSnapshot
{
let items = self.previewItems(from: entry, maxItems: maxItems)
@@ -348,7 +348,7 @@ enum SessionMenuPreviewLoader {
}
}
private static func cache(payload: ClawdbotSessionsPreviewPayload, maxItems: Int) async {
private static func cache(payload: MoltbotSessionsPreviewPayload, maxItems: Int) async {
for entry in payload.previews {
let snapshot = self.snapshot(from: entry, maxItems: maxItems)
await SessionPreviewCache.shared.store(snapshot: snapshot, for: entry.key)
@@ -365,7 +365,7 @@ enum SessionMenuPreviewLoader {
}
private static func previewItems(
from entry: ClawdbotSessionPreviewEntry,
from entry: MoltbotSessionPreviewEntry,
maxItems: Int) -> [SessionPreviewItem]
{
let boundedItems = self.normalizeMaxItems(maxItems)
@@ -381,11 +381,11 @@ enum SessionMenuPreviewLoader {
}
private static func previewItems(
from payload: ClawdbotChatHistoryPayload,
from payload: MoltbotChatHistoryPayload,
maxItems: Int) -> [SessionPreviewItem]
{
let boundedItems = self.normalizeMaxItems(maxItems)
let raw: [ClawdbotKit.AnyCodable] = payload.messages ?? []
let raw: [MoltbotKit.AnyCodable] = payload.messages ?? []
let messages = self.decodeMessages(raw)
let built = messages.compactMap { message -> SessionPreviewItem? in
guard let text = self.previewText(for: message) else { return nil }
@@ -399,10 +399,10 @@ enum SessionMenuPreviewLoader {
return Array(trimmed.reversed())
}
private static func decodeMessages(_ raw: [ClawdbotKit.AnyCodable]) -> [ClawdbotChatMessage] {
private static func decodeMessages(_ raw: [MoltbotKit.AnyCodable]) -> [MoltbotChatMessage] {
raw.compactMap { item in
guard let data = try? JSONEncoder().encode(item) else { return nil }
return try? JSONDecoder().decode(ClawdbotChatMessage.self, from: data)
return try? JSONDecoder().decode(MoltbotChatMessage.self, from: data)
}
}
@@ -421,7 +421,7 @@ enum SessionMenuPreviewLoader {
}
}
private static func previewText(for message: ClawdbotChatMessage) -> String? {
private static func previewText(for message: MoltbotChatMessage) -> String? {
let text = message.content.compactMap(\.text).joined(separator: "\n")
.trimmingCharacters(in: .whitespacesAndNewlines)
if !text.isEmpty { return text }
@@ -442,12 +442,12 @@ enum SessionMenuPreviewLoader {
return nil
}
private static func isToolCall(_ message: ClawdbotChatMessage) -> Bool {
private static func isToolCall(_ message: MoltbotChatMessage) -> Bool {
if message.toolName?.nonEmpty != nil { return true }
return message.content.contains { $0.name?.nonEmpty != nil || $0.type?.lowercased() == "toolcall" }
}
private static func toolNames(for message: ClawdbotChatMessage) -> [String] {
private static func toolNames(for message: MoltbotChatMessage) -> [String] {
var names: [String] = []
for content in message.content {
if let name = content.name?.nonEmpty {
@@ -460,7 +460,7 @@ enum SessionMenuPreviewLoader {
return Self.dedupePreservingOrder(names)
}
private static func mediaSummary(for message: ClawdbotChatMessage) -> String? {
private static func mediaSummary(for message: MoltbotChatMessage) -> String? {
let types = message.content.compactMap { content -> String? in
let raw = content.type?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
guard let raw, !raw.isEmpty else { return nil }

View File

@@ -111,8 +111,8 @@ struct SettingsRootView: View {
private var nixManagedBanner: some View {
// Prefer gateway-resolved paths; fall back to local env defaults if disconnected.
let configPath = self.snapshotPaths.configPath ?? ClawdbotPaths.configURL.path
let stateDir = self.snapshotPaths.stateDir ?? ClawdbotPaths.stateDirURL.path
let configPath = self.snapshotPaths.configPath ?? MoltbotPaths.configURL.path
let stateDir = self.snapshotPaths.stateDir ?? MoltbotPaths.stateDirURL.path
return VStack(alignment: .leading, spacing: 6) {
HStack(spacing: 8) {
@@ -227,7 +227,7 @@ enum SettingsTabRouter {
}
extension Notification.Name {
static let clawdbotSelectSettingsTab = Notification.Name("clawdbotSelectSettingsTab")
static let moltbotSelectSettingsTab = Notification.Name("moltbotSelectSettingsTab")
}
#if DEBUG

View File

@@ -1,4 +1,4 @@
import ClawdbotIPC
import MoltbotIPC
import Foundation
enum ShellExecutor {

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Foundation
struct SkillsStatusReport: Codable {

View File

@@ -1,4 +1,4 @@
import ClawdbotProtocol
import MoltbotProtocol
import Observation
import SwiftUI
@@ -231,13 +231,13 @@ private struct SkillRow: View {
private var sourceLabel: String {
switch self.skill.source {
case "clawdbot-bundled":
case "moltbot-bundled":
"Bundled"
case "clawdbot-managed":
case "moltbot-managed":
"Managed"
case "clawdbot-workspace":
case "moltbot-workspace":
"Workspace"
case "clawdbot-extra":
case "moltbot-extra":
"Extra"
default:
self.skill.source
@@ -578,7 +578,7 @@ extension SkillsSettings {
let skill = SkillStatus(
name: "Test Skill",
description: "Test description",
source: "clawdbot-bundled",
source: "moltbot-bundled",
filePath: "/tmp/skills/test",
baseDir: "/tmp/skills",
skillKey: "test",

View File

@@ -234,7 +234,7 @@ struct TailscaleIntegrationSection: View {
.textFieldStyle(.roundedBorder)
.frame(maxWidth: 240)
.onSubmit { Task { await self.applySettings() } }
Text("Stored in ~/.clawdbot/clawdbot.json. Prefer CLAWDBOT_GATEWAY_PASSWORD for production.")
Text("Stored in ~/.clawdbot/moltbot.json. Prefer CLAWDBOT_GATEWAY_PASSWORD for production.")
.font(.caption)
.foregroundStyle(.secondary)
Button("Update password") { Task { await self.applySettings() } }
@@ -293,9 +293,9 @@ struct TailscaleIntegrationSection: View {
}
if self.connectionMode == .local, !self.isPaused {
self.statusMessage = "Saved to ~/.clawdbot/clawdbot.json. Restarting gateway…"
self.statusMessage = "Saved to ~/.clawdbot/moltbot.json. Restarting gateway…"
} else {
self.statusMessage = "Saved to ~/.clawdbot/clawdbot.json. Restart the gateway to apply."
self.statusMessage = "Saved to ~/.clawdbot/moltbot.json. Restart the gateway to apply."
}
self.restartGatewayIfNeeded()
}

View File

@@ -1,6 +1,6 @@
import AVFoundation
import ClawdbotChatUI
import ClawdbotKit
import MoltbotChatUI
import MoltbotKit
import Foundation
import OSLog
import Speech
@@ -416,9 +416,9 @@ actor TalkModeRuntime {
do {
let history = try await GatewayConnection.shared.chatHistory(sessionKey: sessionKey)
let messages = history.messages ?? []
let decoded: [ClawdbotChatMessage] = messages.compactMap { item in
let decoded: [MoltbotChatMessage] = messages.compactMap { item in
guard let data = try? JSONEncoder().encode(item) else { return nil }
return try? JSONDecoder().decode(ClawdbotChatMessage.self, from: data)
return try? JSONDecoder().decode(MoltbotChatMessage.self, from: data)
}
let assistant = decoded.last { message in
guard message.role == "assistant" else { return false }

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import OSLog

View File

@@ -11,7 +11,7 @@ final class VoiceWakeOverlayController {
let logger = Logger(subsystem: "com.clawdbot", category: "voicewake.overlay")
let enableUI: Bool
/// Keep the voice wake overlay above any other Clawdbot windows, but below the systems pop-up menus.
/// Keep the voice wake overlay above any other Moltbot windows, but below the systems pop-up menus.
/// (Menu bar menus typically live at `.popUpMenu`.)
static let preferredWindowLevel = NSWindow.Level(rawValue: NSWindow.Level.popUpMenu.rawValue - 4)

View File

@@ -205,7 +205,7 @@ struct VoiceWakeSettings: View {
.stroke(Color.secondary.opacity(0.25), lineWidth: 1))
Text(
"Clawdbot reacts when any trigger appears in a transcription. "
"Moltbot reacts when any trigger appears in a transcription. "
+ "Keep them short to avoid false positives.")
.font(.footnote)
.foregroundStyle(.secondary)

View File

@@ -1,7 +1,7 @@
import AppKit
import ClawdbotChatUI
import ClawdbotKit
import ClawdbotProtocol
import MoltbotChatUI
import MoltbotKit
import MoltbotProtocol
import Foundation
import OSLog
import QuartzCore
@@ -16,8 +16,8 @@ private enum WebChatSwiftUILayout {
static let anchorPadding: CGFloat = 8
}
struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
func requestHistory(sessionKey: String) async throws -> ClawdbotChatHistoryPayload {
struct MacGatewayChatTransport: MoltbotChatTransport, Sendable {
func requestHistory(sessionKey: String) async throws -> MoltbotChatHistoryPayload {
try await GatewayConnection.shared.chatHistory(sessionKey: sessionKey)
}
@@ -31,7 +31,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
timeoutMs: 10000)
}
func listSessions(limit: Int?) async throws -> ClawdbotChatSessionsListResponse {
func listSessions(limit: Int?) async throws -> MoltbotChatSessionsListResponse {
var params: [String: AnyCodable] = [
"includeGlobal": AnyCodable(true),
"includeUnknown": AnyCodable(false),
@@ -43,7 +43,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
method: "sessions.list",
params: params,
timeoutMs: 15000)
return try JSONDecoder().decode(ClawdbotChatSessionsListResponse.self, from: data)
return try JSONDecoder().decode(MoltbotChatSessionsListResponse.self, from: data)
}
func sendMessage(
@@ -51,7 +51,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
message: String,
thinking: String,
idempotencyKey: String,
attachments: [ClawdbotChatAttachmentPayload]) async throws -> ClawdbotChatSendResponse
attachments: [MoltbotChatAttachmentPayload]) async throws -> MoltbotChatSendResponse
{
try await GatewayConnection.shared.chatSend(
sessionKey: sessionKey,
@@ -65,7 +65,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
try await GatewayConnection.shared.healthOK(timeoutMs: timeoutMs)
}
func events() -> AsyncStream<ClawdbotChatTransportEvent> {
func events() -> AsyncStream<MoltbotChatTransportEvent> {
AsyncStream { continuation in
let task = Task {
do {
@@ -89,11 +89,11 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
}
}
static func mapPushToTransportEvent(_ push: GatewayPush) -> ClawdbotChatTransportEvent? {
static func mapPushToTransportEvent(_ push: GatewayPush) -> MoltbotChatTransportEvent? {
switch push {
case let .snapshot(hello):
let ok = (try? JSONDecoder().decode(
ClawdbotGatewayHealthOK.self,
MoltbotGatewayHealthOK.self,
from: JSONEncoder().encode(hello.snapshot.health)))?.ok ?? true
return .health(ok: ok)
@@ -102,7 +102,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
case "health":
guard let payload = evt.payload else { return nil }
let ok = (try? JSONDecoder().decode(
ClawdbotGatewayHealthOK.self,
MoltbotGatewayHealthOK.self,
from: JSONEncoder().encode(payload)))?.ok ?? true
return .health(ok: ok)
case "tick":
@@ -110,7 +110,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
case "chat":
guard let payload = evt.payload else { return nil }
guard let chat = try? JSONDecoder().decode(
ClawdbotChatEventPayload.self,
MoltbotChatEventPayload.self,
from: JSONEncoder().encode(payload))
else {
return nil
@@ -119,7 +119,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
case "agent":
guard let payload = evt.payload else { return nil }
guard let agent = try? JSONDecoder().decode(
ClawdbotAgentEventPayload.self,
MoltbotAgentEventPayload.self,
from: JSONEncoder().encode(payload))
else {
return nil
@@ -141,7 +141,7 @@ struct MacGatewayChatTransport: ClawdbotChatTransport, Sendable {
final class WebChatSwiftUIWindowController {
private let presentation: WebChatPresentation
private let sessionKey: String
private let hosting: NSHostingController<ClawdbotChatView>
private let hosting: NSHostingController<MoltbotChatView>
private let contentController: NSViewController
private var window: NSWindow?
private var dismissMonitor: Any?
@@ -152,12 +152,12 @@ final class WebChatSwiftUIWindowController {
self.init(sessionKey: sessionKey, presentation: presentation, transport: MacGatewayChatTransport())
}
init(sessionKey: String, presentation: WebChatPresentation, transport: any ClawdbotChatTransport) {
init(sessionKey: String, presentation: WebChatPresentation, transport: any MoltbotChatTransport) {
self.sessionKey = sessionKey
self.presentation = presentation
let vm = ClawdbotChatViewModel(sessionKey: sessionKey, transport: transport)
let vm = MoltbotChatViewModel(sessionKey: sessionKey, transport: transport)
let accent = Self.color(fromHex: AppStateStore.shared.seamColorHex)
self.hosting = NSHostingController(rootView: ClawdbotChatView(
self.hosting = NSHostingController(rootView: MoltbotChatView(
viewModel: vm,
showsSessionSwitcher: true,
userAccent: accent))
@@ -268,7 +268,7 @@ final class WebChatSwiftUIWindowController {
styleMask: [.titled, .closable, .resizable, .miniaturizable],
backing: .buffered,
defer: false)
window.title = "Clawdbot Chat"
window.title = "Moltbot Chat"
window.contentViewController = contentViewController
window.isReleasedWhenClosed = false
window.titleVisibility = .visible
@@ -311,7 +311,7 @@ final class WebChatSwiftUIWindowController {
private static func makeContentController(
for presentation: WebChatPresentation,
hosting: NSHostingController<ClawdbotChatView>) -> NSViewController
hosting: NSHostingController<MoltbotChatView>) -> NSViewController
{
let controller = NSViewController()
let effectView = NSVisualEffectView()

View File

@@ -1,5 +1,5 @@
import ClawdbotKit
import ClawdbotProtocol
import MoltbotKit
import MoltbotProtocol
import Foundation
import Observation
import SwiftUI
@@ -56,7 +56,7 @@ final class WorkActivityStore {
phase: String,
name: String?,
meta: String?,
args: [String: ClawdbotProtocol.AnyCodable]?)
args: [String: MoltbotProtocol.AnyCodable]?)
{
let toolKind = Self.mapToolKind(name)
let label = Self.buildLabel(name: name, meta: meta, args: args)
@@ -225,7 +225,7 @@ final class WorkActivityStore {
private static func buildLabel(
name: String?,
meta: String?,
args: [String: ClawdbotProtocol.AnyCodable]?) -> String
args: [String: MoltbotProtocol.AnyCodable]?) -> String
{
let wrappedArgs = self.wrapToolArgs(args)
let display = ToolDisplayRegistry.resolve(name: name ?? "tool", args: wrappedArgs, meta: meta)
@@ -236,17 +236,17 @@ final class WorkActivityStore {
return display.label
}
private static func wrapToolArgs(_ args: [String: ClawdbotProtocol.AnyCodable]?) -> ClawdbotKit.AnyCodable? {
private static func wrapToolArgs(_ args: [String: MoltbotProtocol.AnyCodable]?) -> MoltbotKit.AnyCodable? {
guard let args else { return nil }
let converted: [String: Any] = args.mapValues { self.unwrapJSONValue($0.value) }
return ClawdbotKit.AnyCodable(converted)
return MoltbotKit.AnyCodable(converted)
}
private static func unwrapJSONValue(_ value: Any) -> Any {
if let dict = value as? [String: ClawdbotProtocol.AnyCodable] {
if let dict = value as? [String: MoltbotProtocol.AnyCodable] {
return dict.mapValues { self.unwrapJSONValue($0.value) }
}
if let array = value as? [ClawdbotProtocol.AnyCodable] {
if let array = value as? [MoltbotProtocol.AnyCodable] {
return array.map { self.unwrapJSONValue($0.value) }
}
if let dict = value as? [String: Any] {

View File

@@ -1,4 +1,4 @@
import ClawdbotKit
import MoltbotKit
import Foundation
import Network
import Observation
@@ -81,11 +81,11 @@ public final class GatewayDiscoveryModel {
public func start() {
if !self.browsers.isEmpty { return }
for domain in ClawdbotBonjour.gatewayServiceDomains {
for domain in MoltbotBonjour.gatewayServiceDomains {
let params = NWParameters.tcp
params.includePeerToPeer = true
let browser = NWBrowser(
for: .bonjour(type: ClawdbotBonjour.gatewayServiceType, domain: domain),
for: .bonjour(type: MoltbotBonjour.gatewayServiceType, domain: domain),
using: params)
browser.stateUpdateHandler = { [weak self] state in
@@ -113,7 +113,7 @@ public final class GatewayDiscoveryModel {
}
public func refreshWideAreaFallbackNow(timeoutSeconds: TimeInterval = 5.0) {
let domain = ClawdbotBonjour.wideAreaGatewayServiceDomain
let domain = MoltbotBonjour.wideAreaGatewayServiceDomain
Task.detached(priority: .utility) { [weak self] in
guard let self else { return }
let beacons = WideAreaGatewayDiscovery.discover(timeoutSeconds: timeoutSeconds)
@@ -235,7 +235,7 @@ public final class GatewayDiscoveryModel {
}
.sorted { $0.displayName.localizedCaseInsensitiveCompare($1.displayName) == .orderedAscending }
if domain == ClawdbotBonjour.wideAreaGatewayServiceDomain,
if domain == MoltbotBonjour.wideAreaGatewayServiceDomain,
self.hasUsableWideAreaResults
{
self.wideAreaFallbackGateways = []
@@ -243,7 +243,7 @@ public final class GatewayDiscoveryModel {
}
private func scheduleWideAreaFallback() {
let domain = ClawdbotBonjour.wideAreaGatewayServiceDomain
let domain = MoltbotBonjour.wideAreaGatewayServiceDomain
if Self.isRunningTests { return }
guard self.wideAreaFallbackTask == nil else { return }
self.wideAreaFallbackTask = Task.detached(priority: .utility) { [weak self] in
@@ -276,7 +276,7 @@ public final class GatewayDiscoveryModel {
}
private var hasUsableWideAreaResults: Bool {
let domain = ClawdbotBonjour.wideAreaGatewayServiceDomain
let domain = MoltbotBonjour.wideAreaGatewayServiceDomain
guard let gateways = self.gatewaysByDomain[domain], !gateways.isEmpty else { return false }
if !self.filterLocalGateways { return true }
return gateways.contains(where: { !$0.isLocal })
@@ -455,7 +455,7 @@ public final class GatewayDiscoveryModel {
private nonisolated static func prettifyInstanceName(_ decodedName: String) -> String {
let normalized = decodedName.split(whereSeparator: \.isWhitespace).joined(separator: " ")
let stripped = normalized.replacingOccurrences(of: " (Clawdbot)", with: "")
let stripped = normalized.replacingOccurrences(of: " (Moltbot)", with: "")
.replacingOccurrences(of: #"\s+\(\d+\)$"#, with: "", options: .regularExpression)
return stripped.trimmingCharacters(in: .whitespacesAndNewlines)
}

Some files were not shown because too many files have changed in this diff Show More