chore: rename project to clawdbot

This commit is contained in:
Peter Steinberger
2026-01-04 14:32:47 +00:00
parent d48dc71fa4
commit 246adaa119
841 changed files with 4590 additions and 4328 deletions

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/steipete/clawdis") {
if let url = URL(string: "https://github.com/clawdbot/clawdbot") {
NSWorkspace.shared.open(url)
}
} label: {
@@ -29,7 +29,7 @@ struct AboutSettings: View {
}
VStack(spacing: 3) {
Text("Clawdis")
Text("Clawdbot")
.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/steipete/clawdis")
url: "https://github.com/clawdbot/clawdbot")
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: "ClawdisBuildTimestamp") as? String else { return nil }
guard let raw = Bundle.main.object(forInfoDictionaryKey: "ClawdbotBuildTimestamp") as? String else { return nil }
let parser = ISO8601DateFormatter()
parser.formatOptions = [.withInternetDateTime]
guard let date = parser.date(from: raw) else { return raw }
@@ -121,7 +121,7 @@ struct AboutSettings: View {
}
private var gitCommit: String {
Bundle.main.object(forInfoDictionaryKey: "ClawdisGitCommit") as? String ?? "unknown"
Bundle.main.object(forInfoDictionaryKey: "ClawdbotGitCommit") as? String ?? "unknown"
}
private var bundleID: String {

View File

@@ -2,7 +2,7 @@ import Foundation
import OSLog
enum AgentWorkspace {
private static let logger = Logger(subsystem: "com.clawdis", category: "workspace")
private static let logger = Logger(subsystem: "com.clawdbot", category: "workspace")
static let agentsFilename = "AGENTS.md"
static let soulFilename = "SOUL.md"
static let identityFilename = "IDENTITY.md"
@@ -34,7 +34,7 @@ enum AgentWorkspace {
static func resolveWorkspaceURL(from userInput: String?) -> URL {
let trimmed = userInput?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if trimmed.isEmpty { return ClawdisConfigFile.defaultWorkspaceURL() }
if trimmed.isEmpty { return ClawdbotConfigFile.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 - Clawdis Workspace
# AGENTS.md - Clawdbot Workspace
This folder is the assistant's working directory.
@@ -265,7 +265,7 @@ enum AgentWorkspace {
- Timezone (optional)
- Notes
3) ~/.clawdis/clawdis.json
3) ~/.clawdbot/clawdbot.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: ClawdisOAuthStore.AnthropicOAuthStatus = ClawdisOAuthStore.anthropicOAuthStatus()
@State private var oauthStatus: ClawdbotOAuthStore.AnthropicOAuthStatus = ClawdbotOAuthStore.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([ClawdisOAuthStore.oauthURL()])
NSWorkspace.shared.activateFileViewerSelecting([ClawdbotOAuthStore.oauthURL()])
}
.buttonStyle(.bordered)
.disabled(!FileManager.default.fileExists(atPath: ClawdisOAuthStore.oauthURL().path))
.disabled(!FileManager.default.fileExists(atPath: ClawdbotOAuthStore.oauthURL().path))
Button("Refresh") {
self.refresh()
@@ -53,7 +53,7 @@ struct AnthropicAuthControls: View {
.buttonStyle(.bordered)
}
Text(ClawdisOAuthStore.oauthURL().path)
Text(ClawdbotOAuthStore.oauthURL().path)
.font(.caption.monospaced())
.foregroundStyle(.secondary)
.lineLimit(1)
@@ -130,8 +130,8 @@ struct AnthropicAuthControls: View {
}
private func refresh() {
let imported = ClawdisOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = ClawdisOAuthStore.anthropicOAuthStatus()
let imported = ClawdbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = ClawdbotOAuthStore.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 ClawdisOAuthStore.saveAnthropicOAuth(creds)
try ClawdbotOAuthStore.saveAnthropicOAuth(creds)
self.refresh()
self.pkce = nil
self.code = ""
self.statusText = "Connected. Clawdis can now use Claude via OAuth."
self.statusText = "Connected. Clawdbot 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: ClawdisOAuthStore.AnthropicOAuthStatus,
oauthStatus: ClawdbotOAuthStore.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 (Clawdis token file)"
case .oauthFile: "OAuth (Clawdbot 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: ClawdisOAuthStore.AnthropicOAuthStatus = ClawdisOAuthStore
oauthStatus: ClawdbotOAuthStore.AnthropicOAuthStatus = ClawdbotOAuthStore
.anthropicOAuthStatus()) -> AnthropicAuthMode
{
if oauthStatus.isConnected { return .oauthFile }
@@ -58,7 +58,7 @@ enum AnthropicAuthResolver {
}
enum AnthropicOAuth {
private static let logger = Logger(subsystem: "com.clawdis", category: "anthropic-oauth")
private static let logger = Logger(subsystem: "com.clawdbot", category: "anthropic-oauth")
private static let clientId = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
private static let authorizeURL = URL(string: "https://claude.ai/oauth/authorize")!
@@ -194,10 +194,10 @@ enum AnthropicOAuth {
}
}
enum ClawdisOAuthStore {
enum ClawdbotOAuthStore {
static let oauthFilename = "oauth.json"
private static let providerKey = "anthropic"
private static let clawdisOAuthDirEnv = "CLAWDIS_OAUTH_DIR"
private static let clawdbotOAuthDirEnv = "CLAWDBOT_OAUTH_DIR"
private static let legacyPiDirEnv = "PI_CODING_AGENT_DIR"
enum AnthropicOAuthStatus: Equatable {
@@ -215,18 +215,18 @@ enum ClawdisOAuthStore {
var shortDescription: String {
switch self {
case .missingFile: "Clawdis OAuth token file not found"
case .unreadableFile: "Clawdis OAuth token file not readable"
case .invalidJSON: "Clawdis OAuth token file invalid"
case .missingProviderEntry: "No Anthropic entry in Clawdis OAuth token file"
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 .missingTokens: "Anthropic entry missing tokens"
case .connected: "Clawdis OAuth credentials found"
case .connected: "Clawdbot OAuth credentials found"
}
}
}
static func oauthDir() -> URL {
if let override = ProcessInfo.processInfo.environment[self.clawdisOAuthDirEnv]?
if let override = ProcessInfo.processInfo.environment[self.clawdbotOAuthDirEnv]?
.trimmingCharacters(in: .whitespacesAndNewlines),
!override.isEmpty
{
@@ -235,7 +235,7 @@ enum ClawdisOAuthStore {
}
return FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdis", isDirectory: true)
.appendingPathComponent(".clawdbot", isDirectory: true)
.appendingPathComponent("credentials", isDirectory: true)
}

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
extension AnyCodable {

View File

@@ -33,13 +33,13 @@ final class AppState {
}
var onboardingSeen: Bool {
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: "clawdis.onboardingSeen") }
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: "clawdbot.onboardingSeen") }
}
}
var debugPaneEnabled: Bool {
didSet {
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "clawdis.debugPaneEnabled") }
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "clawdbot.debugPaneEnabled") }
CanvasManager.shared.refreshDebugStatus()
}
}
@@ -206,11 +206,11 @@ final class AppState {
init(preview: Bool = false) {
self.isPreview = preview
let onboardingSeen = UserDefaults.standard.bool(forKey: "clawdis.onboardingSeen")
let onboardingSeen = UserDefaults.standard.bool(forKey: "clawdbot.onboardingSeen")
self.isPaused = UserDefaults.standard.bool(forKey: pauseDefaultsKey)
self.launchAtLogin = false
self.onboardingSeen = onboardingSeen
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: "clawdis.debugPaneEnabled")
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: "clawdbot.debugPaneEnabled")
let savedVoiceWake = UserDefaults.standard.bool(forKey: swabbleEnabledKey)
self.swabbleEnabled = voiceWakeSupported ? savedVoiceWake : false
self.swabbleTriggerWords = UserDefaults.standard
@@ -251,7 +251,7 @@ final class AppState {
UserDefaults.standard.set(IconOverrideSelection.system.rawValue, forKey: iconOverrideKey)
}
let configRoot = ClawdisConfigFile.loadDict()
let configRoot = ClawdbotConfigFile.loadDict()
let configGateway = configRoot["gateway"] as? [String: Any]
let configModeRaw = (configGateway?["mode"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
let configMode: ConnectionMode? = {
@@ -339,7 +339,7 @@ final class AppState {
}
private func startConfigWatcher() {
let configUrl = ClawdisConfigFile.url()
let configUrl = ClawdbotConfigFile.url()
self.configWatcher = ConfigFileWatcher(url: configUrl) { [weak self] in
Task { @MainActor in
self?.applyConfigFromDisk()
@@ -349,7 +349,7 @@ final class AppState {
}
private func applyConfigFromDisk() {
let root = ClawdisConfigFile.loadDict()
let root = ClawdbotConfigFile.loadDict()
self.applyConfigOverrides(root)
}
@@ -403,7 +403,7 @@ final class AppState {
private func syncGatewayConfigIfNeeded() {
guard !self.isPreview, !self.isInitializing else { return }
var root = ClawdisConfigFile.loadDict()
var root = ClawdbotConfigFile.loadDict()
var gateway = root["gateway"] as? [String: Any] ?? [:]
var changed = false
@@ -446,7 +446,7 @@ final class AppState {
guard changed else { return }
root["gateway"] = gateway
ClawdisConfigFile.saveDict(root)
ClawdbotConfigFile.saveDict(root)
}
func triggerVoiceEars(ttl: TimeInterval? = 5) {
@@ -586,7 +586,7 @@ extension AppState {
state.canvasEnabled = true
state.remoteTarget = "user@example.com"
state.remoteIdentity = "~/.ssh/id_ed25519"
state.remoteProjectRoot = "~/Projects/clawdis"
state.remoteProjectRoot = "~/Projects/clawdbot"
state.remoteCliPath = ""
state.attachExistingGatewayOnly = false
return state

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Network
import OSLog
@@ -19,7 +19,7 @@ actor BridgeConnectionHandler {
private let logger: Logger
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
private let queue = DispatchQueue(label: "com.clawdis.bridge.connection")
private let queue = DispatchQueue(label: "com.clawdbot.bridge.connection")
private var buffer = Data()
private var isAuthenticated = false

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdisKit
import ClawdisProtocol
import ClawdbotKit
import ClawdbotProtocol
import Foundation
import Network
import OSLog
@@ -8,7 +8,7 @@ import OSLog
actor BridgeServer {
static let shared = BridgeServer()
private let logger = Logger(subsystem: "com.clawdis", category: "bridge")
private let logger = Logger(subsystem: "com.clawdbot", category: "bridge")
private var listener: NWListener?
private var isRunning = false
private var store: PairedNodesStore?
@@ -42,7 +42,7 @@ actor BridgeServer {
Task { await self.handleListenerState(state) }
}
listener.start(queue: DispatchQueue(label: "com.clawdis.bridge"))
listener.start(queue: DispatchQueue(label: "com.clawdbot.bridge"))
self.listener = listener
} catch {
self.logger.error("bridge start failed: \(error.localizedDescription, privacy: .public)")
@@ -473,7 +473,7 @@ actor BridgeServer {
userInfo: [NSLocalizedDescriptionKey: "Application Support unavailable"])
}
return base
.appendingPathComponent("Clawdis", isDirectory: true)
.appendingPathComponent("Clawdbot", isDirectory: true)
.appendingPathComponent("bridge", isDirectory: true)
.appendingPathComponent("paired-nodes.json", isDirectory: false)
}
@@ -486,7 +486,7 @@ enum BridgePairingApprover {
let name = request.displayName ?? request.nodeId
let remote = request.remoteAddress?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
let alert = NSAlert()
alert.messageText = isRepair ? "Re-pair Clawdis Node?" : "Pair Clawdis Node?"
alert.messageText = isRepair ? "Re-pair Clawdbot Node?" : "Pair Clawdbot Node?"
alert.informativeText = """
Node: \(name)
IP: \(remote ?? "unknown")

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Network

View File

@@ -3,7 +3,7 @@ import Foundation
@MainActor
enum CLIInstaller {
private static func embeddedHelperURL() -> URL {
Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/Relay/clawdis")
Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/Relay/clawdbot")
}
static func installedLocation() -> String? {
@@ -21,7 +21,7 @@ enum CLIInstaller {
let embedded = embeddedHelper.resolvingSymlinksInPath()
for basePath in searchPaths {
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("clawdis").path
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("clawdbot").path
var isDirectory: ObjCBool = false
guard fileManager.fileExists(atPath: candidate, isDirectory: &isDirectory),
@@ -54,7 +54,7 @@ enum CLIInstaller {
return
}
let targets = cliHelperSearchPaths.map { "\($0)/clawdis" }
let targets = cliHelperSearchPaths.map { "\($0)/clawdbot" }
let result = await self.privilegedSymlink(source: helper.path, targets: targets)
await statusHandler(result)
}

View File

@@ -1,6 +1,6 @@
import AVFoundation
import ClawdisIPC
import ClawdisKit
import ClawdbotIPC
import ClawdbotKit
import CoreGraphics
import Foundation
import OSLog
@@ -36,7 +36,7 @@ actor CameraCaptureService {
}
}
private let logger = Logger(subsystem: "com.clawdis", category: "camera")
private let logger = Logger(subsystem: "com.clawdbot", category: "camera")
func listDevices() -> [CameraDeviceInfo] {
Self.availableCameras().map { device in
@@ -168,7 +168,7 @@ actor CameraCaptureService {
await Self.warmUpCaptureSession()
let tmpMovURL = FileManager.default.temporaryDirectory
.appendingPathComponent("clawdis-camera-\(UUID().uuidString).mov")
.appendingPathComponent("clawdbot-camera-\(UUID().uuidString).mov")
defer { try? FileManager.default.removeItem(at: tmpMovURL) }
let outputURL: URL = {
@@ -176,7 +176,7 @@ actor CameraCaptureService {
return URL(fileURLWithPath: outPath)
}
return FileManager.default.temporaryDirectory
.appendingPathComponent("clawdis-camera-\(UUID().uuidString).mp4")
.appendingPathComponent("clawdbot-camera-\(UUID().uuidString).mp4")
}()
// Ensure we don't fail exporting due to an existing file.

View File

@@ -1,11 +1,11 @@
import AppKit
import ClawdisIPC
import ClawdisKit
import ClawdbotIPC
import ClawdbotKit
import Foundation
import WebKit
final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
static let messageName = "clawdisCanvasA2UIAction"
static let messageName = "clawdbotCanvasA2UIAction"
private let sessionKey: String
@@ -52,7 +52,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
}()
guard !userAction.isEmpty else { return }
guard let name = ClawdisCanvasA2UIAction.extractActionName(userAction) else { return }
guard let name = ClawdbotCanvasA2UIAction.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 = ClawdisCanvasA2UIAction.compactJSON(userAction["context"])
let contextJSON = ClawdbotCanvasA2UIAction.compactJSON(userAction["context"])
// Token-efficient and unambiguous. The agent should treat this as a UI event and (by default) update Canvas.
let messageContext = ClawdisCanvasA2UIAction.AgentMessageContext(
let messageContext = ClawdbotCanvasA2UIAction.AgentMessageContext(
actionName: name,
session: .init(key: self.sessionKey, surfaceId: surfaceId),
component: .init(id: sourceComponentId, host: InstanceIdentity.displayName, instanceId: instanceId),
contextJSON: contextJSON)
let text = ClawdisCanvasA2UIAction.formatAgentMessage(messageContext)
let text = ClawdbotCanvasA2UIAction.formatAgentMessage(messageContext)
Task { [weak webView] in
if AppStateStore.shared.connectionMode == .local {
@@ -90,7 +90,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
await MainActor.run {
guard let webView else { return }
let js = ClawdisCanvasA2UIAction.jsDispatchA2UIActionStatus(
let js = ClawdbotCanvasA2UIAction.jsDispatchA2UIActionStatus(
actionId: actionId,
ok: result.ok,
error: result.error)
@@ -143,5 +143,5 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
return false
}
// Formatting helpers live in ClawdisKit (`ClawdisCanvasA2UIAction`).
// Formatting helpers live in ClawdbotKit (`ClawdbotCanvasA2UIAction`).
}

View File

@@ -10,7 +10,7 @@ final class CanvasFileWatcher: @unchecked Sendable {
init(url: URL, onChange: @escaping () -> Void) {
self.url = url
self.queue = DispatchQueue(label: "com.clawdis.canvaswatcher")
self.queue = DispatchQueue(label: "com.clawdbot.canvaswatcher")
self.onChange = onChange
}

View File

@@ -1,5 +1,5 @@
import AppKit
import ClawdisIPC
import ClawdbotIPC
import Foundation
import OSLog
@@ -7,7 +7,7 @@ import OSLog
final class CanvasManager {
static let shared = CanvasManager()
private static let logger = Logger(subsystem: "com.clawdis", category: "CanvasManager")
private static let logger = Logger(subsystem: "com.clawdbot", category: "CanvasManager")
private var panelController: CanvasWindowController?
private var panelSessionKey: String?
@@ -25,7 +25,7 @@ final class CanvasManager {
private nonisolated static let canvasRoot: URL = {
let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return base.appendingPathComponent("Clawdis/canvas", isDirectory: true)
return base.appendingPathComponent("Clawdbot/canvas", isDirectory: true)
}()
func show(sessionKey: String, path: String? = nil, placement: CanvasPlacement? = nil) throws -> String {
@@ -230,7 +230,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("__clawdis__/a2ui/").absoluteString + "?platform=macos"
return base.appendingPathComponent("__clawdbot__/a2ui/").absoluteString + "?platform=macos"
}
// MARK: - Anchoring

View File

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

View File

@@ -1,9 +1,9 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import OSLog
import WebKit
private let canvasLogger = Logger(subsystem: "com.clawdis", category: "Canvas")
private let canvasLogger = Logger(subsystem: "com.clawdbot", category: "Canvas")
final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
private let root: URL
@@ -222,7 +222,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
let name = fileURL.deletingPathExtension().lastPathComponent
guard !name.isEmpty, !ext.isEmpty else { return nil }
let bundle = ClawdisKitResources.bundle
let bundle = ClawdbotKitResources.bundle
let resourceURL =
bundle.url(forResource: name, withExtension: ext, subdirectory: subdirectory)
?? bundle.url(forResource: name, withExtension: ext)

View File

@@ -1,6 +1,6 @@
import AppKit
let canvasWindowLogger = Logger(subsystem: "com.clawdis", category: "Canvas")
let canvasWindowLogger = Logger(subsystem: "com.clawdbot", category: "Canvas")
enum CanvasLayout {
static let panelSize = NSSize(width: 520, height: 680)

View File

@@ -23,7 +23,7 @@ extension CanvasWindowController {
}
static func storedFrameDefaultsKey(sessionKey: String) -> String {
"clawdis.canvas.frame.\(self.sanitizeSessionKey(sessionKey))"
"clawdbot.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 == "clawdis" {
if scheme == "clawdbot" {
if self.webView.url?.scheme == CanvasScheme.scheme {
Task { await DeepLinkHandler.shared.handle(url: url) }
} else {

View File

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

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdisIPC
import ClawdisKit
import ClawdbotIPC
import ClawdbotKit
import Foundation
import WebKit
@@ -57,8 +57,8 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
(() => {
try {
if (location.protocol !== '\(CanvasScheme.scheme):') return;
if (globalThis.__clawdisA2UIBridgeInstalled) return;
globalThis.__clawdisA2UIBridgeInstalled = true;
if (globalThis.__clawdbotA2UIBridgeInstalled) return;
globalThis.__clawdbotA2UIBridgeInstalled = true;
const deepLinkKey = \(Self.jsStringLiteral(deepLinkKey));
const sessionKey = \(Self.jsStringLiteral(injectedSessionKey));
@@ -85,11 +85,11 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
...(context.length ? { context } : {}),
};
const handler = globalThis.webkit?.messageHandlers?.clawdisCanvasA2UIAction;
const handler = globalThis.webkit?.messageHandlers?.clawdbotCanvasA2UIAction;
// 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.clawdisA2UI || !!document.querySelector('clawdis-a2ui-host');
const hasBundledA2UIHost = !!globalThis.clawdbotA2UI || !!document.querySelector('clawdbot-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 = 'clawdis://agent?' + params.toString();
location.href = 'clawdbot://agent?' + params.toString();
} catch {}
}, true);
} catch {}
@@ -268,7 +268,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
let js = """
(() => {
try {
const api = globalThis.__clawdis;
const api = globalThis.__clawdbot;
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/clawdis-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
path = "/tmp/clawdbot-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
}
try png.write(to: URL(fileURLWithPath: path), options: [.atomic])

View File

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

View File

@@ -1,6 +1,6 @@
import Foundation
enum ClawdisEnv {
enum ClawdbotEnv {
static func path(_ key: String) -> String? {
// Normalize env overrides once so UI + file IO stay consistent.
guard let value = ProcessInfo.processInfo.environment[key]?
@@ -13,23 +13,23 @@ enum ClawdisEnv {
}
}
enum ClawdisPaths {
private static let configPathEnv = "CLAWDIS_CONFIG_PATH"
private static let stateDirEnv = "CLAWDIS_STATE_DIR"
enum ClawdbotPaths {
private static let configPathEnv = "CLAWDBOT_CONFIG_PATH"
private static let stateDirEnv = "CLAWDBOT_STATE_DIR"
static var stateDirURL: URL {
if let override = ClawdisEnv.path(self.stateDirEnv) {
if let override = ClawdbotEnv.path(self.stateDirEnv) {
return URL(fileURLWithPath: override, isDirectory: true)
}
return FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdis", isDirectory: true)
.appendingPathComponent(".clawdbot", isDirectory: true)
}
static var configURL: URL {
if let override = ClawdisEnv.path(self.configPathEnv) {
if let override = ClawdbotEnv.path(self.configPathEnv) {
return URL(fileURLWithPath: override)
}
return self.stateDirURL.appendingPathComponent("clawdis.json")
return self.stateDirURL.appendingPathComponent("clawdbot.json")
}
static var workspaceURL: URL {

View File

@@ -1,13 +1,13 @@
import Foundation
enum CommandResolver {
private static let projectRootDefaultsKey = "clawdis.gatewayProjectRootPath"
private static let helperName = "clawdis"
private static let projectRootDefaultsKey = "clawdbot.gatewayProjectRootPath"
private static let helperName = "clawdbot"
static func gatewayEntrypoint(in root: URL) -> String? {
let distEntry = root.appendingPathComponent("dist/index.js").path
if FileManager.default.isReadableFile(atPath: distEntry) { return distEntry }
let binEntry = root.appendingPathComponent("bin/clawdis.js").path
let binEntry = root.appendingPathComponent("bin/clawdbot.js").path
if FileManager.default.isReadableFile(atPath: binEntry) { return binEntry }
return nil
}
@@ -36,9 +36,9 @@ enum CommandResolver {
static func errorCommand(with message: String) -> [String] {
let script = """
cat <<'__CLAWDIS_ERR__' >&2
cat <<'__CLAWDBOT_ERR__' >&2
\(message)
__CLAWDIS_ERR__
__CLAWDBOT_ERR__
exit 1
"""
return ["/bin/sh", "-c", script]
@@ -52,7 +52,7 @@ enum CommandResolver {
return url
}
let fallback = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("Projects/clawdis")
.appendingPathComponent("Projects/clawdbot")
if FileManager.default.fileExists(atPath: fallback.path) {
return fallback
}
@@ -166,23 +166,23 @@ enum CommandResolver {
return nil
}
static func clawdisExecutable(searchPaths: [String]? = nil) -> String? {
static func clawdbotExecutable(searchPaths: [String]? = nil) -> String? {
self.findExecutable(named: self.helperName, searchPaths: searchPaths)
}
static func projectClawdisExecutable(projectRoot: URL? = nil) -> String? {
static func projectClawdbotExecutable(projectRoot: URL? = nil) -> String? {
let root = projectRoot ?? self.projectRoot()
let candidate = root.appendingPathComponent("node_modules/.bin").appendingPathComponent(self.helperName).path
return FileManager.default.isExecutableFile(atPath: candidate) ? candidate : nil
}
static func nodeCliPath() -> String? {
let candidate = self.projectRoot().appendingPathComponent("bin/clawdis.js").path
let candidate = self.projectRoot().appendingPathComponent("bin/clawdbot.js").path
return FileManager.default.isReadableFile(atPath: candidate) ? candidate : nil
}
static func hasAnyClawdisInvoker(searchPaths: [String]? = nil) -> Bool {
if self.clawdisExecutable(searchPaths: searchPaths) != nil { return true }
static func hasAnyClawdbotInvoker(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,
self.nodeCliPath() != nil
@@ -192,7 +192,7 @@ enum CommandResolver {
return false
}
static func clawdisNodeCommand(
static func clawdbotNodeCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
@@ -212,8 +212,8 @@ enum CommandResolver {
switch runtimeResult {
case let .success(runtime):
let root = self.projectRoot()
if let clawdisPath = self.projectClawdisExecutable(projectRoot: root) {
return [clawdisPath, subcommand] + extraArgs
if let clawdbotPath = self.projectClawdbotExecutable(projectRoot: root) {
return [clawdbotPath, subcommand] + extraArgs
}
if let entry = self.gatewayEntrypoint(in: root) {
@@ -225,14 +225,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", "clawdis", subcommand] + extraArgs
return [pnpm, "--silent", "clawdbot", subcommand] + extraArgs
}
if let clawdisPath = self.clawdisExecutable(searchPaths: searchPaths) {
return [clawdisPath, subcommand] + extraArgs
if let clawdbotPath = self.clawdbotExecutable(searchPaths: searchPaths) {
return [clawdbotPath, subcommand] + extraArgs
}
let missingEntry = """
clawdis entrypoint missing (looked for dist/index.js or bin/clawdis.js); run pnpm build.
clawdbot entrypoint missing (looked for dist/index.js or bin/clawdbot.js); run pnpm build.
"""
return self.errorCommand(with: missingEntry)
@@ -241,14 +241,14 @@ enum CommandResolver {
}
}
// Existing callers still refer to clawdisCommand; keep it as node alias.
static func clawdisCommand(
// Existing callers still refer to clawdbotCommand; keep it as node alias.
static func clawdbotCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
searchPaths: [String]? = nil) -> [String]
{
self.clawdisNodeCommand(
self.clawdbotNodeCommand(
subcommand: subcommand,
extraArgs: extraArgs,
defaults: defaults,
@@ -274,7 +274,7 @@ enum CommandResolver {
let userHost = parsed.user.map { "\($0)@\(parsed.host)" } ?? parsed.host
args.append(userHost)
// Run the real clawdis CLI on the remote host.
// Run the real clawdbot CLI on the remote host.
let exportedPath = [
"/opt/homebrew/bin",
"/usr/local/bin",
@@ -291,7 +291,7 @@ enum CommandResolver {
let projectSection = if userPRJ.isEmpty {
"""
DEFAULT_PRJ="$HOME/Projects/clawdis"
DEFAULT_PRJ="$HOME/Projects/clawdbot"
if [ -d "$DEFAULT_PRJ" ]; then
PRJ="$DEFAULT_PRJ"
cd "$PRJ" || { echo "Project root not found: $PRJ"; exit 127; }
@@ -330,9 +330,9 @@ enum CommandResolver {
CLI="";
\(cliSection)
\(projectSection)
if command -v clawdis >/dev/null 2>&1; then
CLI="$(command -v clawdis)"
clawdis \(quotedArgs);
if command -v clawdbot >/dev/null 2>&1; then
CLI="$(command -v clawdbot)"
clawdbot \(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"
@@ -340,18 +340,18 @@ enum CommandResolver {
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/clawdis.js" ]; then
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/clawdbot.js" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/bin/clawdis.js"
node "$PRJ/bin/clawdis.js" \(quotedArgs);
CLI="node $PRJ/bin/clawdbot.js"
node "$PRJ/bin/clawdbot.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 clawdis"
pnpm --silent clawdis \(quotedArgs);
CLI="pnpm --silent clawdbot"
pnpm --silent clawdbot \(quotedArgs);
else
echo "clawdis CLI missing on remote host"; exit 127;
echo "clawdbot CLI missing on remote host"; exit 127;
fi
"""
args.append(contentsOf: ["/bin/sh", "-c", scriptBody])
@@ -372,7 +372,7 @@ enum CommandResolver {
if let modeRaw {
mode = AppState.ConnectionMode(rawValue: modeRaw) ?? .local
} else {
let seen = defaults.bool(forKey: "clawdis.onboardingSeen")
let seen = defaults.bool(forKey: "clawdbot.onboardingSeen")
mode = seen ? .local : .unconfigured
}
let target = defaults.string(forKey: remoteTargetKey) ?? ""

View File

@@ -13,7 +13,7 @@ final class ConfigFileWatcher: @unchecked Sendable {
init(url: URL, onChange: @escaping () -> Void) {
self.url = url
self.queue = DispatchQueue(label: "com.clawdis.configwatcher")
self.queue = DispatchQueue(label: "com.clawdbot.configwatcher")
self.onChange = onChange
self.watchedDir = url.deletingLastPathComponent()
self.targetPath = url.path

View File

@@ -25,13 +25,13 @@ struct ConfigSettings: View {
@State private var heartbeatMinutes: Int?
@State private var heartbeatBody: String = "HEARTBEAT"
// clawd browser settings (stored in ~/.clawdis/clawdis.json under "browser")
// clawd browser settings (stored in ~/.clawdbot/clawdbot.json under "browser")
@State private var browserEnabled: Bool = true
@State private var browserControlUrl: String = "http://127.0.0.1:18791"
@State private var browserColorHex: String = "#FF4500"
@State private var browserAttachOnly: Bool = false
// Talk mode settings (stored in ~/.clawdis/clawdis.json under "talk")
// Talk mode settings (stored in ~/.clawdbot/clawdbot.json under "talk")
@State private var talkVoiceId: String = ""
@State private var talkInterruptOnSpeech: Bool = true
@State private var talkApiKey: String = ""
@@ -91,11 +91,11 @@ struct ConfigSettings: View {
@ViewBuilder
private var header: some View {
Text("Clawdis CLI config")
Text("Clawdbot CLI config")
.font(.title3.weight(.semibold))
Text(self.isNixMode
? "This tab is read-only in Nix mode. Edit config via Nix and rebuild."
: "Edit ~/.clawdis/clawdis.json (agent / session / routing / messages).")
: "Edit ~/.clawdbot/clawdbot.json (agent / session / routing / messages).")
.font(.callout)
.foregroundStyle(.secondary)
}
@@ -181,7 +181,7 @@ struct ConfigSettings: View {
}
private var anthropicAuthHelpText: String {
"Determined from Clawdis OAuth token file (~/.clawdis/credentials/oauth.json) " +
"Determined from Clawdbot OAuth token file (~/.clawdbot/credentials/oauth.json) " +
"or environment variables (ANTHROPIC_OAUTH_TOKEN / ANTHROPIC_API_KEY)."
}

View File

@@ -39,7 +39,7 @@ enum ConfigStore {
if let override = overrides.loadLocal {
return override()
}
return ClawdisConfigFile.loadDict()
return ClawdbotConfigFile.loadDict()
}
@MainActor
@@ -55,7 +55,7 @@ enum ConfigStore {
if let override = overrides.saveLocal {
override(root)
} else {
ClawdisConfigFile.saveDict(root)
ClawdbotConfigFile.saveDict(root)
}
}
}

View File

@@ -5,7 +5,7 @@ import OSLog
final class ConnectionModeCoordinator {
static let shared = ConnectionModeCoordinator()
private let logger = Logger(subsystem: "com.clawdis", category: "connection")
private let logger = Logger(subsystem: "com.clawdbot", category: "connection")
/// Apply the requested connection mode by starting/stopping local gateway,
/// managing the control-channel SSH tunnel, and cleaning up chat windows/panels.

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
import Observation
@@ -412,7 +412,7 @@ final class ConnectionsStore {
params: nil,
timeoutMs: 10000)
self.configStatus = snap.valid == false
? "Config invalid; fix it in ~/.clawdis/clawdis.json."
? "Config invalid; fix it in ~/.clawdbot/clawdbot.json."
: nil
self.configRoot = snap.config?.mapValues { $0.foundationValue } ?? [:]
self.configLoaded = true
@@ -695,7 +695,7 @@ final class ConnectionsStore {
method: .configSet,
params: params,
timeoutMs: 10000)
self.configStatus = "Saved to ~/.clawdis/clawdis.json."
self.configStatus = "Saved to ~/.clawdbot/clawdbot.json."
await self.refresh(probe: true)
} catch {
self.configStatus = error.localizedDescription
@@ -904,7 +904,7 @@ final class ConnectionsStore {
method: .configSet,
params: params,
timeoutMs: 10000)
self.configStatus = "Saved to ~/.clawdis/clawdis.json."
self.configStatus = "Saved to ~/.clawdbot/clawdbot.json."
await self.refresh(probe: true)
} catch {
self.configStatus = error.localizedDescription
@@ -1026,7 +1026,7 @@ final class ConnectionsStore {
method: .configSet,
params: params,
timeoutMs: 10000)
self.configStatus = "Saved to ~/.clawdis/clawdis.json."
self.configStatus = "Saved to ~/.clawdbot/clawdbot.json."
await self.refresh(probe: true)
} catch {
self.configStatus = error.localizedDescription
@@ -1118,7 +1118,7 @@ final class ConnectionsStore {
method: .configSet,
params: params,
timeoutMs: 10000)
self.configStatus = "Saved to ~/.clawdis/clawdis.json."
self.configStatus = "Saved to ~/.clawdbot/clawdbot.json."
await self.refresh(probe: true)
} catch {
self.configStatus = error.localizedDescription

View File

@@ -0,0 +1,39 @@
import Foundation
let launchdLabel = "com.clawdbot.mac"
let gatewayLaunchdLabel = "com.clawdbot.gateway"
let onboardingVersionKey = "clawdbot.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 defaultVoiceWakeTriggers = ["clawd", "claude"]
let voiceWakeMicKey = "clawdbot.voiceWakeMicID"
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 locationModeKey = "clawdbot.locationMode"
let locationPreciseKey = "clawdbot.locationPreciseEnabled"
let peekabooBridgeEnabledKey = "clawdbot.peekabooBridgeEnabled"
let deepLinkKeyKey = "clawdbot.deepLinkKey"
let modelCatalogPathKey = "clawdbot.modelCatalogPath"
let modelCatalogReloadKey = "clawdbot.modelCatalogReload"
let attachExistingGatewayOnlyKey = "clawdbot.gateway.attachExistingOnly"
let heartbeatsEnabledKey = "clawdbot.heartbeatsEnabled"
let debugFileLogEnabledKey = "clawdbot.debug.fileLogEnabled"
let appLogLevelKey = "clawdbot.debug.appLogLevel"
let voiceWakeSupported: Bool = ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 26
let cliHelperSearchPaths = ["/usr/local/bin", "/opt/homebrew/bin"]

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
import Observation
import SwiftUI
@@ -73,7 +73,7 @@ final class ControlChannel {
}
private(set) var lastPingMs: Double?
private let logger = Logger(subsystem: "com.clawdis", category: "control")
private let logger = Logger(subsystem: "com.clawdbot", category: "control")
private var eventTask: Task<Void, Never>?
private var recoveryTask: Task<Void, Never>?
@@ -180,7 +180,7 @@ final class ControlChannel {
{
let reason = urlErr.failureURLString ?? urlErr.localizedDescription
return
"Gateway rejected token; set CLAWDIS_GATEWAY_TOKEN in the mac app environment " +
"Gateway rejected token; set CLAWDBOT_GATEWAY_TOKEN in the mac app environment " +
"or clear it on the gateway. " +
"Reason: \(reason)"
}
@@ -360,6 +360,6 @@ final class ControlChannel {
}
extension Notification.Name {
static let controlHeartbeat = Notification.Name("clawdis.control.heartbeat")
static let controlAgentEvent = Notification.Name("clawdis.control.agent")
static let controlHeartbeat = Notification.Name("clawdbot.control.heartbeat")
static let controlAgentEvent = Notification.Name("clawdbot.control.agent")
}

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
import Observation
import OSLog
@@ -21,7 +21,7 @@ final class CronJobsStore {
var lastError: String?
var statusMessage: String?
private let logger = Logger(subsystem: "com.clawdis", category: "cron.ui")
private let logger = Logger(subsystem: "com.clawdbot", category: "cron.ui")
private var refreshTask: Task<Void, Never>?
private var runsTask: Task<Void, Never>?
private var eventTask: Task<Void, Never>?

View File

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

View File

@@ -3,7 +3,7 @@ import Foundation
import SwiftUI
enum DebugActions {
private static let verboseDefaultsKey = "clawdis.debug.verboseMain"
private static let verboseDefaultsKey = "clawdbot.debug.verboseMain"
private static let sessionMenuLimit = 12
@MainActor
@@ -39,7 +39,7 @@ enum DebugActions {
static func openConfigFolder() {
let url = FileManager.default
.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdis", isDirectory: true)
.appendingPathComponent(".clawdbot", isDirectory: true)
NSWorkspace.shared.activateFileViewerSelecting([url])
}
@@ -62,7 +62,7 @@ enum DebugActions {
}
static func sendTestNotification() async {
_ = await NotificationManager().send(title: "Clawdis", body: "Test notification", sound: nil)
_ = await NotificationManager().send(title: "Clawdbot", body: "Test notification", sound: nil)
}
static func sendDebugVoice() async -> Result<String, DebugActionError> {
@@ -187,7 +187,7 @@ enum DebugActions {
private static func resolveSessionStorePath() -> String {
let defaultPath = SessionLoader.defaultStorePath
let configURL = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdis/clawdis.json")
.appendingPathComponent(".clawdbot/clawdbot.json")
guard
let data = try? Data(contentsOf: configURL),
let parsed = try? JSONSerialization.jsonObject(with: data) as? [String: Any],

View File

@@ -176,7 +176,7 @@ struct DebugSettings: View {
Button("Copy sample URL") {
let msg = "Hello from deep link"
let encoded = msg.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? msg
let url = "clawdis://agent?message=\(encoded)&key=\(key)"
let url = "clawdbot://agent?message=\(encoded)&key=\(key)"
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(url, forType: .string)
}
@@ -184,7 +184,7 @@ struct DebugSettings: View {
Spacer(minLength: 0)
}
Text("Deep links (clawdis://…) are always enabled; the key controls unattended runs.")
Text("Deep links (clawdbot://…) are always enabled; the key controls unattended runs.")
.font(.caption2)
.foregroundStyle(.secondary)
@@ -247,7 +247,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/Clawdis/. " +
"Writes a rotating, local-only log under ~/Library/Logs/Clawdbot/. " +
"Enable only while actively debugging.")
HStack(spacing: 8) {
@@ -355,10 +355,10 @@ struct DebugSettings: View {
GroupBox("Paths") {
VStack(alignment: .leading, spacing: 12) {
VStack(alignment: .leading, spacing: 6) {
Text("Clawdis project root")
Text("Clawdbot project root")
.font(.caption.weight(.semibold))
HStack(spacing: 8) {
TextField("Path to clawdis repo", text: self.$gatewayRootInput)
TextField("Path to clawdbot repo", text: self.$gatewayRootInput)
.textFieldStyle(.roundedBorder)
.font(.caption.monospaced())
.onSubmit { self.saveRelayRoot() }
@@ -366,7 +366,7 @@ struct DebugSettings: View {
.buttonStyle(.borderedProminent)
Button("Reset") {
let def = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("Projects/clawdis").path
.appendingPathComponent("Projects/clawdbot").path
self.gatewayRootInput = def
self.saveRelayRoot()
}
@@ -396,7 +396,7 @@ struct DebugSettings: View {
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Used by the CLI session loader; stored in ~/.clawdis/clawdis.json.")
Text("Used by the CLI session loader; stored in ~/.clawdbot/clawdbot.json.")
.font(.footnote)
.foregroundStyle(.secondary)
}
@@ -787,8 +787,8 @@ struct DebugSettings: View {
private func configURL() -> URL {
FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdis")
.appendingPathComponent("clawdis.json")
.appendingPathComponent(".clawdbot")
.appendingPathComponent("clawdbot.json")
}
}
@@ -937,7 +937,7 @@ extension DebugSettings {
view.modelsCount = 3
view.modelsLoading = false
view.modelsError = "Failed to load models"
view.gatewayRootInput = "/tmp/clawdis"
view.gatewayRootInput = "/tmp/clawdbot"
view.sessionStorePath = "/tmp/sessions.json"
view.sessionStoreSaveError = "Save failed"
view.debugSendInFlight = true

View File

@@ -1,10 +1,10 @@
import AppKit
import ClawdisKit
import ClawdbotKit
import Foundation
import OSLog
import Security
private let deepLinkLogger = Logger(subsystem: "com.clawdis", category: "DeepLink")
private let deepLinkLogger = Logger(subsystem: "com.clawdbot", category: "DeepLink")
@MainActor
final class DeepLinkHandler {
@@ -23,7 +23,7 @@ final class DeepLinkHandler {
return
}
guard !AppStateStore.shared.isPaused else {
self.presentAlert(title: "Clawdis is paused", message: "Unpause Clawdis to run agent actions.")
self.presentAlert(title: "Clawdbot is paused", message: "Unpause Clawdbot 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 Clawdis agent?", message: body) else { return }
guard self.confirm(title: "Run Clawdbot agent?", message: body) else { return }
}
if AppStateStore.shared.connectionMode == .local {

View File

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

View File

@@ -6,7 +6,7 @@ final class DockIconManager: NSObject, @unchecked Sendable {
static let shared = DockIconManager()
private var windowsObservation: NSKeyValueObservation?
private let logger = Logger(subsystem: "com.clawdis", category: "DockIconManager")
private let logger = Logger(subsystem: "com.clawdbot", category: "DockIconManager")
override private init() {
super.init()

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
import OSLog
@@ -55,10 +55,10 @@ struct WebSocketSessionBox: @unchecked Sendable {
}
// Avoid ambiguity with the app's own AnyCodable type.
private typealias ProtoAnyCodable = ClawdisProtocol.AnyCodable
private typealias ProtoAnyCodable = ClawdbotProtocol.AnyCodable
actor GatewayChannelActor {
private let logger = Logger(subsystem: "com.clawdis", category: "gateway")
private let logger = Logger(subsystem: "com.clawdbot", category: "gateway")
private var task: WebSocketTaskBox?
private var pending: [String: CheckedContinuation<GatewayFrame, Error>] = [:]
private var connected = false

View File

@@ -1,9 +1,9 @@
import ClawdisChatUI
import ClawdisProtocol
import ClawdbotChatUI
import ClawdbotProtocol
import Foundation
import OSLog
private let gatewayConnectionLogger = Logger(subsystem: "com.clawdis", category: "gateway.connection")
private let gatewayConnectionLogger = Logger(subsystem: "com.clawdbot", category: "gateway.connection")
enum GatewayAgentChannel: String, Codable, CaseIterable, Sendable {
case last
@@ -416,7 +416,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(ClawdisGatewayHealthOK.self, from: data))?.ok ?? true
return (try? self.decoder.decode(ClawdbotGatewayHealthOK.self, from: data))?.ok ?? true
}
// MARK: - Skills
@@ -460,7 +460,7 @@ extension GatewayConnection {
func chatHistory(
sessionKey: String,
limit: Int? = nil,
timeoutMs: Int? = nil) async throws -> ClawdisChatHistoryPayload
timeoutMs: Int? = nil) async throws -> ClawdbotChatHistoryPayload
{
var params: [String: AnyCodable] = ["sessionKey": AnyCodable(sessionKey)]
if let limit { params["limit"] = AnyCodable(limit) }
@@ -476,8 +476,8 @@ extension GatewayConnection {
message: String,
thinking: String,
idempotencyKey: String,
attachments: [ClawdisChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> ClawdisChatSendResponse
attachments: [ClawdbotChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> ClawdbotChatSendResponse
{
var params: [String: AnyCodable] = [
"sessionKey": AnyCodable(sessionKey),

View File

@@ -129,6 +129,6 @@ struct GatewayDiscoveryMenu: View {
} label: {
Image(systemName: "dot.radiowaves.left.and.right")
}
.help("Discover Clawdis bridges on your LAN")
.help("Discover Clawdbot bridges on your LAN")
}
}

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Network
import Observation
@@ -34,7 +34,7 @@ final class GatewayDiscoveryModel {
private var localIdentity: LocalIdentity
private var resolvedTXTByID: [String: [String: String]] = [:]
private var pendingTXTResolvers: [String: GatewayTXTResolver] = [:]
private let logger = Logger(subsystem: "com.clawdis", category: "gateway-discovery")
private let logger = Logger(subsystem: "com.clawdbot", category: "gateway-discovery")
init() {
self.localIdentity = Self.buildLocalIdentityFast()
@@ -44,11 +44,11 @@ final class GatewayDiscoveryModel {
func start() {
if !self.browsers.isEmpty { return }
for domain in ClawdisBonjour.bridgeServiceDomains {
for domain in ClawdbotBonjour.bridgeServiceDomains {
let params = NWParameters.tcp
params.includePeerToPeer = true
let browser = NWBrowser(
for: .bonjour(type: ClawdisBonjour.bridgeServiceType, domain: domain),
for: .bonjour(type: ClawdbotBonjour.bridgeServiceType, domain: domain),
using: params)
browser.stateUpdateHandler = { [weak self] state in
@@ -69,7 +69,7 @@ final class GatewayDiscoveryModel {
}
self.browsers[domain] = browser
browser.start(queue: DispatchQueue(label: "com.clawdis.macos.gateway-discovery.\(domain)"))
browser.start(queue: DispatchQueue(label: "com.clawdbot.macos.gateway-discovery.\(domain)"))
}
}
@@ -279,7 +279,7 @@ final class GatewayDiscoveryModel {
private nonisolated static func prettifyInstanceName(_ decodedName: String) -> String {
let normalized = decodedName.split(whereSeparator: \.isWhitespace).joined(separator: " ")
let stripped = normalized.replacingOccurrences(of: " (Clawdis)", with: "")
let stripped = normalized.replacingOccurrences(of: " (Clawdbot)", with: "")
.replacingOccurrences(of: #"\s+\(\d+\)$"#, with: "", options: .regularExpression)
return stripped.trimmingCharacters(in: .whitespacesAndNewlines)
}

View File

@@ -24,9 +24,9 @@ actor GatewayEndpointStore {
static let live = Deps(
mode: { await MainActor.run { AppStateStore.shared.connectionMode } },
token: { ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_TOKEN"] },
token: { ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_TOKEN"] },
password: {
let root = ClawdisConfigFile.loadDict()
let root = ClawdbotConfigFile.loadDict()
return GatewayEndpointStore.resolveGatewayPassword(
isRemote: CommandResolver.connectionModeIsRemote(),
root: root,
@@ -42,7 +42,7 @@ actor GatewayEndpointStore {
root: [String: Any],
env: [String: String]
) -> String? {
let raw = env["CLAWDIS_GATEWAY_PASSWORD"] ?? ""
let raw = env["CLAWDBOT_GATEWAY_PASSWORD"] ?? ""
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
@@ -72,7 +72,7 @@ actor GatewayEndpointStore {
}
private let deps: Deps
private let logger = Logger(subsystem: "com.clawdis", category: "gateway-endpoint")
private let logger = Logger(subsystem: "com.clawdbot", category: "gateway-endpoint")
private var state: GatewayEndpointState
private var subscribers: [UUID: AsyncStream<GatewayEndpointState>.Continuation] = [:]
@@ -84,7 +84,7 @@ actor GatewayEndpointStore {
if let modeRaw {
initialMode = AppState.ConnectionMode(rawValue: modeRaw) ?? .local
} else {
let seen = UserDefaults.standard.bool(forKey: "clawdis.onboardingSeen")
let seen = UserDefaults.standard.bool(forKey: "clawdbot.onboardingSeen")
initialMode = seen ? .local : .unconfigured
}

View File

@@ -1,4 +1,4 @@
import ClawdisIPC
import ClawdbotIPC
import Foundation
import OSLog
@@ -62,21 +62,21 @@ struct GatewayCommandResolution {
}
enum GatewayEnvironment {
private static let logger = Logger(subsystem: "com.clawdis", category: "gateway.env")
private static let logger = Logger(subsystem: "com.clawdbot", category: "gateway.env")
private static let supportedBindModes: Set<String> = ["loopback", "tailnet", "lan", "auto"]
static func bundledGatewayExecutable() -> String? {
guard let res = Bundle.main.resourceURL else { return nil }
let path = res.appendingPathComponent("Relay/clawdis").path
let path = res.appendingPathComponent("Relay/clawdbot").path
return FileManager.default.isExecutableFile(atPath: path) ? path : nil
}
static func gatewayPort() -> Int {
if let raw = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_PORT"] {
if let raw = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_PORT"] {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if let parsed = Int(trimmed), parsed > 0 { return parsed }
}
if let configPort = ClawdisConfigFile.gatewayPort(), configPort > 0 {
if let configPort = ClawdbotConfigFile.gatewayPort(), configPort > 0 {
return configPort
}
let stored = UserDefaults.standard.integer(forKey: "gatewayPort")
@@ -139,7 +139,7 @@ enum GatewayEnvironment {
requiredGateway: expected?.description,
message: RuntimeLocator.describeFailure(err))
case let .success(runtime):
let gatewayBin = CommandResolver.clawdisExecutable()
let gatewayBin = CommandResolver.clawdbotExecutable()
if gatewayBin == nil, projectEntrypoint == nil {
return GatewayEnvironmentStatus(
@@ -147,7 +147,7 @@ enum GatewayEnvironment {
nodeVersion: runtime.version.description,
gatewayVersion: nil,
requiredGateway: expected?.description,
message: "clawdis CLI not found in PATH; install the global package.")
message: "clawdbot CLI not found in PATH; install the global package.")
}
let installed = gatewayBin.flatMap { self.readGatewayVersion(binary: $0) }
@@ -196,7 +196,7 @@ enum GatewayEnvironment {
let projectRoot = CommandResolver.projectRoot()
let projectEntrypoint = CommandResolver.gatewayEntrypoint(in: projectRoot)
let status = self.check()
let gatewayBin = CommandResolver.clawdisExecutable()
let gatewayBin = CommandResolver.clawdbotExecutable()
let bundled = self.bundledGatewayExecutable()
let runtime = RuntimeLocator.resolve(searchPaths: CommandResolver.preferredPaths())
@@ -229,14 +229,14 @@ enum GatewayEnvironment {
if CommandResolver.connectionModeIsRemote() {
return nil
}
if let env = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_BIND"] {
if let env = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_BIND"] {
let trimmed = env.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if self.supportedBindModes.contains(trimmed) {
return trimmed
}
}
let root = ClawdisConfigFile.loadDict()
let root = ClawdbotConfigFile.loadDict()
if let gateway = root["gateway"] as? [String: Any],
let bind = gateway["bind"] as? String
{
@@ -257,16 +257,16 @@ enum GatewayEnvironment {
let bun = CommandResolver.findExecutable(named: "bun")
let (label, cmd): (String, [String]) =
if let npm {
("npm", [npm, "install", "-g", "clawdis@\(target)"])
("npm", [npm, "install", "-g", "clawdbot@\(target)"])
} else if let pnpm {
("pnpm", [pnpm, "add", "-g", "clawdis@\(target)"])
("pnpm", [pnpm, "add", "-g", "clawdbot@\(target)"])
} else if let bun {
("bun", [bun, "add", "-g", "clawdis@\(target)"])
("bun", [bun, "add", "-g", "clawdbot@\(target)"])
} else {
("npm", ["npm", "install", "-g", "clawdis@\(target)"])
("npm", ["npm", "install", "-g", "clawdbot@\(target)"])
}
statusHandler("Installing clawdis@\(target) via \(label)")
statusHandler("Installing clawdbot@\(target) via \(label)")
func summarize(_ text: String) -> String? {
let lines = text
@@ -280,7 +280,7 @@ enum GatewayEnvironment {
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: ["PATH": preferred], timeout: 300)
if response.success {
statusHandler("Installed clawdis@\(target)")
statusHandler("Installed clawdbot@\(target)")
} else {
if response.timedOut {
statusHandler("Install failed: timed out. Check your internet connection and try again.")

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
/// Structured error surfaced when the gateway responds with `{ ok: false }`.

View File

@@ -1,9 +1,9 @@
import Foundation
enum GatewayLaunchAgentManager {
private static let logger = Logger(subsystem: "com.clawdis", category: "gateway.launchd")
private static let logger = Logger(subsystem: "com.clawdbot", category: "gateway.launchd")
private static let supportedBindModes: Set<String> = ["loopback", "tailnet", "lan", "auto"]
private static let legacyGatewayLaunchdLabel = "com.steipete.clawdis.gateway"
private static let legacyGatewayLaunchdLabel = "com.steipete.clawdbot.gateway"
private static var plistURL: URL {
FileManager.default.homeDirectoryForCurrentUser
@@ -16,7 +16,7 @@ enum GatewayLaunchAgentManager {
}
private static func gatewayExecutablePath(bundlePath: String) -> String {
"\(bundlePath)/Contents/Resources/Relay/clawdis"
"\(bundlePath)/Contents/Resources/Relay/clawdbot"
}
private static func relayDir(bundlePath: String) -> String {
@@ -26,7 +26,7 @@ enum GatewayLaunchAgentManager {
private static func gatewayProgramArguments(bundlePath: String, port: Int, bind: String) -> [String] {
#if DEBUG
let projectRoot = CommandResolver.projectRoot()
if let localBin = CommandResolver.projectClawdisExecutable(projectRoot: projectRoot) {
if let localBin = CommandResolver.projectClawdbotExecutable(projectRoot: projectRoot) {
return [localBin, "gateway", "--port", "\(port)", "--bind", bind]
}
if let entry = CommandResolver.gatewayEntrypoint(in: projectRoot),
@@ -96,20 +96,20 @@ enum GatewayLaunchAgentManager {
var envEntries = """
<key>PATH</key>
<string>\(preferredPath)</string>
<key>CLAWDIS_IMAGE_BACKEND</key>
<key>CLAWDBOT_IMAGE_BACKEND</key>
<string>sips</string>
"""
if let token {
let escapedToken = self.escapePlistValue(token)
envEntries += """
<key>CLAWDIS_GATEWAY_TOKEN</key>
<key>CLAWDBOT_GATEWAY_TOKEN</key>
<string>\(escapedToken)</string>
"""
}
if let password {
let escapedPassword = self.escapePlistValue(password)
envEntries += """
<key>CLAWDIS_GATEWAY_PASSWORD</key>
<key>CLAWDBOT_GATEWAY_PASSWORD</key>
<string>\(escapedPassword)</string>
"""
}
@@ -155,14 +155,14 @@ enum GatewayLaunchAgentManager {
if CommandResolver.connectionModeIsRemote() {
return nil
}
if let env = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_BIND"] {
if let env = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_BIND"] {
let trimmed = env.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if self.supportedBindModes.contains(trimmed) {
return trimmed
}
}
let root = ClawdisConfigFile.loadDict()
let root = ClawdbotConfigFile.loadDict()
if let gateway = root["gateway"] as? [String: Any],
let bind = gateway["bind"] as? String
{
@@ -176,20 +176,20 @@ enum GatewayLaunchAgentManager {
}
private static func preferredGatewayToken() -> String? {
let raw = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_TOKEN"] ?? ""
let raw = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_TOKEN"] ?? ""
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.isEmpty ? nil : trimmed
}
private static func preferredGatewayPassword() -> String? {
// First check environment variable
let raw = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_PASSWORD"] ?? ""
let raw = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_PASSWORD"] ?? ""
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
// Then check config file (gateway.auth.password)
let root = ClawdisConfigFile.loadDict()
let root = ClawdbotConfigFile.loadDict()
if let gateway = root["gateway"] as? [String: Any],
let auth = gateway["auth"] as? [String: Any],
let password = auth["password"] as? String

View File

@@ -1,13 +1,13 @@
import ClawdisProtocol
import ClawdbotProtocol
import Foundation
enum GatewayPayloadDecoding {
static func decode<T: Decodable>(_ payload: ClawdisProtocol.AnyCodable, as _: T.Type = T.self) throws -> T {
static func decode<T: Decodable>(_ payload: ClawdbotProtocol.AnyCodable, as _: T.Type = T.self) throws -> T {
let data = try JSONEncoder().encode(payload)
return try JSONDecoder().decode(T.self, from: data)
}
static func decodeIfPresent<T: Decodable>(_ payload: ClawdisProtocol.AnyCodable?, as _: T.Type = T.self) throws
static func decodeIfPresent<T: Decodable>(_ payload: ClawdbotProtocol.AnyCodable?, as _: T.Type = T.self) throws
-> T?
{
guard let payload else { return nil }

View File

@@ -42,7 +42,7 @@ final class GatewayProcessManager {
private var environmentRefreshTask: Task<Void, Never>?
private var lastEnvironmentRefresh: Date?
private var logRefreshTask: Task<Void, Never>?
private let logger = Logger(subsystem: "com.clawdis", category: "gateway.process")
private let logger = Logger(subsystem: "com.clawdbot", category: "gateway.process")
private let logLimit = 20000 // characters to keep in-memory
private let environmentRefreshMinInterval: TimeInterval = 30
@@ -239,7 +239,7 @@ final class GatewayProcessManager {
let lower = message.lowercased()
if self.isGatewayAuthFailure(error) {
return """
Gateway on port \(port) rejected auth. Set CLAWDIS_GATEWAY_TOKEN in the app \
Gateway on port \(port) rejected auth. Set CLAWDBOT_GATEWAY_TOKEN in the app \
to match the running gateway (or clear it on the gateway) and retry.
"""
}

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
// The generated gateway protocol models are value types, but they don't currently declare Sendable.
// We use them across actors via GatewayConnection's event stream, so mark them as unchecked.

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
/// Server-push messages from the gateway websocket.
///

View File

@@ -1,6 +1,6 @@
import AppKit
import ClawdisIPC
import ClawdisKit
import ClawdbotIPC
import ClawdbotKit
import CoreLocation
import Observation
import SwiftUI
@@ -8,7 +8,7 @@ import SwiftUI
struct GeneralSettings: View {
@Bindable var state: AppState
@AppStorage(cameraEnabledKey) private var cameraEnabled: Bool = false
@AppStorage(locationModeKey) private var locationModeRaw: String = ClawdisLocationMode.off.rawValue
@AppStorage(locationModeKey) private var locationModeRaw: String = ClawdbotLocationMode.off.rawValue
@AppStorage(locationPreciseKey) private var locationPreciseEnabled: Bool = true
private let healthStore = HealthStore.shared
private let gatewayManager = GatewayProcessManager.shared
@@ -22,7 +22,7 @@ struct GeneralSettings: View {
@State private var showRemoteAdvanced = false
private let isPreview = ProcessInfo.processInfo.isPreview
private var isNixMode: Bool { ProcessInfo.processInfo.isNixMode }
@State private var lastLocationModeRaw: String = ClawdisLocationMode.off.rawValue
@State private var lastLocationModeRaw: String = ClawdbotLocationMode.off.rawValue
var body: some View {
ScrollView(.vertical) {
@@ -36,8 +36,8 @@ struct GeneralSettings: View {
VStack(alignment: .leading, spacing: 12) {
SettingsToggleRow(
title: "Clawdis active",
subtitle: "Pause to stop the Clawdis gateway; no messages will be processed.",
title: "Clawdbot active",
subtitle: "Pause to stop the Clawdbot gateway; no messages will be processed.",
binding: self.activeBinding)
self.connectionSection
@@ -46,12 +46,12 @@ struct GeneralSettings: View {
SettingsToggleRow(
title: "Launch at login",
subtitle: "Automatically start Clawdis after you sign in.",
subtitle: "Automatically start Clawdbot after you sign in.",
binding: self.$state.launchAtLogin)
SettingsToggleRow(
title: "Show Dock icon",
subtitle: "Keep Clawdis visible in the Dock instead of menu-bar-only mode.",
subtitle: "Keep Clawdbot visible in the Dock instead of menu-bar-only mode.",
binding: self.$state.showDockIcon)
SettingsToggleRow(
@@ -74,9 +74,9 @@ struct GeneralSettings: View {
.font(.body)
Picker("", selection: self.$locationModeRaw) {
Text("Off").tag(ClawdisLocationMode.off.rawValue)
Text("While Using").tag(ClawdisLocationMode.whileUsing.rawValue)
Text("Always").tag(ClawdisLocationMode.always.rawValue)
Text("Off").tag(ClawdbotLocationMode.off.rawValue)
Text("While Using").tag(ClawdbotLocationMode.whileUsing.rawValue)
Text("Always").tag(ClawdbotLocationMode.always.rawValue)
}
.pickerStyle(.segmented)
@@ -103,7 +103,7 @@ struct GeneralSettings: View {
Spacer(minLength: 12)
HStack {
Spacer()
Button("Quit Clawdis") { NSApp.terminate(nil) }
Button("Quit Clawdbot") { NSApp.terminate(nil) }
.buttonStyle(.borderedProminent)
}
}
@@ -125,7 +125,7 @@ struct GeneralSettings: View {
.onChange(of: self.locationModeRaw) { _, newValue in
let previous = self.lastLocationModeRaw
self.lastLocationModeRaw = newValue
guard let mode = ClawdisLocationMode(rawValue: newValue) else { return }
guard let mode = ClawdbotLocationMode(rawValue: newValue) else { return }
Task {
let granted = await self.requestLocationAuthorization(mode: mode)
if !granted {
@@ -144,11 +144,11 @@ struct GeneralSettings: View {
set: { self.state.isPaused = !$0 })
}
private var locationMode: ClawdisLocationMode {
ClawdisLocationMode(rawValue: self.locationModeRaw) ?? .off
private var locationMode: ClawdbotLocationMode {
ClawdbotLocationMode(rawValue: self.locationModeRaw) ?? .off
}
private func requestLocationAuthorization(mode: ClawdisLocationMode) async -> Bool {
private func requestLocationAuthorization(mode: ClawdbotLocationMode) async -> Bool {
guard mode != .off else { return true }
let status = CLLocationManager.authorizationStatus()
if status == .authorizedAlways || status == .authorizedWhenInUse {
@@ -169,7 +169,7 @@ struct GeneralSettings: View {
private var connectionSection: some View {
VStack(alignment: .leading, spacing: 10) {
Text("Clawdis runs")
Text("Clawdbot runs")
.font(.title3.weight(.semibold))
.frame(maxWidth: .infinity, alignment: .leading)
@@ -249,12 +249,12 @@ struct GeneralSettings: View {
.frame(width: 280)
}
LabeledContent("Project root") {
TextField("/home/you/Projects/clawdis", text: self.$state.remoteProjectRoot)
TextField("/home/you/Projects/clawdbot", text: self.$state.remoteProjectRoot)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
LabeledContent("CLI path") {
TextField("/Applications/Clawdis.app/.../clawdis", text: self.$state.remoteCliPath)
TextField("/Applications/Clawdbot.app/.../clawdbot", text: self.$state.remoteCliPath)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
@@ -377,7 +377,7 @@ struct GeneralSettings: View {
.foregroundStyle(.secondary)
.lineLimit(2)
} else {
Text("Symlink \"clawdis\" into /usr/local/bin and /opt/homebrew/bin for scripts.")
Text("Symlink \"clawdbot\" into /usr/local/bin and /opt/homebrew/bin for scripts.")
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(2)
@@ -683,7 +683,7 @@ extension GeneralSettings {
let alert = NSAlert()
alert.messageText = "Log file not found"
alert.informativeText = """
Looked for clawdis logs in /tmp/clawdis/.
Looked for clawdbot logs in /tmp/clawdbot/.
Run a health check or send a message to generate activity, then try again.
"""
alert.alertStyle = .informational
@@ -726,8 +726,8 @@ extension GeneralSettings {
state.connectionMode = .remote
state.remoteTarget = "user@host:2222"
state.remoteIdentity = "/tmp/id_ed25519"
state.remoteProjectRoot = "/tmp/clawdis"
state.remoteCliPath = "/tmp/clawdis"
state.remoteProjectRoot = "/tmp/clawdbot"
state.remoteCliPath = "/tmp/clawdbot"
let view = GeneralSettings(state: state)
view.gatewayStatus = GatewayEnvironmentStatus(
@@ -739,7 +739,7 @@ extension GeneralSettings {
view.remoteStatus = .failed("SSH failed")
view.showRemoteAdvanced = true
view.cliInstalled = true
view.cliInstallLocation = "/usr/local/bin/clawdis"
view.cliInstallLocation = "/usr/local/bin/clawdbot"
view.cliStatus = "Installed"
_ = view.body

View File

@@ -77,7 +77,7 @@ enum HealthState: Equatable {
final class HealthStore {
static let shared = HealthStore()
private static let logger = Logger(subsystem: "com.clawdis", category: "health")
private static let logger = Logger(subsystem: "com.clawdbot", category: "health")
private(set) var snapshot: HealthSnapshot?
private(set) var lastSuccess: Date?
@@ -171,9 +171,9 @@ final class HealthStore {
if !snap.web.linked {
if let tg = snap.telegram, tg.configured {
let tgLabel = (tg.probe?.ok ?? true) ? "Telegram ok" : "Telegram degraded"
return "\(tgLabel) · Not linked — run clawdis login"
return "\(tgLabel) · Not linked — run clawdbot login"
}
return "Not linked — run clawdis login"
return "Not linked — run clawdbot login"
}
let auth = snap.web.authAgeMs.map { msToAge($0) } ?? "unknown"
if let connect = snap.web.connect, !connect.ok {
@@ -189,7 +189,7 @@ final class HealthStore {
let lower = error.lowercased()
if lower.contains("connection refused") {
let port = GatewayEnvironment.gatewayPort()
return "The gateway control port (127.0.0.1:\(port)) isnt listening — restart Clawdis to bring it back."
return "The gateway control port (127.0.0.1:\(port)) isnt listening — restart Clawdbot to bring it back."
}
if lower.contains("timeout") {
return "Timed out waiting for the control server; the gateway may be crashed or still starting."
@@ -201,7 +201,7 @@ final class HealthStore {
func describeFailure(from snap: HealthSnapshot, fallback: String?) -> String {
if !snap.web.linked {
return "Not linked — run clawdis login"
return "Not linked — run clawdbot login"
}
if let connect = snap.web.connect, !connect.ok {
let elapsed = connect.elapsedMs.map { "\(Int($0))ms" } ?? "unknown duration"

View File

@@ -2,7 +2,7 @@ import Darwin
import Foundation
enum InstanceIdentity {
private static let suiteName = "com.clawdis.shared"
private static let suiteName = "com.clawdbot.shared"
private static let instanceIdKey = "instanceId"
private static var defaults: UserDefaults {
@@ -29,7 +29,7 @@ enum InstanceIdentity {
{
return name
}
return "clawdis"
return "clawdbot"
}()
static let modelIdentifier: String? = {

View File

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

View File

@@ -1,4 +1,4 @@
import ClawdisProtocol
import ClawdbotProtocol
import Cocoa
import Foundation
import Observation
@@ -40,7 +40,7 @@ final class InstancesStore {
var statusMessage: String?
var isLoading = false
private let logger = Logger(subsystem: "com.clawdis", category: "instances")
private let logger = Logger(subsystem: "com.clawdbot", category: "instances")
private var task: Task<Void, Never>?
private let interval: TimeInterval = 30
private var eventTask: Task<Void, Never>?
@@ -280,7 +280,7 @@ final class InstancesStore {
}
}
func handlePresenceEventPayload(_ payload: ClawdisProtocol.AnyCodable) {
func handlePresenceEventPayload(_ payload: ClawdbotProtocol.AnyCodable) {
do {
let wrapper = try GatewayPayloadDecoding.decode(payload, as: PresenceEventPayload.self)
self.applyPresence(wrapper.presence)

View File

@@ -1,10 +1,10 @@
import Foundation
enum LaunchAgentManager {
private static let legacyLaunchdLabel = "com.steipete.clawdis"
private static let legacyLaunchdLabel = "com.steipete.clawdbot"
private static var plistURL: URL {
FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("Library/LaunchAgents/com.clawdis.mac.plist")
.appendingPathComponent("Library/LaunchAgents/com.clawdbot.mac.plist")
}
private static var legacyPlistURL: URL {
FileManager.default.homeDirectoryForCurrentUser
@@ -39,10 +39,10 @@ enum LaunchAgentManager {
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.clawdis.mac</string>
<string>com.clawdbot.mac</string>
<key>ProgramArguments</key>
<array>
<string>\(bundlePath)/Contents/MacOS/Clawdis</string>
<string>\(bundlePath)/Contents/MacOS/Clawdbot</string>
</array>
<key>WorkingDirectory</key>
<string>\(FileManager.default.homeDirectoryForCurrentUser.path)</string>

View File

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

View File

@@ -1,15 +1,15 @@
import Foundation
enum LogLocator {
private static let logDir = URL(fileURLWithPath: "/tmp/clawdis")
private static let stdoutLog = logDir.appendingPathComponent("clawdis-stdout.log")
private static let gatewayLog = logDir.appendingPathComponent("clawdis-gateway.log")
private static let logDir = URL(fileURLWithPath: "/tmp/clawdbot")
private static let stdoutLog = logDir.appendingPathComponent("clawdbot-stdout.log")
private static let gatewayLog = logDir.appendingPathComponent("clawdbot-gateway.log")
private static func modificationDate(for url: URL) -> Date {
(try? url.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? .distantPast
}
/// Returns the newest log file under /tmp/clawdis/ (rolling or stdout), or nil if none exist.
/// Returns the newest log file under /tmp/clawdbot/ (rolling or stdout), or nil if none exist.
static func bestLogFile() -> URL? {
let fm = FileManager.default
let files = (try? fm.contentsOfDirectory(
@@ -18,7 +18,7 @@ enum LogLocator {
options: [.skipsHiddenFiles])) ?? []
return files
.filter { $0.lastPathComponent.hasPrefix("clawdis") && $0.pathExtension == "log" }
.filter { $0.lastPathComponent.hasPrefix("clawdbot") && $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 ClawdisLogging {
enum ClawdbotLogging {
private static let labelSeparator = "::"
private static let didBootstrap: Void = {
LoggingSystem.bootstrap { label in
let (subsystem, category) = Self.parseLabel(label)
let osHandler = ClawdisOSLogHandler(subsystem: subsystem, category: category)
let fileHandler = ClawdisFileLogHandler(label: label)
let osHandler = ClawdbotOSLogHandler(subsystem: subsystem, category: category)
let fileHandler = ClawdbotFileLogHandler(label: label)
return MultiplexLogHandler([osHandler, fileHandler])
}
}()
@@ -74,7 +74,7 @@ enum ClawdisLogging {
static func parseLabel(_ label: String) -> (String, String) {
guard let range = label.range(of: Self.labelSeparator) else {
return ("com.clawdis", label)
return ("com.clawdbot", label)
}
let subsystem = String(label[..<range.lowerBound])
let category = String(label[range.upperBound...])
@@ -84,8 +84,8 @@ enum ClawdisLogging {
extension Logging.Logger {
init(subsystem: String, category: String) {
ClawdisLogging.bootstrapIfNeeded()
let label = ClawdisLogging.makeLabel(subsystem: subsystem, category: category)
ClawdbotLogging.bootstrapIfNeeded()
let label = ClawdbotLogging.makeLabel(subsystem: subsystem, category: category)
self.init(label: label)
}
}
@@ -96,7 +96,7 @@ extension Logger.Message.StringInterpolation {
}
}
struct ClawdisOSLogHandler: LogHandler {
struct ClawdbotOSLogHandler: LogHandler {
private let osLogger: os.Logger
var metadata: Logger.Metadata = [:]
@@ -175,7 +175,7 @@ struct ClawdisOSLogHandler: LogHandler {
}
}
struct ClawdisFileLogHandler: LogHandler {
struct ClawdbotFileLogHandler: LogHandler {
let label: String
var metadata: Logger.Metadata = [:]
@@ -200,7 +200,7 @@ struct ClawdisFileLogHandler: LogHandler {
line: UInt)
{
guard AppLogSettings.fileLoggingEnabled() else { return }
let (subsystem, category) = ClawdisLogging.parseLabel(self.label)
let (subsystem, category) = ClawdbotLogging.parseLabel(self.label)
var fields: [String: String] = [
"subsystem": subsystem,
"category": category,

View File

@@ -7,7 +7,7 @@ import Security
import SwiftUI
@main
struct ClawdisApp: App {
struct ClawdbotApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var delegate
@State private var state: AppState
private let gatewayManager = GatewayProcessManager.shared
@@ -29,7 +29,7 @@ struct ClawdisApp: App {
}
init() {
ClawdisLogging.bootstrapIfNeeded()
ClawdbotLogging.bootstrapIfNeeded()
_state = State(initialValue: AppStateStore.shared)
}
@@ -231,7 +231,7 @@ private final class StatusItemMouseHandlerView: NSView {
@MainActor
final class AppDelegate: NSObject, NSApplicationDelegate {
private var state: AppState?
private let webChatAutoLogger = Logger(subsystem: "com.clawdis", category: "Chat")
private let webChatAutoLogger = Logger(subsystem: "com.clawdbot", category: "Chat")
let updaterController: UpdaterProviding = makeUpdaterController()
func application(_: NSApplication, open urls: [URL]) {

View File

@@ -4,7 +4,7 @@ import Foundation
import Observation
import SwiftUI
/// Menu contents for the Clawdis menu bar extra.
/// Menu contents for the Clawdbot menu bar extra.
struct MenuContent: View {
@Bindable var state: AppState
let updater: UpdaterProviding?
@@ -123,7 +123,7 @@ struct MenuContent: View {
Button("Settings…") { self.open(tab: .general) }
.keyboardShortcut(",", modifiers: [.command])
self.debugMenu
Button("About Clawdis") { self.open(tab: .about) }
Button("About Clawdbot") { self.open(tab: .about) }
if let updater, updater.isAvailable, self.updateStatus.isUpdateReady {
Button("Update ready, restart now?") { updater.checkForUpdates(nil) }
}
@@ -148,11 +148,11 @@ struct MenuContent: View {
private var connectionLabel: String {
switch self.state.connectionMode {
case .unconfigured:
"Clawdis Not Configured"
"Clawdbot Not Configured"
case .remote:
"Remote Clawdis Active"
"Remote Clawdbot Active"
case .local:
"Clawdis Active"
"Clawdbot Active"
}
}
@@ -286,7 +286,7 @@ struct MenuContent: View {
SettingsTabRouter.request(tab)
NSApp.activate(ignoringOtherApps: true)
self.openSettings()
NotificationCenter.default.post(name: .clawdisSelectSettingsTab, object: tab)
NotificationCenter.default.post(name: .clawdbotSelectSettingsTab, object: tab)
}
@MainActor

View File

@@ -4,7 +4,7 @@ import JavaScriptCore
enum ModelCatalogLoader {
static let defaultPath: String = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("Projects/pi-mono/packages/ai/src/models.generated.ts").path
private static let logger = Logger(subsystem: "com.clawdis", category: "models")
private static let logger = Logger(subsystem: "com.clawdbot", category: "models")
static func load(from path: String) async throws -> [ModelChoice] {
let expanded = (path as NSString).expandingTildeInPath

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