Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
307
apps/macos/Sources/OpenClaw/PairingAlertSupport.swift
Normal file
307
apps/macos/Sources/OpenClaw/PairingAlertSupport.swift
Normal file
@@ -0,0 +1,307 @@
|
||||
import AppKit
|
||||
import OpenClawKit
|
||||
import OSLog
|
||||
|
||||
final class PairingAlertHostWindow: NSWindow {
|
||||
override var canBecomeKey: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override var canBecomeMain: Bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class PairingAlertState {
|
||||
var activeAlert: NSAlert?
|
||||
var activeRequestId: String?
|
||||
var alertHostWindow: NSWindow?
|
||||
}
|
||||
|
||||
@MainActor
|
||||
enum PairingAlertSupport {
|
||||
enum PairingResolution: String {
|
||||
case approved
|
||||
case rejected
|
||||
}
|
||||
|
||||
struct ButtonTitles {
|
||||
var approve: String = "Approve"
|
||||
var postpone: String = "Not Now"
|
||||
var reject: String = "Reject"
|
||||
|
||||
init(approve: String = "Approve", postpone: String = "Not Now", reject: String = "Reject") {
|
||||
self.approve = approve
|
||||
self.postpone = postpone
|
||||
self.reject = reject
|
||||
}
|
||||
}
|
||||
|
||||
struct PairingResolvedEvent: Codable {
|
||||
let requestId: String
|
||||
let decision: String
|
||||
let ts: Double
|
||||
}
|
||||
|
||||
static func endActiveAlert(activeAlert: inout NSAlert?, activeRequestId: inout String?) {
|
||||
guard let alert = activeAlert else { return }
|
||||
if let parent = alert.window.sheetParent {
|
||||
parent.endSheet(alert.window, returnCode: .abort)
|
||||
}
|
||||
activeAlert = nil
|
||||
activeRequestId = nil
|
||||
}
|
||||
|
||||
static func endActiveAlert(state: PairingAlertState) {
|
||||
self.endActiveAlert(activeAlert: &state.activeAlert, activeRequestId: &state.activeRequestId)
|
||||
}
|
||||
|
||||
static func requireAlertHostWindow(alertHostWindow: inout NSWindow?) -> NSWindow {
|
||||
if let alertHostWindow {
|
||||
return alertHostWindow
|
||||
}
|
||||
|
||||
let window = PairingAlertHostWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 520, height: 1),
|
||||
styleMask: [.borderless],
|
||||
backing: .buffered,
|
||||
defer: false)
|
||||
window.title = ""
|
||||
window.isReleasedWhenClosed = false
|
||||
window.level = .floating
|
||||
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
||||
window.isOpaque = false
|
||||
window.hasShadow = false
|
||||
window.backgroundColor = .clear
|
||||
window.ignoresMouseEvents = true
|
||||
|
||||
alertHostWindow = window
|
||||
return window
|
||||
}
|
||||
|
||||
static func configureDefaultPairingAlert(
|
||||
_ alert: NSAlert,
|
||||
messageText: String,
|
||||
informativeText: String,
|
||||
buttonTitles: ButtonTitles = ButtonTitles(),
|
||||
accessoryView: NSView? = nil)
|
||||
{
|
||||
alert.alertStyle = .informational
|
||||
alert.messageText = messageText
|
||||
alert.informativeText = informativeText
|
||||
alert.accessoryView = accessoryView
|
||||
alert.addButton(withTitle: buttonTitles.approve)
|
||||
alert.addButton(withTitle: buttonTitles.postpone)
|
||||
alert.addButton(withTitle: buttonTitles.reject)
|
||||
if #available(macOS 11.0, *), alert.buttons.indices.contains(2) {
|
||||
alert.buttons[2].hasDestructiveAction = true
|
||||
}
|
||||
}
|
||||
|
||||
static func beginCenteredSheet(
|
||||
alert: NSAlert,
|
||||
hostWindow: NSWindow,
|
||||
completionHandler: @escaping (NSApplication.ModalResponse) -> Void)
|
||||
{
|
||||
let sheetSize = alert.window.frame.size
|
||||
if let screen = hostWindow.screen ?? NSScreen.main {
|
||||
let bounds = screen.visibleFrame
|
||||
let x = bounds.midX - (sheetSize.width / 2)
|
||||
let sheetOriginY = bounds.midY - (sheetSize.height / 2)
|
||||
let hostY = sheetOriginY + sheetSize.height - hostWindow.frame.height
|
||||
hostWindow.setFrameOrigin(NSPoint(x: x, y: hostY))
|
||||
} else {
|
||||
hostWindow.center()
|
||||
}
|
||||
hostWindow.makeKeyAndOrderFront(nil)
|
||||
alert.beginSheetModal(for: hostWindow, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
static func runPairingPushTask(
|
||||
bufferingNewest: Int = 200,
|
||||
loadPending: @escaping @MainActor () async -> Void,
|
||||
handlePush: @escaping @MainActor (GatewayPush) -> Void) async
|
||||
{
|
||||
_ = try? await GatewayConnection.shared.refresh()
|
||||
await loadPending()
|
||||
await GatewayPushSubscription.consume(bufferingNewest: bufferingNewest, onPush: handlePush)
|
||||
}
|
||||
|
||||
static func startPairingPushTask(
|
||||
task: inout Task<Void, Never>?,
|
||||
isStopping: inout Bool,
|
||||
bufferingNewest: Int = 200,
|
||||
loadPending: @escaping @MainActor () async -> Void,
|
||||
handlePush: @escaping @MainActor (GatewayPush) -> Void)
|
||||
{
|
||||
guard task == nil else { return }
|
||||
isStopping = false
|
||||
task = Task {
|
||||
await self.runPairingPushTask(
|
||||
bufferingNewest: bufferingNewest,
|
||||
loadPending: loadPending,
|
||||
handlePush: handlePush)
|
||||
}
|
||||
}
|
||||
|
||||
static func beginPairingAlert(
|
||||
messageText: String,
|
||||
informativeText: String,
|
||||
buttonTitles: ButtonTitles = ButtonTitles(),
|
||||
accessoryView: NSView? = nil,
|
||||
alertHostWindow: inout NSWindow?,
|
||||
completion: @escaping (NSApplication.ModalResponse, NSWindow) -> Void) -> NSAlert
|
||||
{
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
|
||||
let alert = NSAlert()
|
||||
self.configureDefaultPairingAlert(
|
||||
alert,
|
||||
messageText: messageText,
|
||||
informativeText: informativeText,
|
||||
buttonTitles: buttonTitles,
|
||||
accessoryView: accessoryView)
|
||||
|
||||
let hostWindow = self.requireAlertHostWindow(alertHostWindow: &alertHostWindow)
|
||||
self.beginCenteredSheet(alert: alert, hostWindow: hostWindow) { response in
|
||||
completion(response, hostWindow)
|
||||
}
|
||||
return alert
|
||||
}
|
||||
|
||||
static func presentPairingAlert(
|
||||
requestId: String,
|
||||
messageText: String,
|
||||
informativeText: String,
|
||||
buttonTitles: ButtonTitles = ButtonTitles(),
|
||||
accessoryView: NSView? = nil,
|
||||
activeAlert: inout NSAlert?,
|
||||
activeRequestId: inout String?,
|
||||
alertHostWindow: inout NSWindow?,
|
||||
completion: @escaping (NSApplication.ModalResponse, NSWindow) -> Void)
|
||||
{
|
||||
activeRequestId = requestId
|
||||
activeAlert = self.beginPairingAlert(
|
||||
messageText: messageText,
|
||||
informativeText: informativeText,
|
||||
buttonTitles: buttonTitles,
|
||||
accessoryView: accessoryView,
|
||||
alertHostWindow: &alertHostWindow,
|
||||
completion: completion)
|
||||
}
|
||||
|
||||
static func presentPairingAlert<Request>(
|
||||
request: Request,
|
||||
requestId: String,
|
||||
messageText: String,
|
||||
informativeText: String,
|
||||
buttonTitles: ButtonTitles = ButtonTitles(),
|
||||
accessoryView: NSView? = nil,
|
||||
state: PairingAlertState,
|
||||
onResponse: @escaping @MainActor (NSApplication.ModalResponse, Request) async -> Void)
|
||||
{
|
||||
self.presentPairingAlert(
|
||||
requestId: requestId,
|
||||
messageText: messageText,
|
||||
informativeText: informativeText,
|
||||
buttonTitles: buttonTitles,
|
||||
accessoryView: accessoryView,
|
||||
activeAlert: &state.activeAlert,
|
||||
activeRequestId: &state.activeRequestId,
|
||||
alertHostWindow: &state.alertHostWindow,
|
||||
completion: { response, hostWindow in
|
||||
Task { @MainActor in
|
||||
self.clearActivePairingAlert(state: state, hostWindow: hostWindow)
|
||||
await onResponse(response, request)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static func clearActivePairingAlert(
|
||||
activeAlert: inout NSAlert?,
|
||||
activeRequestId: inout String?,
|
||||
hostWindow: NSWindow)
|
||||
{
|
||||
activeRequestId = nil
|
||||
activeAlert = nil
|
||||
hostWindow.orderOut(nil)
|
||||
}
|
||||
|
||||
static func clearActivePairingAlert(state: PairingAlertState, hostWindow: NSWindow) {
|
||||
self.clearActivePairingAlert(
|
||||
activeAlert: &state.activeAlert,
|
||||
activeRequestId: &state.activeRequestId,
|
||||
hostWindow: hostWindow)
|
||||
}
|
||||
|
||||
static func stopPairingPrompter(
|
||||
isStopping: inout Bool,
|
||||
activeAlert: inout NSAlert?,
|
||||
activeRequestId: inout String?,
|
||||
task: inout Task<Void, Never>?,
|
||||
queue: inout [some Any],
|
||||
isPresenting: inout Bool,
|
||||
alertHostWindow: inout NSWindow?)
|
||||
{
|
||||
isStopping = true
|
||||
self.endActiveAlert(activeAlert: &activeAlert, activeRequestId: &activeRequestId)
|
||||
task?.cancel()
|
||||
task = nil
|
||||
queue.removeAll(keepingCapacity: false)
|
||||
isPresenting = false
|
||||
activeRequestId = nil
|
||||
alertHostWindow?.orderOut(nil)
|
||||
alertHostWindow?.close()
|
||||
alertHostWindow = nil
|
||||
}
|
||||
|
||||
static func stopPairingPrompter(
|
||||
isStopping: inout Bool,
|
||||
task: inout Task<Void, Never>?,
|
||||
queue: inout [some Any],
|
||||
isPresenting: inout Bool,
|
||||
state: PairingAlertState)
|
||||
{
|
||||
self.stopPairingPrompter(
|
||||
isStopping: &isStopping,
|
||||
activeAlert: &state.activeAlert,
|
||||
activeRequestId: &state.activeRequestId,
|
||||
task: &task,
|
||||
queue: &queue,
|
||||
isPresenting: &isPresenting,
|
||||
alertHostWindow: &state.alertHostWindow)
|
||||
}
|
||||
|
||||
static func approveRequest(
|
||||
requestId: String,
|
||||
kind: String,
|
||||
logger: Logger,
|
||||
action: @escaping () async throws -> Void) async -> Bool
|
||||
{
|
||||
do {
|
||||
try await action()
|
||||
logger.info("approved \(kind, privacy: .public) pairing requestId=\(requestId, privacy: .public)")
|
||||
return true
|
||||
} catch {
|
||||
logger.error("approve failed requestId=\(requestId, privacy: .public)")
|
||||
logger.error("approve failed: \(error.localizedDescription, privacy: .public)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
static func rejectRequest(
|
||||
requestId: String,
|
||||
kind: String,
|
||||
logger: Logger,
|
||||
action: @escaping () async throws -> Void) async
|
||||
{
|
||||
do {
|
||||
try await action()
|
||||
logger.info("rejected \(kind, privacy: .public) pairing requestId=\(requestId, privacy: .public)")
|
||||
} catch {
|
||||
logger.error("reject failed requestId=\(requestId, privacy: .public)")
|
||||
logger.error("reject failed: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user