feat(macos): onboard Claude OAuth + identity

This commit is contained in:
Peter Steinberger
2025-12-14 04:21:20 +00:00
parent a47d3e3e35
commit a097c848bb
6 changed files with 565 additions and 4 deletions

View File

@@ -4,6 +4,8 @@ import OSLog
enum AgentWorkspace {
private static let logger = Logger(subsystem: "com.steipete.clawdis", category: "workspace")
static let agentsFilename = "AGENTS.md"
static let identityStartMarker = "<!-- clawdis:identity:start -->"
static let identityEndMarker = "<!-- clawdis:identity:end -->"
static func displayPath(for url: URL) -> String {
let home = FileManager.default.homeDirectoryForCurrentUser.path
@@ -36,6 +38,31 @@ enum AgentWorkspace {
return agentsURL
}
static func upsertIdentity(workspaceURL: URL, identity: AgentIdentity) throws {
let agentsURL = try self.bootstrap(workspaceURL: workspaceURL)
var content = (try? String(contentsOf: agentsURL, encoding: .utf8)) ?? ""
let block = self.identityBlock(identity: identity)
if let start = content.range(of: self.identityStartMarker),
let end = content.range(of: self.identityEndMarker),
start.lowerBound < end.upperBound
{
content.replaceSubrange(
start.lowerBound..<end.upperBound,
with: block.trimmingCharacters(in: .whitespacesAndNewlines))
} else if let insert = self.identityInsertRange(in: content) {
content.insert(contentsOf: "\n\n## Identity\n\(block)\n", at: insert.upperBound)
} else {
content = [content.trimmingCharacters(in: .whitespacesAndNewlines), "## Identity\n\(block)"]
.filter { !$0.isEmpty }
.joined(separator: "\n\n")
.appending("\n")
}
try content.write(to: agentsURL, atomically: true, encoding: .utf8)
self.logger.info("Updated identity in \(agentsURL.path, privacy: .public)")
}
static func defaultTemplate() -> String {
"""
# AGENTS.md — Clawdis Workspace
@@ -51,4 +78,26 @@ enum AgentWorkspace {
- Add your preferred style, rules, and “memory” here.
"""
}
private static func identityBlock(identity: AgentIdentity) -> String {
let name = identity.name.trimmingCharacters(in: .whitespacesAndNewlines)
let theme = identity.theme.trimmingCharacters(in: .whitespacesAndNewlines)
let emoji = identity.emoji.trimmingCharacters(in: .whitespacesAndNewlines)
return """
\(self.identityStartMarker)
- Name: \(name)
- Theme: \(theme)
- Emoji: \(emoji)
\(self.identityEndMarker)
"""
}
private static func identityInsertRange(in content: String) -> Range<String.Index>? {
if let firstHeading = content.range(of: "\n") {
// Insert after the first line (usually "# AGENTS.md ")
return firstHeading
}
return nil
}
}