Files
bot/apps/macos/Sources/Bot/OnboardingView+Workspace.swift
zooqueen fd1d312208 feat: merge upstream improvements via rebrand bridge
Squash merge of 1,462 upstream commits with openclaw→hanzo-bot
naming transforms applied. Conflicts resolved favoring our main
branch to preserve existing customizations.

Key upstream additions:
- iOS Security Stack (concurrency locks, runtime guards, TTS fallback)
- Discord CDN hostname allowlisting for SSRF protection
- Discord mention handling improvements
- Various bug fixes and stability improvements
2026-03-03 09:38:30 -08:00

98 lines
3.6 KiB
Swift

import Foundation
extension OnboardingView {
func loadWorkspaceDefaults() async {
guard self.workspacePath.isEmpty else { return }
let configured = await self.loadAgentWorkspace()
let url = AgentWorkspace.resolveWorkspaceURL(from: configured)
self.workspacePath = AgentWorkspace.displayPath(for: url)
self.refreshBootstrapStatus()
}
func ensureDefaultWorkspace() async {
guard self.state.connectionMode == .local else { return }
let configured = await self.loadAgentWorkspace()
let url = AgentWorkspace.resolveWorkspaceURL(from: configured)
switch AgentWorkspace.bootstrapSafety(for: url) {
case .safe:
do {
_ = try AgentWorkspace.bootstrap(workspaceURL: url)
if (configured ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
await self.saveAgentWorkspace(AgentWorkspace.displayPath(for: url))
}
} catch {
self.workspaceStatus = "Failed to create workspace: \(error.localizedDescription)"
}
case let .unsafe (reason):
self.workspaceStatus = "Workspace not touched: \(reason)"
}
self.refreshBootstrapStatus()
}
func refreshBootstrapStatus() {
let url = AgentWorkspace.resolveWorkspaceURL(from: self.workspacePath)
self.needsBootstrap = AgentWorkspace.needsBootstrap(workspaceURL: url)
if self.needsBootstrap {
self.didAutoKickoff = false
}
}
var workspaceBootstrapCommand: String {
let template = AgentWorkspace.defaultTemplate().trimmingCharacters(in: .whitespacesAndNewlines)
return """
mkdir -p ~/.hanzo-bot/workspace
cat > ~/.hanzo-bot/workspace/AGENTS.md <<'EOF'
\(template)
EOF
"""
}
func applyWorkspace() async {
guard !self.workspaceApplying else { return }
self.workspaceApplying = true
defer { self.workspaceApplying = false }
do {
let url = AgentWorkspace.resolveWorkspaceURL(from: self.workspacePath)
if case let .unsafe (reason) = AgentWorkspace.bootstrapSafety(for: url) {
self.workspaceStatus = "Workspace not created: \(reason)"
return
}
_ = try AgentWorkspace.bootstrap(workspaceURL: url)
self.workspacePath = AgentWorkspace.displayPath(for: url)
self.workspaceStatus = "Workspace ready at \(self.workspacePath)"
self.refreshBootstrapStatus()
} catch {
self.workspaceStatus = "Failed to create workspace: \(error.localizedDescription)"
}
}
private func loadAgentWorkspace() async -> String? {
let root = await ConfigStore.load()
return AgentWorkspaceConfig.workspace(from: root)
}
@discardableResult
func saveAgentWorkspace(_ workspace: String?) async -> Bool {
let (success, errorMessage) = await OnboardingView.buildAndSaveWorkspace(workspace)
if let errorMessage {
self.workspaceStatus = errorMessage
}
return success
}
@MainActor
private static func buildAndSaveWorkspace(_ workspace: String?) async -> (Bool, String?) {
var root = await ConfigStore.load()
AgentWorkspaceConfig.setWorkspace(in: &root, workspace: workspace)
do {
try await ConfigStore.save(root)
return (true, nil)
} catch {
let errorMessage = "Failed to save config: \(error.localizedDescription)"
return (false, errorMessage)
}
}
}