chore: rename project to clawdbot

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

View File

@@ -3,21 +3,21 @@
import PackageDescription
let package = Package(
name: "ClawdisKit",
name: "ClawdbotKit",
platforms: [
.iOS(.v17),
.macOS(.v15),
],
products: [
.library(name: "ClawdisKit", targets: ["ClawdisKit"]),
.library(name: "ClawdisChatUI", targets: ["ClawdisChatUI"]),
.library(name: "ClawdbotKit", targets: ["ClawdbotKit"]),
.library(name: "ClawdbotChatUI", targets: ["ClawdbotChatUI"]),
],
dependencies: [
.package(url: "https://github.com/steipete/ElevenLabsKit", exact: "0.1.0"),
],
targets: [
.target(
name: "ClawdisKit",
name: "ClawdbotKit",
dependencies: [
.product(name: "ElevenLabsKit", package: "ElevenLabsKit"),
],
@@ -28,14 +28,14 @@ let package = Package(
.enableUpcomingFeature("StrictConcurrency"),
]),
.target(
name: "ClawdisChatUI",
dependencies: ["ClawdisKit"],
name: "ClawdbotChatUI",
dependencies: ["ClawdbotKit"],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.testTarget(
name: "ClawdisKitTests",
dependencies: ["ClawdisKit", "ClawdisChatUI"],
name: "ClawdbotKitTests",
dependencies: ["ClawdbotKit", "ClawdbotChatUI"],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("SwiftTesting"),

View File

@@ -8,9 +8,9 @@ import UniformTypeIdentifiers
#endif
@MainActor
struct ClawdisChatComposer: View {
@Bindable var viewModel: ClawdisChatViewModel
let style: ClawdisChatView.Style
struct ClawdbotChatComposer: View {
@Bindable var viewModel: ClawdbotChatViewModel
let style: ClawdbotChatView.Style
let showsSessionSwitcher: Bool
#if !os(macOS)
@@ -54,21 +54,21 @@ struct ClawdisChatComposer: View {
topTrailing: 0),
style: .continuous)
shape
.fill(ClawdisChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdisChatTheme.composerBorder, lineWidth: 1))
.fill(ClawdbotChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdbotChatTheme.composerBorder, lineWidth: 1))
.shadow(color: .black.opacity(0.12), radius: 12, y: 6)
} else {
let shape = RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
shape
.fill(ClawdisChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdisChatTheme.composerBorder, lineWidth: 1))
.fill(ClawdbotChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdbotChatTheme.composerBorder, lineWidth: 1))
.shadow(color: .black.opacity(0.12), radius: 12, y: 6)
}
#else
let shape = RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
shape
.fill(ClawdisChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdisChatTheme.composerBorder, lineWidth: 1))
.fill(ClawdbotChatTheme.composerBackground)
.overlay(shape.strokeBorder(ClawdbotChatTheme.composerBorder, lineWidth: 1))
.shadow(color: .black.opacity(0.12), radius: 12, y: 6)
#endif
}
@@ -144,11 +144,11 @@ struct ClawdisChatComposer: View {
HStack(spacing: 6) {
ForEach(
self.viewModel.attachments,
id: \ClawdisPendingAttachment.id)
{ (att: ClawdisPendingAttachment) in
id: \ClawdbotPendingAttachment.id)
{ (att: ClawdbotPendingAttachment) in
HStack(spacing: 6) {
if let img = att.preview {
ClawdisPlatformImageFactory.image(img)
ClawdbotPlatformImageFactory.image(img)
.resizable()
.scaledToFill()
.frame(width: 22, height: 22)
@@ -181,7 +181,7 @@ struct ClawdisChatComposer: View {
self.editorOverlay
Rectangle()
.fill(ClawdisChatTheme.divider)
.fill(ClawdbotChatTheme.divider)
.frame(height: 1)
.padding(.horizontal, 2)
@@ -197,10 +197,10 @@ struct ClawdisChatComposer: View {
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(ClawdisChatTheme.composerField)
.fill(ClawdbotChatTheme.composerField)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.strokeBorder(ClawdisChatTheme.composerBorder)))
.strokeBorder(ClawdbotChatTheme.composerBorder)))
.padding(self.editorPadding)
}
@@ -217,7 +217,7 @@ struct ClawdisChatComposer: View {
}
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(ClawdisChatTheme.subtleCard)
.background(ClawdbotChatTheme.subtleCard)
.clipShape(Capsule())
}

View File

@@ -4,7 +4,7 @@ enum ChatMarkdownSplitter {
struct InlineImage: Identifiable {
let id = UUID()
let label: String
let image: ClawdisPlatformImage?
let image: ClawdbotPlatformImage?
}
struct Block: Identifiable {
@@ -93,11 +93,11 @@ enum ChatMarkdownSplitter {
let label = ns.substring(with: match.range(at: 1))
let dataURL = ns.substring(with: match.range(at: 2))
let image: ClawdisPlatformImage? = {
let image: ClawdbotPlatformImage? = {
guard let comma = dataURL.firstIndex(of: ",") else { return nil }
let b64 = String(dataURL[dataURL.index(after: comma)...])
guard let data = Data(base64Encoded: b64) else { return nil }
return ClawdisPlatformImage(data: data)
return ClawdbotPlatformImage(data: data)
}()
images.append(InlineImage(label: label, image: image))

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import SwiftUI
@@ -135,8 +135,8 @@ private struct ChatBubbleShape: InsettableShape {
@MainActor
struct ChatMessageBubble: View {
let message: ClawdisChatMessage
let style: ClawdisChatView.Style
let message: ClawdbotChatMessage
let style: ClawdbotChatView.Style
let userAccent: Color?
var body: some View {
@@ -151,14 +151,14 @@ struct ChatMessageBubble: View {
@MainActor
private struct ChatMessageBody: View {
let message: ClawdisChatMessage
let message: ClawdbotChatMessage
let isUser: Bool
let style: ClawdisChatView.Style
let style: ClawdbotChatView.Style
let userAccent: Color?
var body: some View {
let text = self.primaryText
let textColor = self.isUser ? ClawdisChatTheme.userText : ClawdisChatTheme.assistantText
let textColor = self.isUser ? ClawdbotChatTheme.userText : ClawdbotChatTheme.assistantText
VStack(alignment: .leading, spacing: 10) {
if self.isToolResultMessage {
@@ -185,7 +185,7 @@ private struct ChatMessageBody: View {
id: \ChatMarkdownSplitter.InlineImage.id)
{ (item: ChatMarkdownSplitter.InlineImage) in
if let img = item.image {
ClawdisPlatformImageFactory.image(img)
ClawdbotPlatformImageFactory.image(img)
.resizable()
.scaledToFit()
.frame(maxHeight: 260)
@@ -250,7 +250,7 @@ private struct ChatMessageBody: View {
return parts.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines)
}
private var inlineAttachments: [ClawdisChatMessageContent] {
private var inlineAttachments: [ClawdbotChatMessageContent] {
self.message.content.filter { content in
switch content.type ?? "text" {
case "file", "attachment":
@@ -261,7 +261,7 @@ private struct ChatMessageBody: View {
}
}
private var toolCalls: [ClawdisChatMessageContent] {
private var toolCalls: [ClawdbotChatMessageContent] {
self.message.content.filter { content in
let kind = (content.type ?? "").lowercased()
if ["toolcall", "tool_call", "tooluse", "tool_use"].contains(kind) {
@@ -271,7 +271,7 @@ private struct ChatMessageBody: View {
}
}
private var inlineToolResults: [ClawdisChatMessageContent] {
private var inlineToolResults: [ClawdbotChatMessageContent] {
self.message.content.filter { content in
let kind = (content.type ?? "").lowercased()
return kind == "toolresult" || kind == "tool_result"
@@ -294,12 +294,12 @@ private struct ChatMessageBody: View {
private var bubbleFillColor: Color {
if self.isUser {
return self.userAccent ?? ClawdisChatTheme.userBubble
return self.userAccent ?? ClawdbotChatTheme.userBubble
}
if self.style == .onboarding {
return ClawdisChatTheme.onboardingAssistantBubble
return ClawdbotChatTheme.onboardingAssistantBubble
}
return ClawdisChatTheme.assistantBubble
return ClawdbotChatTheme.assistantBubble
}
private var bubbleBackground: AnyShapeStyle {
@@ -311,7 +311,7 @@ private struct ChatMessageBody: View {
return Color.white.opacity(0.12)
}
if self.style == .onboarding {
return ClawdisChatTheme.onboardingAssistantBorder
return ClawdbotChatTheme.onboardingAssistantBorder
}
return Color.white.opacity(0.08)
}
@@ -357,7 +357,7 @@ private struct ChatMessageBody: View {
}
private struct AttachmentRow: View {
let att: ClawdisChatMessageContent
let att: ClawdbotChatMessageContent
let isUser: Bool
var body: some View {
@@ -366,7 +366,7 @@ private struct AttachmentRow: View {
Text(self.att.fileName ?? "Attachment")
.font(.footnote)
.lineLimit(1)
.foregroundStyle(self.isUser ? ClawdisChatTheme.userText : ClawdisChatTheme.assistantText)
.foregroundStyle(self.isUser ? ClawdbotChatTheme.userText : ClawdbotChatTheme.assistantText)
Spacer()
}
.padding(10)
@@ -376,7 +376,7 @@ private struct AttachmentRow: View {
}
private struct ToolCallCard: View {
let content: ClawdisChatMessageContent
let content: ClawdbotChatMessageContent
let isUser: Bool
var body: some View {
@@ -397,7 +397,7 @@ private struct ToolCallCard: View {
.padding(10)
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(ClawdisChatTheme.subtleCard)
.fill(ClawdbotChatTheme.subtleCard)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1)))
@@ -432,7 +432,7 @@ private struct ToolResultCard: View {
Text(self.displayText)
.font(.footnote.monospaced())
.foregroundStyle(self.isUser ? ClawdisChatTheme.userText : ClawdisChatTheme.assistantText)
.foregroundStyle(self.isUser ? ClawdbotChatTheme.userText : ClawdbotChatTheme.assistantText)
.lineLimit(self.expanded ? nil : Self.previewLineLimit)
if self.shouldShowToggle {
@@ -447,7 +447,7 @@ private struct ToolResultCard: View {
.padding(10)
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(ClawdisChatTheme.subtleCard)
.fill(ClawdbotChatTheme.subtleCard)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1)))
@@ -471,7 +471,7 @@ private struct ToolResultCard: View {
@MainActor
struct ChatTypingIndicatorBubble: View {
let style: ClawdisChatView.Style
let style: ClawdbotChatView.Style
var body: some View {
HStack(spacing: 10) {
@@ -487,7 +487,7 @@ struct ChatTypingIndicatorBubble: View {
.padding(.horizontal, self.style == .standard ? 12 : 14)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(ClawdisChatTheme.assistantBubble))
.fill(ClawdbotChatTheme.assistantBubble))
.overlay(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
@@ -513,7 +513,7 @@ struct ChatStreamingAssistantBubble: View {
.padding(12)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(ClawdisChatTheme.assistantBubble))
.fill(ClawdbotChatTheme.assistantBubble))
.overlay(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
@@ -524,7 +524,7 @@ struct ChatStreamingAssistantBubble: View {
@MainActor
struct ChatPendingToolsBubble: View {
let toolCalls: [ClawdisChatPendingToolCall]
let toolCalls: [ClawdbotChatPendingToolCall]
var body: some View {
VStack(alignment: .leading, spacing: 8) {
@@ -557,7 +557,7 @@ struct ChatPendingToolsBubble: View {
.padding(12)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(ClawdisChatTheme.assistantBubble))
.fill(ClawdbotChatTheme.assistantBubble))
.overlay(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.strokeBorder(Color.white.opacity(0.08), lineWidth: 1))
@@ -646,7 +646,7 @@ private struct ChatAssistantTextBody: View {
VStack(alignment: .leading, spacing: 10) {
ForEach(segments) { segment in
let font = segment.kind == .thinking ? Font.system(size: 14).italic() : Font.system(size: 14)
ChatMarkdownBody(text: segment.text, textColor: ClawdisChatTheme.assistantText, font: font)
ChatMarkdownBody(text: segment.text, textColor: ClawdbotChatTheme.assistantText, font: font)
}
}
}
@@ -676,7 +676,7 @@ private struct ChatMarkdownBody: View {
id: \ChatMarkdownSplitter.InlineImage.id)
{ (item: ChatMarkdownSplitter.InlineImage) in
if let img = item.image {
ClawdisPlatformImageFactory.image(img)
ClawdbotPlatformImageFactory.image(img)
.resizable()
.scaledToFit()
.frame(maxHeight: 260)

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
// NOTE: keep this file lightweight; decode must be resilient to varying transcript formats.
@@ -6,14 +6,14 @@ import Foundation
#if canImport(AppKit)
import AppKit
public typealias ClawdisPlatformImage = NSImage
public typealias ClawdbotPlatformImage = NSImage
#elseif canImport(UIKit)
import UIKit
public typealias ClawdisPlatformImage = UIImage
public typealias ClawdbotPlatformImage = UIImage
#endif
public struct ClawdisChatUsageCost: Codable, Hashable, Sendable {
public struct ClawdbotChatUsageCost: Codable, Hashable, Sendable {
public let input: Double?
public let output: Double?
public let cacheRead: Double?
@@ -21,12 +21,12 @@ public struct ClawdisChatUsageCost: Codable, Hashable, Sendable {
public let total: Double?
}
public struct ClawdisChatUsage: Codable, Hashable, Sendable {
public struct ClawdbotChatUsage: Codable, Hashable, Sendable {
public let input: Int?
public let output: Int?
public let cacheRead: Int?
public let cacheWrite: Int?
public let cost: ClawdisChatUsageCost?
public let cost: ClawdbotChatUsageCost?
public let total: Int?
enum CodingKeys: String, CodingKey {
@@ -45,7 +45,7 @@ public struct ClawdisChatUsage: Codable, Hashable, Sendable {
self.output = try container.decodeIfPresent(Int.self, forKey: .output)
self.cacheRead = try container.decodeIfPresent(Int.self, forKey: .cacheRead)
self.cacheWrite = try container.decodeIfPresent(Int.self, forKey: .cacheWrite)
self.cost = try container.decodeIfPresent(ClawdisChatUsageCost.self, forKey: .cost)
self.cost = try container.decodeIfPresent(ClawdbotChatUsageCost.self, forKey: .cost)
self.total =
try container.decodeIfPresent(Int.self, forKey: .total) ??
container.decodeIfPresent(Int.self, forKey: .totalTokens)
@@ -62,7 +62,7 @@ public struct ClawdisChatUsage: Codable, Hashable, Sendable {
}
}
public struct ClawdisChatMessageContent: Codable, Hashable, Sendable {
public struct ClawdbotChatMessageContent: Codable, Hashable, Sendable {
public let type: String?
public let text: String?
public let thinking: String?
@@ -135,14 +135,14 @@ public struct ClawdisChatMessageContent: Codable, Hashable, Sendable {
}
}
public struct ClawdisChatMessage: Codable, Identifiable, Sendable {
public struct ClawdbotChatMessage: Codable, Identifiable, Sendable {
public var id: UUID = .init()
public let role: String
public let content: [ClawdisChatMessageContent]
public let content: [ClawdbotChatMessageContent]
public let timestamp: Double?
public let toolCallId: String?
public let toolName: String?
public let usage: ClawdisChatUsage?
public let usage: ClawdbotChatUsage?
public let stopReason: String?
enum CodingKeys: String, CodingKey {
@@ -160,11 +160,11 @@ public struct ClawdisChatMessage: Codable, Identifiable, Sendable {
public init(
id: UUID = .init(),
role: String,
content: [ClawdisChatMessageContent],
content: [ClawdbotChatMessageContent],
timestamp: Double?,
toolCallId: String? = nil,
toolName: String? = nil,
usage: ClawdisChatUsage? = nil,
usage: ClawdbotChatUsage? = nil,
stopReason: String? = nil)
{
self.id = id
@@ -187,10 +187,10 @@ public struct ClawdisChatMessage: Codable, Identifiable, Sendable {
self.toolName =
try container.decodeIfPresent(String.self, forKey: .toolName) ??
container.decodeIfPresent(String.self, forKey: .tool_name)
self.usage = try container.decodeIfPresent(ClawdisChatUsage.self, forKey: .usage)
self.usage = try container.decodeIfPresent(ClawdbotChatUsage.self, forKey: .usage)
self.stopReason = try container.decodeIfPresent(String.self, forKey: .stopReason)
if let decoded = try? container.decode([ClawdisChatMessageContent].self, forKey: .content) {
if let decoded = try? container.decode([ClawdbotChatMessageContent].self, forKey: .content) {
self.content = decoded
return
}
@@ -198,7 +198,7 @@ public struct ClawdisChatMessage: Codable, Identifiable, Sendable {
// Some session log formats store `content` as a plain string.
if let text = try? container.decode(String.self, forKey: .content) {
self.content = [
ClawdisChatMessageContent(
ClawdbotChatMessageContent(
type: "text",
text: text,
thinking: nil,
@@ -228,19 +228,19 @@ public struct ClawdisChatMessage: Codable, Identifiable, Sendable {
}
}
public struct ClawdisChatHistoryPayload: Codable, Sendable {
public struct ClawdbotChatHistoryPayload: Codable, Sendable {
public let sessionKey: String
public let sessionId: String?
public let messages: [AnyCodable]?
public let thinkingLevel: String?
}
public struct ClawdisChatSendResponse: Codable, Sendable {
public struct ClawdbotChatSendResponse: Codable, Sendable {
public let runId: String
public let status: String
}
public struct ClawdisChatEventPayload: Codable, Sendable {
public struct ClawdbotChatEventPayload: Codable, Sendable {
public let runId: String?
public let sessionKey: String?
public let state: String?
@@ -248,7 +248,7 @@ public struct ClawdisChatEventPayload: Codable, Sendable {
public let errorMessage: String?
}
public struct ClawdisAgentEventPayload: Codable, Sendable, Identifiable {
public struct ClawdbotAgentEventPayload: Codable, Sendable, Identifiable {
public var id: String { "\(self.runId)-\(self.seq ?? -1)" }
public let runId: String
public let seq: Int?
@@ -257,7 +257,7 @@ public struct ClawdisAgentEventPayload: Codable, Sendable, Identifiable {
public let data: [String: AnyCodable]
}
public struct ClawdisChatPendingToolCall: Identifiable, Hashable, Sendable {
public struct ClawdbotChatPendingToolCall: Identifiable, Hashable, Sendable {
public var id: String { self.toolCallId }
public let toolCallId: String
public let name: String
@@ -266,18 +266,18 @@ public struct ClawdisChatPendingToolCall: Identifiable, Hashable, Sendable {
public let isError: Bool?
}
public struct ClawdisGatewayHealthOK: Codable, Sendable {
public struct ClawdbotGatewayHealthOK: Codable, Sendable {
public let ok: Bool?
}
public struct ClawdisPendingAttachment: Identifiable {
public struct ClawdbotPendingAttachment: Identifiable {
public let id = UUID()
public let url: URL?
public let data: Data
public let fileName: String
public let mimeType: String
public let type: String
public let preview: ClawdisPlatformImage?
public let preview: ClawdbotPlatformImage?
public init(
url: URL?,
@@ -285,7 +285,7 @@ public struct ClawdisPendingAttachment: Identifiable {
fileName: String,
mimeType: String,
type: String = "file",
preview: ClawdisPlatformImage?)
preview: ClawdbotPlatformImage?)
{
self.url = url
self.data = data
@@ -296,7 +296,7 @@ public struct ClawdisPendingAttachment: Identifiable {
}
}
public struct ClawdisChatAttachmentPayload: Codable, Sendable, Hashable {
public struct ClawdbotChatAttachmentPayload: Codable, Sendable, Hashable {
public let type: String
public let mimeType: String
public let fileName: String

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
enum ChatPayloadDecoding {

View File

@@ -1,11 +1,11 @@
import Foundation
public struct ClawdisChatSessionsDefaults: Codable, Sendable {
public struct ClawdbotChatSessionsDefaults: Codable, Sendable {
public let model: String?
public let contextTokens: Int?
}
public struct ClawdisChatSessionEntry: Codable, Identifiable, Sendable, Hashable {
public struct ClawdbotChatSessionEntry: Codable, Identifiable, Sendable, Hashable {
public var id: String { self.key }
public let key: String
@@ -31,10 +31,10 @@ public struct ClawdisChatSessionEntry: Codable, Identifiable, Sendable, Hashable
public let contextTokens: Int?
}
public struct ClawdisChatSessionsListResponse: Codable, Sendable {
public struct ClawdbotChatSessionsListResponse: Codable, Sendable {
public let ts: Double?
public let path: String?
public let count: Int?
public let defaults: ClawdisChatSessionsDefaults?
public let sessions: [ClawdisChatSessionEntry]
public let defaults: ClawdbotChatSessionsDefaults?
public let sessions: [ClawdbotChatSessionEntry]
}

View File

@@ -3,7 +3,7 @@ import SwiftUI
@MainActor
struct ChatSessionsSheet: View {
@Bindable var viewModel: ClawdisChatViewModel
@Bindable var viewModel: ClawdbotChatViewModel
@Environment(\.dismiss) private var dismiss
var body: some View {

View File

@@ -14,7 +14,7 @@ extension NSAppearance {
}
#endif
enum ClawdisChatTheme {
enum ClawdbotChatTheme {
#if os(macOS)
static func resolvedAssistantBubbleColor(for appearance: NSAppearance) -> NSColor {
// NSColor semantic colors don't reliably resolve for arbitrary NSAppearance in SwiftPM.
@@ -31,11 +31,11 @@ enum ClawdisChatTheme {
}
static let assistantBubbleDynamicNSColor = NSColor(
name: NSColor.Name("ClawdisChatTheme.assistantBubble"),
name: NSColor.Name("ClawdbotChatTheme.assistantBubble"),
dynamicProvider: resolvedAssistantBubbleColor(for:))
static let onboardingAssistantBubbleDynamicNSColor = NSColor(
name: NSColor.Name("ClawdisChatTheme.onboardingAssistantBubble"),
name: NSColor.Name("ClawdbotChatTheme.onboardingAssistantBubble"),
dynamicProvider: resolvedOnboardingAssistantBubbleColor(for:))
#endif
@@ -163,8 +163,8 @@ enum ClawdisChatTheme {
}
}
enum ClawdisPlatformImageFactory {
static func image(_ image: ClawdisPlatformImage) -> Image {
enum ClawdbotPlatformImageFactory {
static func image(_ image: ClawdbotPlatformImage) -> Image {
#if os(macOS)
Image(nsImage: image)
#else

View File

@@ -1,44 +1,44 @@
import Foundation
public enum ClawdisChatTransportEvent: Sendable {
public enum ClawdbotChatTransportEvent: Sendable {
case health(ok: Bool)
case tick
case chat(ClawdisChatEventPayload)
case agent(ClawdisAgentEventPayload)
case chat(ClawdbotChatEventPayload)
case agent(ClawdbotAgentEventPayload)
case seqGap
}
public protocol ClawdisChatTransport: Sendable {
func requestHistory(sessionKey: String) async throws -> ClawdisChatHistoryPayload
public protocol ClawdbotChatTransport: Sendable {
func requestHistory(sessionKey: String) async throws -> ClawdbotChatHistoryPayload
func sendMessage(
sessionKey: String,
message: String,
thinking: String,
idempotencyKey: String,
attachments: [ClawdisChatAttachmentPayload]) async throws -> ClawdisChatSendResponse
attachments: [ClawdbotChatAttachmentPayload]) async throws -> ClawdbotChatSendResponse
func abortRun(sessionKey: String, runId: String) async throws
func listSessions(limit: Int?) async throws -> ClawdisChatSessionsListResponse
func listSessions(limit: Int?) async throws -> ClawdbotChatSessionsListResponse
func requestHealth(timeoutMs: Int) async throws -> Bool
func events() -> AsyncStream<ClawdisChatTransportEvent>
func events() -> AsyncStream<ClawdbotChatTransportEvent>
func setActiveSessionKey(_ sessionKey: String) async throws
}
extension ClawdisChatTransport {
extension ClawdbotChatTransport {
public func setActiveSessionKey(_: String) async throws {}
public func abortRun(sessionKey _: String, runId _: String) async throws {
throw NSError(
domain: "ClawdisChatTransport",
domain: "ClawdbotChatTransport",
code: 0,
userInfo: [NSLocalizedDescriptionKey: "chat.abort not supported by this transport"])
}
public func listSessions(limit _: Int?) async throws -> ClawdisChatSessionsListResponse {
public func listSessions(limit _: Int?) async throws -> ClawdbotChatSessionsListResponse {
throw NSError(
domain: "ClawdisChatTransport",
domain: "ClawdbotChatTransport",
code: 0,
userInfo: [NSLocalizedDescriptionKey: "sessions.list not supported by this transport"])
}

View File

@@ -1,13 +1,13 @@
import SwiftUI
@MainActor
public struct ClawdisChatView: View {
public struct ClawdbotChatView: View {
public enum Style {
case standard
case onboarding
}
@State private var viewModel: ClawdisChatViewModel
@State private var viewModel: ClawdbotChatViewModel
@State private var scrollerBottomID = UUID()
@State private var scrollPosition: UUID?
@State private var showSessions = false
@@ -39,7 +39,7 @@ public struct ClawdisChatView: View {
}
public init(
viewModel: ClawdisChatViewModel,
viewModel: ClawdbotChatViewModel,
showsSessionSwitcher: Bool = false,
style: Style = .standard,
userAccent: Color? = nil)
@@ -52,13 +52,13 @@ public struct ClawdisChatView: View {
public var body: some View {
ZStack {
ClawdisChatTheme.background
ClawdbotChatTheme.background
.ignoresSafeArea()
VStack(spacing: Layout.stackSpacing) {
self.messageList
.padding(.horizontal, Layout.outerPaddingHorizontal)
ClawdisChatComposer(
ClawdbotChatComposer(
viewModel: self.viewModel,
style: self.style,
showsSessionSwitcher: self.showsSessionSwitcher)
@@ -175,8 +175,8 @@ public struct ClawdisChatView: View {
}
}
private var visibleMessages: [ClawdisChatMessage] {
let base: [ClawdisChatMessage]
private var visibleMessages: [ClawdbotChatMessage] {
let base: [ClawdbotChatMessage]
if self.style == .onboarding {
guard let first = self.viewModel.messages.first else { return [] }
base = first.role.lowercased() == "user" ? Array(self.viewModel.messages.dropFirst()) : self.viewModel
@@ -293,8 +293,8 @@ public struct ClawdisChatView: View {
return ("Error", "exclamationmark.triangle.fill", .orange)
}
private func mergeToolResults(in messages: [ClawdisChatMessage]) -> [ClawdisChatMessage] {
var result: [ClawdisChatMessage] = []
private func mergeToolResults(in messages: [ClawdbotChatMessage]) -> [ClawdbotChatMessage] {
var result: [ClawdbotChatMessage] = []
result.reserveCapacity(messages.count)
for message in messages {
@@ -318,7 +318,7 @@ public struct ClawdisChatView: View {
var content = last.content
content.append(
ClawdisChatMessageContent(
ClawdbotChatMessageContent(
type: "tool_result",
text: toolText,
thinking: nil,
@@ -330,7 +330,7 @@ public struct ClawdisChatView: View {
name: message.toolName,
arguments: nil))
let merged = ClawdisChatMessage(
let merged = ClawdbotChatMessage(
id: last.id,
role: last.role,
content: content,
@@ -345,12 +345,12 @@ public struct ClawdisChatView: View {
return result
}
private func isToolResultMessage(_ message: ClawdisChatMessage) -> Bool {
private func isToolResultMessage(_ message: ClawdbotChatMessage) -> Bool {
let role = message.role.lowercased()
return role == "toolresult" || role == "tool_result"
}
private func toolCallIds(in message: ClawdisChatMessage) -> Set<String> {
private func toolCallIds(in message: ClawdbotChatMessage) -> Set<String> {
var ids = Set<String>()
for content in message.content {
let kind = (content.type ?? "").lowercased()
@@ -367,7 +367,7 @@ public struct ClawdisChatView: View {
return ids
}
private func toolResultText(from message: ClawdisChatMessage) -> String {
private func toolResultText(from message: ClawdbotChatMessage) -> String {
let parts = message.content.compactMap { content -> String? in
let kind = (content.type ?? "text").lowercased()
guard kind == "text" || kind.isEmpty else { return nil }
@@ -415,7 +415,7 @@ private struct ChatNoticeCard: View {
.padding(18)
.background(
RoundedRectangle(cornerRadius: 18, style: .continuous)
.fill(ClawdisChatTheme.subtleCard)
.fill(ClawdbotChatTheme.subtleCard)
.overlay(
RoundedRectangle(cornerRadius: 18, style: .continuous)
.strokeBorder(Color.white.opacity(0.12), lineWidth: 1)))
@@ -468,7 +468,7 @@ private struct ChatNoticeBanner: View {
.padding(.vertical, 10)
.background(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(ClawdisChatTheme.subtleCard)
.fill(ClawdbotChatTheme.subtleCard)
.overlay(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.strokeBorder(Color.white.opacity(0.12), lineWidth: 1)))

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Observation
import OSLog
@@ -10,28 +10,28 @@ import AppKit
import UIKit
#endif
private let chatUILogger = Logger(subsystem: "com.clawdis", category: "ClawdisChatUI")
private let chatUILogger = Logger(subsystem: "com.clawdbot", category: "ClawdbotChatUI")
@MainActor
@Observable
public final class ClawdisChatViewModel {
public private(set) var messages: [ClawdisChatMessage] = []
public final class ClawdbotChatViewModel {
public private(set) var messages: [ClawdbotChatMessage] = []
public var input: String = ""
public var thinkingLevel: String = "off"
public private(set) var isLoading = false
public private(set) var isSending = false
public private(set) var isAborting = false
public var errorText: String?
public var attachments: [ClawdisPendingAttachment] = []
public var attachments: [ClawdbotPendingAttachment] = []
public private(set) var healthOK: Bool = false
public private(set) var pendingRunCount: Int = 0
public private(set) var sessionKey: String
public private(set) var sessionId: String?
public private(set) var streamingAssistantText: String?
public private(set) var pendingToolCalls: [ClawdisChatPendingToolCall] = []
public private(set) var sessions: [ClawdisChatSessionEntry] = []
private let transport: any ClawdisChatTransport
public private(set) var pendingToolCalls: [ClawdbotChatPendingToolCall] = []
public private(set) var sessions: [ClawdbotChatSessionEntry] = []
private let transport: any ClawdbotChatTransport
@ObservationIgnored
private nonisolated(unsafe) var eventTask: Task<Void, Never>?
@@ -43,7 +43,7 @@ public final class ClawdisChatViewModel {
private nonisolated(unsafe) var pendingRunTimeoutTasks: [String: Task<Void, Never>] = [:]
private let pendingRunTimeoutMs: UInt64 = 120_000
private var pendingToolCallsById: [String: ClawdisChatPendingToolCall] = [:] {
private var pendingToolCallsById: [String: ClawdbotChatPendingToolCall] = [:] {
didSet {
self.pendingToolCalls = self.pendingToolCallsById.values
.sorted { ($0.startedAt ?? 0) < ($1.startedAt ?? 0) }
@@ -52,7 +52,7 @@ public final class ClawdisChatViewModel {
private var lastHealthPollAt: Date?
public init(sessionKey: String, transport: any ClawdisChatTransport) {
public init(sessionKey: String, transport: any ClawdbotChatTransport) {
self.sessionKey = sessionKey
self.transport = transport
@@ -99,12 +99,12 @@ public final class ClawdisChatViewModel {
Task { await self.performSwitchSession(to: sessionKey) }
}
public var sessionChoices: [ClawdisChatSessionEntry] {
public var sessionChoices: [ClawdbotChatSessionEntry] {
let now = Date().timeIntervalSince1970 * 1000
let cutoff = now - (24 * 60 * 60 * 1000)
let sorted = self.sessions.sorted { ($0.updatedAt ?? 0) > ($1.updatedAt ?? 0) }
var seen = Set<String>()
var recent: [ClawdisChatSessionEntry] = []
var recent: [ClawdbotChatSessionEntry] = []
for entry in sorted {
guard !seen.contains(entry.key) else { continue }
seen.insert(entry.key)
@@ -113,7 +113,7 @@ public final class ClawdisChatViewModel {
}
let mainKey = "main"
var result: [ClawdisChatSessionEntry] = []
var result: [ClawdbotChatSessionEntry] = []
var included = Set<String>()
if let main = sorted.first(where: { $0.key == mainKey }) {
result.append(main)
@@ -143,7 +143,7 @@ public final class ClawdisChatViewModel {
Task { await self.addImageAttachment(url: nil, data: data, fileName: fileName, mimeType: mimeType) }
}
public func removeAttachment(_ id: ClawdisPendingAttachment.ID) {
public func removeAttachment(_ id: ClawdbotPendingAttachment.ID) {
self.attachments.removeAll { $0.id == id }
}
@@ -185,15 +185,15 @@ public final class ClawdisChatViewModel {
}
}
private static func decodeMessages(_ raw: [AnyCodable]) -> [ClawdisChatMessage] {
private static func decodeMessages(_ raw: [AnyCodable]) -> [ClawdbotChatMessage] {
let decoded = raw.compactMap { item in
(try? ChatPayloadDecoding.decode(item, as: ClawdisChatMessage.self))
(try? ChatPayloadDecoding.decode(item, as: ClawdbotChatMessage.self))
}
return Self.dedupeMessages(decoded)
}
private static func dedupeMessages(_ messages: [ClawdisChatMessage]) -> [ClawdisChatMessage] {
var result: [ClawdisChatMessage] = []
private static func dedupeMessages(_ messages: [ClawdbotChatMessage]) -> [ClawdbotChatMessage] {
var result: [ClawdbotChatMessage] = []
result.reserveCapacity(messages.count)
var seen = Set<String>()
@@ -210,7 +210,7 @@ public final class ClawdisChatViewModel {
return result
}
private static func dedupeKey(for message: ClawdisChatMessage) -> String? {
private static func dedupeKey(for message: ClawdbotChatMessage) -> String? {
guard let timestamp = message.timestamp else { return nil }
let text = message.content.compactMap(\.text).joined(separator: "\n")
.trimmingCharacters(in: .whitespacesAndNewlines)
@@ -238,8 +238,8 @@ public final class ClawdisChatViewModel {
self.streamingAssistantText = nil
// Optimistically append user message to UI.
var userContent: [ClawdisChatMessageContent] = [
ClawdisChatMessageContent(
var userContent: [ClawdbotChatMessageContent] = [
ClawdbotChatMessageContent(
type: "text",
text: messageText,
thinking: nil,
@@ -251,8 +251,8 @@ public final class ClawdisChatViewModel {
name: nil,
arguments: nil),
]
let encodedAttachments = self.attachments.map { att -> ClawdisChatAttachmentPayload in
ClawdisChatAttachmentPayload(
let encodedAttachments = self.attachments.map { att -> ClawdbotChatAttachmentPayload in
ClawdbotChatAttachmentPayload(
type: att.type,
mimeType: att.mimeType,
fileName: att.fileName,
@@ -260,7 +260,7 @@ public final class ClawdisChatViewModel {
}
for att in encodedAttachments {
userContent.append(
ClawdisChatMessageContent(
ClawdbotChatMessageContent(
type: att.type,
text: nil,
thinking: nil,
@@ -273,7 +273,7 @@ public final class ClawdisChatViewModel {
arguments: nil))
}
self.messages.append(
ClawdisChatMessage(
ClawdbotChatMessage(
id: UUID(),
role: "user",
content: userContent,
@@ -337,8 +337,8 @@ public final class ClawdisChatViewModel {
await self.bootstrap()
}
private func placeholderSession(key: String) -> ClawdisChatSessionEntry {
ClawdisChatSessionEntry(
private func placeholderSession(key: String) -> ClawdbotChatSessionEntry {
ClawdbotChatSessionEntry(
key: key,
kind: nil,
displayName: nil,
@@ -359,7 +359,7 @@ public final class ClawdisChatViewModel {
contextTokens: nil)
}
private func handleTransportEvent(_ evt: ClawdisChatTransportEvent) {
private func handleTransportEvent(_ evt: ClawdbotChatTransportEvent) {
switch evt {
case let .health(ok):
self.healthOK = ok
@@ -375,7 +375,7 @@ public final class ClawdisChatViewModel {
}
}
private func handleChatEvent(_ chat: ClawdisChatEventPayload) {
private func handleChatEvent(_ chat: ClawdbotChatEventPayload) {
if let sessionKey = chat.sessionKey, sessionKey != self.sessionKey {
return
}
@@ -412,7 +412,7 @@ public final class ClawdisChatViewModel {
}
}
private func handleAgentEvent(_ evt: ClawdisAgentEventPayload) {
private func handleAgentEvent(_ evt: ClawdbotAgentEventPayload) {
if let sessionId, evt.runId != sessionId {
return
}
@@ -428,7 +428,7 @@ public final class ClawdisChatViewModel {
guard let toolCallId = evt.data["toolCallId"]?.value as? String else { return }
if phase == "start" {
let args = evt.data["args"]
self.pendingToolCallsById[toolCallId] = ClawdisChatPendingToolCall(
self.pendingToolCallsById[toolCallId] = ClawdbotChatPendingToolCall(
toolCallId: toolCallId,
name: name,
args: args,
@@ -539,7 +539,7 @@ public final class ClawdisChatViewModel {
let preview = Self.previewImage(data: data)
self.attachments.append(
ClawdisPendingAttachment(
ClawdbotPendingAttachment(
url: url,
data: data,
fileName: fileName,
@@ -547,7 +547,7 @@ public final class ClawdisChatViewModel {
preview: preview))
}
private static func previewImage(data: Data) -> ClawdisPlatformImage? {
private static func previewImage(data: Data) -> ClawdbotPlatformImage? {
#if canImport(AppKit)
NSImage(data: data)
#elseif canImport(UIKit)

View File

@@ -1,10 +1,10 @@
import Foundation
public enum ClawdisBonjour {
public enum ClawdbotBonjour {
// v0: internal-only, subject to rename.
public static let bridgeServiceType = "_clawdis-bridge._tcp"
public static let bridgeServiceType = "_clawdbot-bridge._tcp"
public static let bridgeServiceDomain = "local."
public static let wideAreaBridgeServiceDomain = "clawdis.internal."
public static let wideAreaBridgeServiceDomain = "clawdbot.internal."
public static let bridgeServiceDomains = [
bridgeServiceDomain,

View File

@@ -27,14 +27,14 @@ public struct BridgeInvokeResponse: Codable, Sendable {
public let id: String
public let ok: Bool
public let payloadJSON: String?
public let error: ClawdisNodeError?
public let error: ClawdbotNodeError?
public init(
type: String = "invoke-res",
id: String,
ok: Bool,
payloadJSON: String? = nil,
error: ClawdisNodeError? = nil)
error: ClawdbotNodeError? = nil)
{
self.type = type
self.id = id

View File

@@ -1,38 +1,38 @@
import Foundation
public enum ClawdisCameraCommand: String, Codable, Sendable {
public enum ClawdbotCameraCommand: String, Codable, Sendable {
case list = "camera.list"
case snap = "camera.snap"
case clip = "camera.clip"
}
public enum ClawdisCameraFacing: String, Codable, Sendable {
public enum ClawdbotCameraFacing: String, Codable, Sendable {
case back
case front
}
public enum ClawdisCameraImageFormat: String, Codable, Sendable {
public enum ClawdbotCameraImageFormat: String, Codable, Sendable {
case jpg
case jpeg
}
public enum ClawdisCameraVideoFormat: String, Codable, Sendable {
public enum ClawdbotCameraVideoFormat: String, Codable, Sendable {
case mp4
}
public struct ClawdisCameraSnapParams: Codable, Sendable, Equatable {
public var facing: ClawdisCameraFacing?
public struct ClawdbotCameraSnapParams: Codable, Sendable, Equatable {
public var facing: ClawdbotCameraFacing?
public var maxWidth: Int?
public var quality: Double?
public var format: ClawdisCameraImageFormat?
public var format: ClawdbotCameraImageFormat?
public var deviceId: String?
public var delayMs: Int?
public init(
facing: ClawdisCameraFacing? = nil,
facing: ClawdbotCameraFacing? = nil,
maxWidth: Int? = nil,
quality: Double? = nil,
format: ClawdisCameraImageFormat? = nil,
format: ClawdbotCameraImageFormat? = nil,
deviceId: String? = nil,
delayMs: Int? = nil)
{
@@ -45,18 +45,18 @@ public struct ClawdisCameraSnapParams: Codable, Sendable, Equatable {
}
}
public struct ClawdisCameraClipParams: Codable, Sendable, Equatable {
public var facing: ClawdisCameraFacing?
public struct ClawdbotCameraClipParams: Codable, Sendable, Equatable {
public var facing: ClawdbotCameraFacing?
public var durationMs: Int?
public var includeAudio: Bool?
public var format: ClawdisCameraVideoFormat?
public var format: ClawdbotCameraVideoFormat?
public var deviceId: String?
public init(
facing: ClawdisCameraFacing? = nil,
facing: ClawdbotCameraFacing? = nil,
durationMs: Int? = nil,
includeAudio: Bool? = nil,
format: ClawdisCameraVideoFormat? = nil,
format: ClawdbotCameraVideoFormat? = nil,
deviceId: String? = nil)
{
self.facing = facing

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisCanvasA2UIAction: Sendable {
public enum ClawdbotCanvasA2UIAction: Sendable {
public struct AgentMessageContext: Sendable {
public struct Session: Sendable {
public var key: String
@@ -94,6 +94,6 @@ public enum ClawdisCanvasA2UIAction: Sendable {
}
return "{\"id\":\"\(actionId)\",\"ok\":\(ok ? "true" : "false"),\"error\":\"\"}"
}()
return "window.dispatchEvent(new CustomEvent('clawdis:a2ui-action-status', { detail: \(json) }));"
return "window.dispatchEvent(new CustomEvent('clawdbot:a2ui-action-status', { detail: \(json) }));"
}
}

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisCanvasA2UICommand: String, Codable, Sendable {
public enum ClawdbotCanvasA2UICommand: String, Codable, Sendable {
/// Render A2UI content on the device canvas.
case push = "canvas.a2ui.push"
/// Legacy alias for `push` when sending JSONL.
@@ -9,7 +9,7 @@ public enum ClawdisCanvasA2UICommand: String, Codable, Sendable {
case reset = "canvas.a2ui.reset"
}
public struct ClawdisCanvasA2UIPushParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasA2UIPushParams: Codable, Sendable, Equatable {
public var messages: [AnyCodable]
public init(messages: [AnyCodable]) {
@@ -17,7 +17,7 @@ public struct ClawdisCanvasA2UIPushParams: Codable, Sendable, Equatable {
}
}
public struct ClawdisCanvasA2UIPushJSONLParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasA2UIPushJSONLParams: Codable, Sendable, Equatable {
public var jsonl: String
public init(jsonl: String) {

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisCanvasA2UIJSONL: Sendable {
public enum ClawdbotCanvasA2UIJSONL: Sendable {
public struct ParsedItem: Sendable {
public var lineNumber: Int
public var message: AnyCodable

View File

@@ -1,6 +1,6 @@
import Foundation
public struct ClawdisCanvasNavigateParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasNavigateParams: Codable, Sendable, Equatable {
public var url: String
public init(url: String) {
@@ -8,7 +8,7 @@ public struct ClawdisCanvasNavigateParams: Codable, Sendable, Equatable {
}
}
public struct ClawdisCanvasPlacement: Codable, Sendable, Equatable {
public struct ClawdbotCanvasPlacement: Codable, Sendable, Equatable {
public var x: Double?
public var y: Double?
public var width: Double?
@@ -22,17 +22,17 @@ public struct ClawdisCanvasPlacement: Codable, Sendable, Equatable {
}
}
public struct ClawdisCanvasPresentParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasPresentParams: Codable, Sendable, Equatable {
public var url: String?
public var placement: ClawdisCanvasPlacement?
public var placement: ClawdbotCanvasPlacement?
public init(url: String? = nil, placement: ClawdisCanvasPlacement? = nil) {
public init(url: String? = nil, placement: ClawdbotCanvasPlacement? = nil) {
self.url = url
self.placement = placement
}
}
public struct ClawdisCanvasEvalParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasEvalParams: Codable, Sendable, Equatable {
public var javaScript: String
public init(javaScript: String) {
@@ -40,7 +40,7 @@ public struct ClawdisCanvasEvalParams: Codable, Sendable, Equatable {
}
}
public enum ClawdisCanvasSnapshotFormat: String, Codable, Sendable {
public enum ClawdbotCanvasSnapshotFormat: String, Codable, Sendable {
case png
case jpeg
@@ -63,12 +63,12 @@ public enum ClawdisCanvasSnapshotFormat: String, Codable, Sendable {
}
}
public struct ClawdisCanvasSnapshotParams: Codable, Sendable, Equatable {
public struct ClawdbotCanvasSnapshotParams: Codable, Sendable, Equatable {
public var maxWidth: Int?
public var quality: Double?
public var format: ClawdisCanvasSnapshotFormat?
public var format: ClawdbotCanvasSnapshotFormat?
public init(maxWidth: Int? = nil, quality: Double? = nil, format: ClawdisCanvasSnapshotFormat? = nil) {
public init(maxWidth: Int? = nil, quality: Double? = nil, format: ClawdbotCanvasSnapshotFormat? = nil) {
self.maxWidth = maxWidth
self.quality = quality
self.format = format

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisCanvasCommand: String, Codable, Sendable {
public enum ClawdbotCanvasCommand: String, Codable, Sendable {
case present = "canvas.present"
case hide = "canvas.hide"
case navigate = "canvas.navigate"

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisCapability: String, Codable, Sendable {
public enum ClawdbotCapability: String, Codable, Sendable {
case canvas
case camera
case screen

View File

@@ -1,5 +1,5 @@
import Foundation
public enum ClawdisKitResources {
public enum ClawdbotKitResources {
public static let bundle: Bundle = .module
}

View File

@@ -37,7 +37,7 @@ public struct AgentDeepLink: Codable, Sendable, Equatable {
public enum DeepLinkParser {
public static func parse(_ url: URL) -> DeepLinkRoute? {
guard url.scheme?.lowercased() == "clawdis" else { return nil }
guard url.scheme?.lowercased() == "clawdbot" else { return nil }
guard let host = url.host?.lowercased(), !host.isEmpty else { return nil }
guard let comps = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil }

View File

@@ -1,28 +1,28 @@
import Foundation
public enum ClawdisLocationCommand: String, Codable, Sendable {
public enum ClawdbotLocationCommand: String, Codable, Sendable {
case get = "location.get"
}
public enum ClawdisLocationAccuracy: String, Codable, Sendable {
public enum ClawdbotLocationAccuracy: String, Codable, Sendable {
case coarse
case balanced
case precise
}
public struct ClawdisLocationGetParams: Codable, Sendable, Equatable {
public struct ClawdbotLocationGetParams: Codable, Sendable, Equatable {
public var timeoutMs: Int?
public var maxAgeMs: Int?
public var desiredAccuracy: ClawdisLocationAccuracy?
public var desiredAccuracy: ClawdbotLocationAccuracy?
public init(timeoutMs: Int? = nil, maxAgeMs: Int? = nil, desiredAccuracy: ClawdisLocationAccuracy? = nil) {
public init(timeoutMs: Int? = nil, maxAgeMs: Int? = nil, desiredAccuracy: ClawdbotLocationAccuracy? = nil) {
self.timeoutMs = timeoutMs
self.maxAgeMs = maxAgeMs
self.desiredAccuracy = desiredAccuracy
}
}
public struct ClawdisLocationPayload: Codable, Sendable, Equatable {
public struct ClawdbotLocationPayload: Codable, Sendable, Equatable {
public var lat: Double
public var lon: Double
public var accuracyMeters: Double

View File

@@ -0,0 +1,7 @@
import Foundation
public enum ClawdbotLocationMode: String, Codable, Sendable, CaseIterable {
case off
case whileUsing
case always
}

View File

@@ -1,6 +1,6 @@
import Foundation
public enum ClawdisNodeErrorCode: String, Codable, Sendable {
public enum ClawdbotNodeErrorCode: String, Codable, Sendable {
case notPaired = "NOT_PAIRED"
case unauthorized = "UNAUTHORIZED"
case backgroundUnavailable = "NODE_BACKGROUND_UNAVAILABLE"
@@ -8,14 +8,14 @@ public enum ClawdisNodeErrorCode: String, Codable, Sendable {
case unavailable = "UNAVAILABLE"
}
public struct ClawdisNodeError: Error, Codable, Sendable, Equatable {
public var code: ClawdisNodeErrorCode
public struct ClawdbotNodeError: Error, Codable, Sendable, Equatable {
public var code: ClawdbotNodeErrorCode
public var message: String
public var retryable: Bool?
public var retryAfterMs: Int?
public init(
code: ClawdisNodeErrorCode,
code: ClawdbotNodeErrorCode,
message: String,
retryable: Bool? = nil,
retryAfterMs: Int? = nil)

View File

@@ -55,7 +55,7 @@
backface-visibility: hidden;
opacity: 0.45;
pointer-events: none;
animation: clawdis-grid-drift 140s ease-in-out infinite alternate;
animation: clawdbot-grid-drift 140s ease-in-out infinite alternate;
}
:root[data-platform="android"] body::before { opacity: 0.80; }
body::after {
@@ -73,7 +73,7 @@
backface-visibility: hidden;
transform: translate3d(0,0,0);
pointer-events: none;
animation: clawdis-glow-drift 110s ease-in-out infinite alternate;
animation: clawdbot-glow-drift 110s ease-in-out infinite alternate;
}
:root[data-platform="android"] body::after { opacity: 0.85; }
@supports (mix-blend-mode: screen) {
@@ -82,12 +82,12 @@
@supports not (mix-blend-mode: screen) {
body::after { opacity: 0.70; }
}
@keyframes clawdis-grid-drift {
@keyframes clawdbot-grid-drift {
0% { transform: translate3d(-12px, 8px, 0) rotate(-7deg); opacity: 0.40; }
50% { transform: translate3d( 10px,-7px, 0) rotate(-6.6deg); opacity: 0.56; }
100% { transform: translate3d(-8px, 6px, 0) rotate(-7.2deg); opacity: 0.42; }
}
@keyframes clawdis-glow-drift {
@keyframes clawdbot-glow-drift {
0% { transform: translate3d(-18px, 12px, 0) scale(1.02); opacity: 0.40; }
50% { transform: translate3d( 14px,-10px, 0) scale(1.05); opacity: 0.52; }
100% { transform: translate3d(-10px, 8px, 0) scale(1.03); opacity: 0.43; }
@@ -101,14 +101,14 @@
touch-action: none;
z-index: 1;
}
:root[data-platform="android"] #clawdis-canvas {
:root[data-platform="android"] #clawdbot-canvas {
background:
radial-gradient(1100px 800px at 20% 15%, rgba(42, 113, 255, 0.78), rgba(0,0,0,0) 58%),
radial-gradient(900px 650px at 82% 28%, rgba(255, 0, 138, 0.66), rgba(0,0,0,0) 62%),
radial-gradient(1000px 900px at 60% 88%, rgba(0, 209, 255, 0.58), rgba(0,0,0,0) 62%),
#141c33;
}
#clawdis-status {
#clawdbot-status {
position: fixed;
inset: 0;
display: none;
@@ -119,7 +119,7 @@
pointer-events: none;
z-index: 3;
}
#clawdis-status .card {
#clawdbot-status .card {
text-align: center;
padding: 16px 18px;
border-radius: 14px;
@@ -129,13 +129,13 @@
-webkit-backdrop-filter: blur(14px);
backdrop-filter: blur(14px);
}
#clawdis-status .title {
#clawdbot-status .title {
font: 600 20px -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, sans-serif;
letter-spacing: 0.2px;
color: rgba(255,255,255,0.92);
text-shadow: 0 0 22px rgba(42, 113, 255, 0.35);
}
#clawdis-status .subtitle {
#clawdbot-status .subtitle {
margin-top: 6px;
font: 500 12px -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
color: rgba(255,255,255,0.58);
@@ -143,20 +143,20 @@
</style>
</head>
<body>
<canvas id="clawdis-canvas"></canvas>
<div id="clawdis-status">
<canvas id="clawdbot-canvas"></canvas>
<div id="clawdbot-status">
<div class="card">
<div class="title" id="clawdis-status-title">Ready</div>
<div class="subtitle" id="clawdis-status-subtitle">Waiting for agent</div>
<div class="title" id="clawdbot-status-title">Ready</div>
<div class="subtitle" id="clawdbot-status-subtitle">Waiting for agent</div>
</div>
</div>
<script>
(() => {
const canvas = document.getElementById('clawdis-canvas');
const canvas = document.getElementById('clawdbot-canvas');
const ctx = canvas.getContext('2d');
const statusEl = document.getElementById('clawdis-status');
const titleEl = document.getElementById('clawdis-status-title');
const subtitleEl = document.getElementById('clawdis-status-subtitle');
const statusEl = document.getElementById('clawdbot-status');
const titleEl = document.getElementById('clawdbot-status-title');
const subtitleEl = document.getElementById('clawdbot-status-subtitle');
const debugStatusEnabledByQuery = (() => {
try {
const params = new URLSearchParams(window.location.search);
@@ -194,7 +194,7 @@
statusEl.style.display = 'none';
}
window.__clawdis = {
window.__clawdbot = {
canvas,
ctx,
setDebugStatusEnabled,

View File

@@ -1,10 +1,10 @@
import Foundation
public enum ClawdisScreenCommand: String, Codable, Sendable {
public enum ClawdbotScreenCommand: String, Codable, Sendable {
case record = "screen.record"
}
public struct ClawdisScreenRecordParams: Codable, Sendable, Equatable {
public struct ClawdbotScreenRecordParams: Codable, Sendable, Equatable {
public var screenIndex: Int?
public var durationMs: Int?
public var fps: Double?

View File

@@ -1,14 +1,14 @@
import Foundation
public enum ClawdisNodeStorage {
public enum ClawdbotNodeStorage {
public static func appSupportDir() throws -> URL {
let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
guard let base else {
throw NSError(domain: "ClawdisNodeStorage", code: 1, userInfo: [
throw NSError(domain: "ClawdbotNodeStorage", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Application Support directory unavailable",
])
}
return base.appendingPathComponent("Clawdis", isDirectory: true)
return base.appendingPathComponent("Clawdbot", isDirectory: true)
}
public static func canvasRoot(sessionKey: String) throws -> URL {
@@ -21,11 +21,11 @@ public enum ClawdisNodeStorage {
public static func cachesDir() throws -> URL {
let base = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
guard let base else {
throw NSError(domain: "ClawdisNodeStorage", code: 2, userInfo: [
throw NSError(domain: "ClawdbotNodeStorage", code: 2, userInfo: [
NSLocalizedDescriptionKey: "Caches directory unavailable",
])
}
return base.appendingPathComponent("Clawdis", isDirectory: true)
return base.appendingPathComponent("Clawdbot", isDirectory: true)
}
public static func canvasSnapshotsRoot(sessionKey: String) throws -> URL {

View File

@@ -1,23 +1,23 @@
import Foundation
public enum ClawdisSystemCommand: String, Codable, Sendable {
public enum ClawdbotSystemCommand: String, Codable, Sendable {
case run = "system.run"
case notify = "system.notify"
}
public enum ClawdisNotificationPriority: String, Codable, Sendable {
public enum ClawdbotNotificationPriority: String, Codable, Sendable {
case passive
case active
case timeSensitive
}
public enum ClawdisNotificationDelivery: String, Codable, Sendable {
public enum ClawdbotNotificationDelivery: String, Codable, Sendable {
case system
case overlay
case auto
}
public struct ClawdisSystemRunParams: Codable, Sendable, Equatable {
public struct ClawdbotSystemRunParams: Codable, Sendable, Equatable {
public var command: [String]
public var cwd: String?
public var env: [String: String]?
@@ -39,19 +39,19 @@ public struct ClawdisSystemRunParams: Codable, Sendable, Equatable {
}
}
public struct ClawdisSystemNotifyParams: Codable, Sendable, Equatable {
public struct ClawdbotSystemNotifyParams: Codable, Sendable, Equatable {
public var title: String
public var body: String
public var sound: String?
public var priority: ClawdisNotificationPriority?
public var delivery: ClawdisNotificationDelivery?
public var priority: ClawdbotNotificationPriority?
public var delivery: ClawdbotNotificationDelivery?
public init(
title: String,
body: String,
sound: String? = nil,
priority: ClawdisNotificationPriority? = nil,
delivery: ClawdisNotificationDelivery? = nil)
priority: ClawdbotNotificationPriority? = nil,
delivery: ClawdbotNotificationDelivery? = nil)
{
self.title = title
self.body = body

View File

@@ -90,7 +90,7 @@ public enum ToolDisplayRegistry {
}
private static func loadConfig() -> ToolDisplayConfig {
guard let url = ClawdisKitResources.bundle.url(forResource: "tool-display", withExtension: "json") else {
guard let url = ClawdbotKitResources.bundle.url(forResource: "tool-display", withExtension: "json") else {
return ToolDisplayConfig(version: nil, fallback: nil, tools: nil)
}
do {

View File

@@ -1,4 +1,4 @@
@testable import ClawdisChatUI
@testable import ClawdbotChatUI
import Testing
@Suite struct AssistantTextParserTests {

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import Testing
@Suite struct BonjourEscapesTests {
@@ -8,7 +8,7 @@ import Testing
}
@Test func decodeSpaces() {
#expect(BonjourEscapes.decode("Clawdis\\032Gateway") == "Clawdis Gateway")
#expect(BonjourEscapes.decode("Clawdbot\\032Gateway") == "Clawdbot Gateway")
}
@Test func decodeMultipleEscapes() {

View File

@@ -1,28 +1,28 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Testing
@Suite struct CanvasA2UIActionTests {
@Test func sanitizeTagValueIsStable() {
#expect(ClawdisCanvasA2UIAction.sanitizeTagValue("Hello World!") == "Hello_World_")
#expect(ClawdisCanvasA2UIAction.sanitizeTagValue(" ") == "-")
#expect(ClawdisCanvasA2UIAction.sanitizeTagValue("macOS 26.2") == "macOS_26.2")
#expect(ClawdbotCanvasA2UIAction.sanitizeTagValue("Hello World!") == "Hello_World_")
#expect(ClawdbotCanvasA2UIAction.sanitizeTagValue(" ") == "-")
#expect(ClawdbotCanvasA2UIAction.sanitizeTagValue("macOS 26.2") == "macOS_26.2")
}
@Test func extractActionNameAcceptsNameOrAction() {
#expect(ClawdisCanvasA2UIAction.extractActionName(["name": "Hello"]) == "Hello")
#expect(ClawdisCanvasA2UIAction.extractActionName(["action": "Wave"]) == "Wave")
#expect(ClawdisCanvasA2UIAction.extractActionName(["name": " ", "action": "Fallback"]) == "Fallback")
#expect(ClawdisCanvasA2UIAction.extractActionName(["action": " "]) == nil)
#expect(ClawdbotCanvasA2UIAction.extractActionName(["name": "Hello"]) == "Hello")
#expect(ClawdbotCanvasA2UIAction.extractActionName(["action": "Wave"]) == "Wave")
#expect(ClawdbotCanvasA2UIAction.extractActionName(["name": " ", "action": "Fallback"]) == "Fallback")
#expect(ClawdbotCanvasA2UIAction.extractActionName(["action": " "]) == nil)
}
@Test func formatAgentMessageIsTokenEfficientAndUnambiguous() {
let messageContext = ClawdisCanvasA2UIAction.AgentMessageContext(
let messageContext = ClawdbotCanvasA2UIAction.AgentMessageContext(
actionName: "Get Weather",
session: .init(key: "main", surfaceId: "main"),
component: .init(id: "btnWeather", host: "Peters iPad", instanceId: "ipad16,6"),
contextJSON: "{\"city\":\"Vienna\"}")
let msg = ClawdisCanvasA2UIAction.formatAgentMessage(messageContext)
let msg = ClawdbotCanvasA2UIAction.formatAgentMessage(messageContext)
#expect(msg.contains("CANVAS_A2UI "))
#expect(msg.contains("action=Get_Weather"))

View File

@@ -1,11 +1,11 @@
import ClawdisKit
import ClawdbotKit
import Testing
@Suite struct CanvasA2UITests {
@Test func commandStringsAreStable() {
#expect(ClawdisCanvasA2UICommand.push.rawValue == "canvas.a2ui.push")
#expect(ClawdisCanvasA2UICommand.pushJSONL.rawValue == "canvas.a2ui.pushJSONL")
#expect(ClawdisCanvasA2UICommand.reset.rawValue == "canvas.a2ui.reset")
#expect(ClawdbotCanvasA2UICommand.push.rawValue == "canvas.a2ui.push")
#expect(ClawdbotCanvasA2UICommand.pushJSONL.rawValue == "canvas.a2ui.pushJSONL")
#expect(ClawdbotCanvasA2UICommand.reset.rawValue == "canvas.a2ui.reset")
}
@Test func jsonlDecodesAndValidatesV0_8() throws {
@@ -16,7 +16,7 @@ import Testing
{"deleteSurface":{"surfaceId":"main"}}
"""
let messages = try ClawdisCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
let messages = try ClawdbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
#expect(messages.count == 4)
}
@@ -26,7 +26,7 @@ import Testing
"""
#expect(throws: Error.self) {
_ = try ClawdisCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
_ = try ClawdbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
}
}
@@ -36,7 +36,7 @@ import Testing
"""
#expect(throws: Error.self) {
_ = try ClawdisCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
_ = try ClawdbotCanvasA2UIJSONL.decodeMessagesFromJSONL(jsonl)
}
}
}

View File

@@ -1,11 +1,11 @@
import ClawdisKit
import ClawdbotKit
import Foundation
import Testing
@Suite struct CanvasSnapshotFormatTests {
@Test func acceptsJpgAlias() throws {
struct Wrapper: Codable {
var format: ClawdisCanvasSnapshotFormat
var format: ClawdbotCanvasSnapshotFormat
}
let data = try #require("{\"format\":\"jpg\"}".data(using: .utf8))

View File

@@ -1,4 +1,4 @@
@testable import ClawdisChatUI
@testable import ClawdbotChatUI
import Foundation
import Testing
@@ -19,8 +19,8 @@ private func luminance(_ color: NSColor) throws -> CGFloat {
let lightAppearance = try #require(NSAppearance(named: .aqua))
let darkAppearance = try #require(NSAppearance(named: .darkAqua))
let lightResolved = ClawdisChatTheme.resolvedAssistantBubbleColor(for: lightAppearance)
let darkResolved = ClawdisChatTheme.resolvedAssistantBubbleColor(for: darkAppearance)
let lightResolved = ClawdbotChatTheme.resolvedAssistantBubbleColor(for: lightAppearance)
let darkResolved = ClawdbotChatTheme.resolvedAssistantBubbleColor(for: darkAppearance)
#expect(try luminance(lightResolved) > luminance(darkResolved))
#else
#expect(Bool(true))

View File

@@ -1,5 +1,5 @@
@testable import ClawdisChatUI
import ClawdisKit
@testable import ClawdbotChatUI
import ClawdbotKit
import Foundation
import Testing
@@ -31,40 +31,40 @@ private actor TestChatTransportState {
var abortedRunIds: [String] = []
}
private final class TestChatTransport: @unchecked Sendable, ClawdisChatTransport {
private final class TestChatTransport: @unchecked Sendable, ClawdbotChatTransport {
private let state = TestChatTransportState()
private let historyResponses: [ClawdisChatHistoryPayload]
private let sessionsResponses: [ClawdisChatSessionsListResponse]
private let historyResponses: [ClawdbotChatHistoryPayload]
private let sessionsResponses: [ClawdbotChatSessionsListResponse]
private let stream: AsyncStream<ClawdisChatTransportEvent>
private let continuation: AsyncStream<ClawdisChatTransportEvent>.Continuation
private let stream: AsyncStream<ClawdbotChatTransportEvent>
private let continuation: AsyncStream<ClawdbotChatTransportEvent>.Continuation
init(
historyResponses: [ClawdisChatHistoryPayload],
sessionsResponses: [ClawdisChatSessionsListResponse] = [])
historyResponses: [ClawdbotChatHistoryPayload],
sessionsResponses: [ClawdbotChatSessionsListResponse] = [])
{
self.historyResponses = historyResponses
self.sessionsResponses = sessionsResponses
var cont: AsyncStream<ClawdisChatTransportEvent>.Continuation!
var cont: AsyncStream<ClawdbotChatTransportEvent>.Continuation!
self.stream = AsyncStream { c in
cont = c
}
self.continuation = cont
}
func events() -> AsyncStream<ClawdisChatTransportEvent> {
func events() -> AsyncStream<ClawdbotChatTransportEvent> {
self.stream
}
func setActiveSessionKey(_: String) async throws {}
func requestHistory(sessionKey: String) async throws -> ClawdisChatHistoryPayload {
func requestHistory(sessionKey: String) async throws -> ClawdbotChatHistoryPayload {
let idx = await self.state.historyCallCount
await self.state.setHistoryCallCount(idx + 1)
if idx < self.historyResponses.count {
return self.historyResponses[idx]
}
return self.historyResponses.last ?? ClawdisChatHistoryPayload(
return self.historyResponses.last ?? ClawdbotChatHistoryPayload(
sessionKey: sessionKey,
sessionId: nil,
messages: [],
@@ -76,23 +76,23 @@ private final class TestChatTransport: @unchecked Sendable, ClawdisChatTransport
message _: String,
thinking _: String,
idempotencyKey: String,
attachments _: [ClawdisChatAttachmentPayload]) async throws -> ClawdisChatSendResponse
attachments _: [ClawdbotChatAttachmentPayload]) async throws -> ClawdbotChatSendResponse
{
await self.state.sentRunIdsAppend(idempotencyKey)
return ClawdisChatSendResponse(runId: idempotencyKey, status: "ok")
return ClawdbotChatSendResponse(runId: idempotencyKey, status: "ok")
}
func abortRun(sessionKey _: String, runId: String) async throws {
await self.state.abortedRunIdsAppend(runId)
}
func listSessions(limit _: Int?) async throws -> ClawdisChatSessionsListResponse {
func listSessions(limit _: Int?) async throws -> ClawdbotChatSessionsListResponse {
let idx = await self.state.sessionsCallCount
await self.state.setSessionsCallCount(idx + 1)
if idx < self.sessionsResponses.count {
return self.sessionsResponses[idx]
}
return self.sessionsResponses.last ?? ClawdisChatSessionsListResponse(
return self.sessionsResponses.last ?? ClawdbotChatSessionsListResponse(
ts: nil,
path: nil,
count: 0,
@@ -104,7 +104,7 @@ private final class TestChatTransport: @unchecked Sendable, ClawdisChatTransport
true
}
func emit(_ evt: ClawdisChatTransportEvent) {
func emit(_ evt: ClawdbotChatTransportEvent) {
self.continuation.yield(evt)
}
@@ -139,12 +139,12 @@ private extension TestChatTransportState {
@Suite struct ChatViewModelTests {
@Test func streamsAssistantAndClearsOnFinal() async throws {
let sessionId = "sess-main"
let history1 = ClawdisChatHistoryPayload(
let history1 = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: sessionId,
messages: [],
thinkingLevel: "off")
let history2 = ClawdisChatHistoryPayload(
let history2 = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: sessionId,
messages: [
@@ -157,7 +157,7 @@ private extension TestChatTransportState {
thinkingLevel: "off")
let transport = TestChatTransport(historyResponses: [history1, history2])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "main", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "main", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } }
@@ -170,7 +170,7 @@ private extension TestChatTransportState {
transport.emit(
.agent(
ClawdisAgentEventPayload(
ClawdbotAgentEventPayload(
runId: sessionId,
seq: 1,
stream: "assistant",
@@ -181,7 +181,7 @@ private extension TestChatTransportState {
transport.emit(
.agent(
ClawdisAgentEventPayload(
ClawdbotAgentEventPayload(
runId: sessionId,
seq: 2,
stream: "tool",
@@ -198,7 +198,7 @@ private extension TestChatTransportState {
let runId = try #require(await transport.lastSentRunId())
transport.emit(
.chat(
ClawdisChatEventPayload(
ClawdbotChatEventPayload(
runId: runId,
sessionKey: "main",
state: "final",
@@ -213,20 +213,20 @@ private extension TestChatTransportState {
@Test func clearsStreamingOnExternalFinalEvent() async throws {
let sessionId = "sess-main"
let history = ClawdisChatHistoryPayload(
let history = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: sessionId,
messages: [],
thinkingLevel: "off")
let transport = TestChatTransport(historyResponses: [history, history])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "main", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "main", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } }
transport.emit(
.agent(
ClawdisAgentEventPayload(
ClawdbotAgentEventPayload(
runId: sessionId,
seq: 1,
stream: "assistant",
@@ -235,7 +235,7 @@ private extension TestChatTransportState {
transport.emit(
.agent(
ClawdisAgentEventPayload(
ClawdbotAgentEventPayload(
runId: sessionId,
seq: 2,
stream: "tool",
@@ -252,7 +252,7 @@ private extension TestChatTransportState {
transport.emit(
.chat(
ClawdisChatEventPayload(
ClawdbotChatEventPayload(
runId: "other-run",
sessionKey: "main",
state: "final",
@@ -268,18 +268,18 @@ private extension TestChatTransportState {
let recent = now - (2 * 60 * 60 * 1000)
let recentOlder = now - (5 * 60 * 60 * 1000)
let stale = now - (26 * 60 * 60 * 1000)
let history = ClawdisChatHistoryPayload(
let history = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: "sess-main",
messages: [],
thinkingLevel: "off")
let sessions = ClawdisChatSessionsListResponse(
let sessions = ClawdbotChatSessionsListResponse(
ts: now,
path: nil,
count: 4,
defaults: nil,
sessions: [
ClawdisChatSessionEntry(
ClawdbotChatSessionEntry(
key: "recent-1",
kind: nil,
displayName: nil,
@@ -298,7 +298,7 @@ private extension TestChatTransportState {
totalTokens: nil,
model: nil,
contextTokens: nil),
ClawdisChatSessionEntry(
ClawdbotChatSessionEntry(
key: "main",
kind: nil,
displayName: nil,
@@ -317,7 +317,7 @@ private extension TestChatTransportState {
totalTokens: nil,
model: nil,
contextTokens: nil),
ClawdisChatSessionEntry(
ClawdbotChatSessionEntry(
key: "recent-2",
kind: nil,
displayName: nil,
@@ -336,7 +336,7 @@ private extension TestChatTransportState {
totalTokens: nil,
model: nil,
contextTokens: nil),
ClawdisChatSessionEntry(
ClawdbotChatSessionEntry(
key: "old-1",
kind: nil,
displayName: nil,
@@ -360,7 +360,7 @@ private extension TestChatTransportState {
let transport = TestChatTransport(
historyResponses: [history],
sessionsResponses: [sessions])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "main", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "main", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("sessions loaded") { await MainActor.run { !vm.sessions.isEmpty } }
@@ -371,18 +371,18 @@ private extension TestChatTransportState {
@Test func sessionChoicesIncludeCurrentWhenMissing() async throws {
let now = Date().timeIntervalSince1970 * 1000
let recent = now - (30 * 60 * 1000)
let history = ClawdisChatHistoryPayload(
let history = ClawdbotChatHistoryPayload(
sessionKey: "custom",
sessionId: "sess-custom",
messages: [],
thinkingLevel: "off")
let sessions = ClawdisChatSessionsListResponse(
let sessions = ClawdbotChatSessionsListResponse(
ts: now,
path: nil,
count: 1,
defaults: nil,
sessions: [
ClawdisChatSessionEntry(
ClawdbotChatSessionEntry(
key: "main",
kind: nil,
displayName: nil,
@@ -406,7 +406,7 @@ private extension TestChatTransportState {
let transport = TestChatTransport(
historyResponses: [history],
sessionsResponses: [sessions])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "custom", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "custom", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("sessions loaded") { await MainActor.run { !vm.sessions.isEmpty } }
@@ -416,20 +416,20 @@ private extension TestChatTransportState {
@Test func clearsStreamingOnExternalErrorEvent() async throws {
let sessionId = "sess-main"
let history = ClawdisChatHistoryPayload(
let history = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: sessionId,
messages: [],
thinkingLevel: "off")
let transport = TestChatTransport(historyResponses: [history, history])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "main", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "main", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } }
transport.emit(
.agent(
ClawdisAgentEventPayload(
ClawdbotAgentEventPayload(
runId: sessionId,
seq: 1,
stream: "assistant",
@@ -440,7 +440,7 @@ private extension TestChatTransportState {
transport.emit(
.chat(
ClawdisChatEventPayload(
ClawdbotChatEventPayload(
runId: "other-run",
sessionKey: "main",
state: "error",
@@ -452,13 +452,13 @@ private extension TestChatTransportState {
@Test func abortRequestsDoNotClearPendingUntilAbortedEvent() async throws {
let sessionId = "sess-main"
let history = ClawdisChatHistoryPayload(
let history = ClawdbotChatHistoryPayload(
sessionKey: "main",
sessionId: sessionId,
messages: [],
thinkingLevel: "off")
let transport = TestChatTransport(historyResponses: [history, history])
let vm = await MainActor.run { ClawdisChatViewModel(sessionKey: "main", transport: transport) }
let vm = await MainActor.run { ClawdbotChatViewModel(sessionKey: "main", transport: transport) }
await MainActor.run { vm.load() }
try await waitUntil("bootstrap") { await MainActor.run { vm.healthOK && vm.sessionId == sessionId } }
@@ -482,7 +482,7 @@ private extension TestChatTransportState {
transport.emit(
.chat(
ClawdisChatEventPayload(
ClawdbotChatEventPayload(
runId: runId,
sessionKey: "main",
state: "aborted",

View File

@@ -1,5 +1,5 @@
import XCTest
@testable import ClawdisKit
@testable import ClawdbotKit
final class ElevenLabsTTSValidationTests: XCTestCase {
func testValidatedOutputFormatAllowsOnlyMp3Presets() {

View File

@@ -1,4 +1,4 @@
import ClawdisKit
import ClawdbotKit
import CoreGraphics
import ImageIO
import Testing

View File

@@ -1,5 +1,5 @@
import XCTest
@testable import ClawdisKit
@testable import ClawdbotKit
final class TalkDirectiveTests: XCTestCase {
func testParsesDirectiveAndStripsLine() {

View File

@@ -1,5 +1,5 @@
import XCTest
@testable import ClawdisKit
@testable import ClawdbotKit
final class TalkHistoryTimestampTests: XCTestCase {
func testSecondsTimestampsAreAcceptedWithSmallTolerance() {

View File

@@ -1,5 +1,5 @@
import XCTest
@testable import ClawdisKit
@testable import ClawdbotKit
final class TalkPromptBuilderTests: XCTestCase {
func testBuildIncludesTranscript() {

View File

@@ -4,7 +4,7 @@ import { ContextProvider } from "@lit/context";
import { v0_8 } from "@a2ui/lit";
import "@a2ui/lit/ui";
import { themeContext } from "@clawdis/a2ui-theme-context";
import { themeContext } from "@clawdbot/a2ui-theme-context";
const modalStyles = css`
dialog {
@@ -42,7 +42,7 @@ const buttonShadow = isAndroid ? "0 2px 10px rgba(6, 182, 212, 0.14)" : "0 10px
const statusShadow = isAndroid ? "0 2px 10px rgba(0, 0, 0, 0.18)" : "0 10px 24px rgba(0, 0, 0, 0.25)";
const statusBlur = isAndroid ? "10px" : "14px";
const clawdisTheme = {
const clawdbotTheme = {
components: {
AudioPlayer: emptyClasses(),
Button: emptyClasses(),
@@ -152,7 +152,7 @@ const clawdisTheme = {
},
};
class ClawdisA2UIHost extends LitElement {
class ClawdbotA2UIHost extends LitElement {
static properties = {
surfaces: { state: true },
pendingAction: { state: true },
@@ -162,7 +162,7 @@ class ClawdisA2UIHost extends LitElement {
#processor = v0_8.Data.createSignalA2uiMessageProcessor();
#themeProvider = new ContextProvider(this, {
context: themeContext,
initialValue: clawdisTheme,
initialValue: clawdbotTheme,
});
surfaces = [];
@@ -177,10 +177,10 @@ class ClawdisA2UIHost extends LitElement {
position: relative;
box-sizing: border-box;
padding:
var(--clawdis-a2ui-inset-top, 0px)
var(--clawdis-a2ui-inset-right, 0px)
var(--clawdis-a2ui-inset-bottom, 0px)
var(--clawdis-a2ui-inset-left, 0px);
var(--clawdbot-a2ui-inset-top, 0px)
var(--clawdbot-a2ui-inset-right, 0px)
var(--clawdbot-a2ui-inset-bottom, 0px)
var(--clawdbot-a2ui-inset-left, 0px);
}
#surfaces {
@@ -189,14 +189,14 @@ class ClawdisA2UIHost extends LitElement {
gap: 12px;
height: 100%;
overflow: auto;
padding-bottom: var(--clawdis-a2ui-scroll-pad-bottom, 0px);
padding-bottom: var(--clawdbot-a2ui-scroll-pad-bottom, 0px);
}
.status {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: var(--clawdis-a2ui-status-top, 12px);
top: var(--clawdbot-a2ui-status-top, 12px);
display: inline-flex;
align-items: center;
gap: 8px;
@@ -217,7 +217,7 @@ class ClawdisA2UIHost extends LitElement {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: var(--clawdis-a2ui-toast-bottom, 12px);
bottom: var(--clawdbot-a2ui-toast-bottom, 12px);
display: inline-flex;
align-items: center;
gap: 8px;
@@ -243,7 +243,7 @@ class ClawdisA2UIHost extends LitElement {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: var(--clawdis-a2ui-empty-top, var(--clawdis-a2ui-status-top, 12px));
top: var(--clawdbot-a2ui-empty-top, var(--clawdbot-a2ui-status-top, 12px));
text-align: center;
opacity: 0.8;
padding: 10px 12px;
@@ -276,21 +276,21 @@ class ClawdisA2UIHost extends LitElement {
connectedCallback() {
super.connectedCallback();
globalThis.clawdisA2UI = {
globalThis.clawdbotA2UI = {
applyMessages: (messages) => this.applyMessages(messages),
reset: () => this.reset(),
getSurfaces: () => Array.from(this.#processor.getSurfaces().keys()),
};
this.addEventListener("a2uiaction", (evt) => this.#handleA2UIAction(evt));
this.#statusListener = (evt) => this.#handleActionStatus(evt);
globalThis.addEventListener("clawdis:a2ui-action-status", this.#statusListener);
globalThis.addEventListener("clawdbot:a2ui-action-status", this.#statusListener);
this.#syncSurfaces();
}
disconnectedCallback() {
super.disconnectedCallback();
if (this.#statusListener) {
globalThis.removeEventListener("clawdis:a2ui-action-status", this.#statusListener);
globalThis.removeEventListener("clawdbot:a2ui-action-status", this.#statusListener);
this.#statusListener = null;
}
}
@@ -393,15 +393,15 @@ class ClawdisA2UIHost extends LitElement {
...(Object.keys(context).length ? { context } : {}),
};
globalThis.__clawdisLastA2UIAction = userAction;
globalThis.__clawdbotLastA2UIAction = userAction;
const handler =
globalThis.webkit?.messageHandlers?.clawdisCanvasA2UIAction ??
globalThis.clawdisCanvasA2UIAction;
globalThis.webkit?.messageHandlers?.clawdbotCanvasA2UIAction ??
globalThis.clawdbotCanvasA2UIAction;
if (handler?.postMessage) {
try {
// WebKit message handlers support structured objects; Android's JS interface expects strings.
if (handler === globalThis.clawdisCanvasA2UIAction) {
if (handler === globalThis.clawdbotCanvasA2UIAction) {
handler.postMessage(JSON.stringify({ userAction }));
} else {
handler.postMessage({ userAction });
@@ -481,4 +481,4 @@ class ClawdisA2UIHost extends LitElement {
}
}
customElements.define("clawdis-a2ui-host", ClawdisA2UIHost);
customElements.define("clawdbot-a2ui-host", ClawdbotA2UIHost);

View File

@@ -27,7 +27,7 @@ export default defineConfig({
alias: {
"@a2ui/lit": path.resolve(a2uiLitDist, "index.js"),
"@a2ui/lit/ui": path.resolve(a2uiLitDist, "0.8/ui/ui.js"),
"@clawdis/a2ui-theme-context": a2uiThemeContext,
"@clawdbot/a2ui-theme-context": a2uiThemeContext,
"@lit/context": path.resolve(repoRoot, "node_modules/@lit/context/index.js"),
"@lit/context/": path.resolve(repoRoot, "node_modules/@lit/context/"),
"@lit-labs/signals": path.resolve(repoRoot, "node_modules/@lit-labs/signals/index.js"),

View File

@@ -1,7 +0,0 @@
import Foundation
public enum ClawdisLocationMode: String, Codable, Sendable, CaseIterable {
case off
case whileUsing
case always
}