chore: rename project to clawdbot
This commit is contained in:
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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,
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ClawdisProtocol
|
||||
import ClawdbotProtocol
|
||||
import Foundation
|
||||
|
||||
extension AnyCodable {
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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")
|
||||
@@ -1,4 +1,4 @@
|
||||
import ClawdisKit
|
||||
import ClawdbotKit
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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`).
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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? {
|
||||
@@ -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 {
|
||||
@@ -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()
|
||||
@@ -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])
|
||||
@@ -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] {
|
||||
@@ -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 {
|
||||
@@ -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) ?? ""
|
||||
@@ -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
|
||||
@@ -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)."
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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
|
||||
39
apps/macos/Sources/Clawdbot/Constants.swift
Normal file
39
apps/macos/Sources/Clawdbot/Constants.swift
Normal 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"]
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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>?
|
||||
@@ -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",
|
||||
@@ -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],
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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),
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.")
|
||||
@@ -1,4 +1,4 @@
|
||||
import ClawdisProtocol
|
||||
import ClawdbotProtocol
|
||||
import Foundation
|
||||
|
||||
/// Structured error surfaced when the gateway responds with `{ ok: false }`.
|
||||
@@ -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
|
||||
@@ -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 }
|
||||
@@ -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.
|
||||
"""
|
||||
}
|
||||
@@ -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.
|
||||
@@ -1,4 +1,4 @@
|
||||
import ClawdisProtocol
|
||||
import ClawdbotProtocol
|
||||
|
||||
/// Server-push messages from the gateway websocket.
|
||||
///
|
||||
@@ -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
|
||||
|
||||
@@ -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)) isn’t listening — restart Clawdis to bring it back."
|
||||
return "The gateway control port (127.0.0.1:\(port)) isn’t 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"
|
||||
@@ -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? = {
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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])
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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]) {
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user