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

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:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

View File

@@ -0,0 +1,301 @@
import Foundation
import Network
import Observation
import SwiftUI
struct HealthSnapshot: Codable {
struct ChannelSummary: Codable {
struct Probe: Codable {
struct Bot: Codable {
let username: String?
}
struct Webhook: Codable {
let url: String?
}
let ok: Bool?
let status: Int?
let error: String?
let elapsedMs: Double?
let bot: Bot?
let webhook: Webhook?
}
let configured: Bool?
let linked: Bool?
let authAgeMs: Double?
let probe: Probe?
let lastProbeAt: Double?
}
struct SessionInfo: Codable {
let key: String
let updatedAt: Double?
let age: Double?
}
struct Sessions: Codable {
let path: String
let count: Int
let recent: [SessionInfo]
}
let ok: Bool?
let ts: Double
let durationMs: Double
let channels: [String: ChannelSummary]
let channelOrder: [String]?
let channelLabels: [String: String]?
let heartbeatSeconds: Int?
let sessions: Sessions
}
enum HealthState: Equatable {
case unknown
case ok
case linkingNeeded
case degraded(String)
var tint: Color {
switch self {
case .ok: .green
case .linkingNeeded: .red
case .degraded: .orange
case .unknown: .secondary
}
}
}
@MainActor
@Observable
final class HealthStore {
static let shared = HealthStore()
private static let logger = Logger(subsystem: "ai.openclaw", category: "health")
private(set) var snapshot: HealthSnapshot?
private(set) var lastSuccess: Date?
private(set) var lastError: String?
private(set) var isRefreshing = false
private var loopTask: Task<Void, Never>?
private let refreshInterval: TimeInterval = 60
private init() {
// Avoid background health polling in SwiftUI previews and tests.
if !ProcessInfo.processInfo.isPreview, !ProcessInfo.processInfo.isRunningTests {
self.start()
}
}
/// Test-only escape hatch: the HealthStore is a process-wide singleton but
/// state derivation is pure from `snapshot` + `lastError`.
func __setSnapshotForTest(_ snapshot: HealthSnapshot?, lastError: String? = nil) {
self.snapshot = snapshot
self.lastError = lastError
}
func start() {
guard self.loopTask == nil else { return }
self.loopTask = Task { [weak self] in
guard let self else { return }
while !Task.isCancelled {
await self.refresh()
try? await Task.sleep(nanoseconds: UInt64(self.refreshInterval * 1_000_000_000))
}
}
}
func stop() {
self.loopTask?.cancel()
self.loopTask = nil
}
func refresh(onDemand: Bool = false) async {
guard !self.isRefreshing else { return }
self.isRefreshing = true
defer { self.isRefreshing = false }
let previousError = self.lastError
do {
let data = try await ControlChannel.shared.health(timeout: 15)
if let decoded = decodeHealthSnapshot(from: data) {
self.snapshot = decoded
self.lastSuccess = Date()
self.lastError = nil
if previousError != nil {
Self.logger.info("health refresh recovered")
}
} else {
self.lastError = "health output not JSON"
if onDemand { self.snapshot = nil }
if previousError != self.lastError {
Self.logger.warning("health refresh failed: output not JSON")
}
}
} catch {
let desc = error.localizedDescription
self.lastError = desc
if onDemand { self.snapshot = nil }
if previousError != desc {
Self.logger.error("health refresh failed \(desc, privacy: .public)")
}
}
}
private static func isChannelHealthy(_ summary: HealthSnapshot.ChannelSummary) -> Bool {
guard summary.configured == true else { return false }
// If probe is missing, treat it as "configured but unknown health" (not a hard fail).
return summary.probe?.ok ?? true
}
private static func describeProbeFailure(_ probe: HealthSnapshot.ChannelSummary.Probe) -> String {
let elapsed = probe.elapsedMs.map { "\(Int($0))ms" }
if let error = probe.error, error.lowercased().contains("timeout") || probe.status == nil {
if let elapsed { return "Health check timed out (\(elapsed))" }
return "Health check timed out"
}
let code = probe.status.map { "status \($0)" } ?? "status unknown"
let reason = probe.error?.isEmpty == false ? probe.error! : "health probe failed"
if let elapsed { return "\(reason) (\(code), \(elapsed))" }
return "\(reason) (\(code))"
}
private func resolveLinkChannel(
_ snap: HealthSnapshot) -> (id: String, summary: HealthSnapshot.ChannelSummary)?
{
let order = snap.channelOrder ?? Array(snap.channels.keys)
for id in order {
if let summary = snap.channels[id], summary.linked == true {
return (id: id, summary: summary)
}
}
for id in order {
if let summary = snap.channels[id], summary.linked != nil {
return (id: id, summary: summary)
}
}
return nil
}
private func resolveFallbackChannel(
_ snap: HealthSnapshot,
excluding id: String?) -> (id: String, summary: HealthSnapshot.ChannelSummary)?
{
let order = snap.channelOrder ?? Array(snap.channels.keys)
for channelId in order {
if channelId == id { continue }
guard let summary = snap.channels[channelId] else { continue }
if Self.isChannelHealthy(summary) {
return (id: channelId, summary: summary)
}
}
return nil
}
var state: HealthState {
if let error = self.lastError, !error.isEmpty {
return .degraded(error)
}
guard let snap = self.snapshot else { return .unknown }
guard let link = self.resolveLinkChannel(snap) else { return .unknown }
if link.summary.linked != true {
// Linking is optional if any other channel is healthy; don't paint the whole app red.
let fallback = self.resolveFallbackChannel(snap, excluding: link.id)
return fallback != nil ? .degraded("Not linked") : .linkingNeeded
}
// A channel can be "linked" but still unhealthy (failed probe / cannot connect).
if let probe = link.summary.probe, probe.ok == false {
return .degraded(Self.describeProbeFailure(probe))
}
return .ok
}
var summaryLine: String {
if self.isRefreshing { return "Health check running…" }
if let error = self.lastError { return "Health check failed: \(error)" }
guard let snap = self.snapshot else { return "Health check pending" }
guard let link = self.resolveLinkChannel(snap) else { return "Health check pending" }
if link.summary.linked != true {
if let fallback = self.resolveFallbackChannel(snap, excluding: link.id) {
let fallbackLabel = snap.channelLabels?[fallback.id] ?? fallback.id.capitalized
let fallbackState = (fallback.summary.probe?.ok ?? true) ? "ok" : "degraded"
return "\(fallbackLabel) \(fallbackState) · Not linked — run openclaw login"
}
return "Not linked — run openclaw login"
}
let auth = link.summary.authAgeMs.map { msToAge($0) } ?? "unknown"
if let probe = link.summary.probe, probe.ok == false {
let status = probe.status.map(String.init) ?? "?"
let suffix = probe.status == nil ? "probe degraded" : "probe degraded · status \(status)"
return "linked · auth \(auth) · \(suffix)"
}
return "linked · auth \(auth)"
}
/// Short, human-friendly detail for the last failure, used in the UI.
var detailLine: String? {
if let error = self.lastError, !error.isEmpty {
let lower = error.lowercased()
if lower.contains("connection refused") {
let port = GatewayEnvironment.gatewayPort()
let host = GatewayConnectivityCoordinator.shared.localEndpointHostLabel ?? "127.0.0.1:\(port)"
return "The gateway control port (\(host)) isnt listening — restart OpenClaw to bring it back."
}
if lower.contains("timeout") {
return "Timed out waiting for the control server; the gateway may be crashed or still starting."
}
return error
}
return nil
}
func describeFailure(from snap: HealthSnapshot, fallback: String?) -> String {
if let link = self.resolveLinkChannel(snap), link.summary.linked != true {
return "Not linked — run openclaw login"
}
if let link = self.resolveLinkChannel(snap), let probe = link.summary.probe, probe.ok == false {
return Self.describeProbeFailure(probe)
}
if let fallback, !fallback.isEmpty {
return fallback
}
return "health probe failed"
}
var degradedSummary: String? {
guard case let .degraded(reason) = self.state else { return nil }
if reason == "[object Object]" || reason.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
let snap = self.snapshot
{
return self.describeFailure(from: snap, fallback: reason)
}
return reason
}
}
func msToAge(_ ms: Double) -> String {
let minutes = Int(round(ms / 60000))
if minutes < 1 { return "just now" }
if minutes < 60 { return "\(minutes)m" }
let hours = Int(round(Double(minutes) / 60))
if hours < 48 { return "\(hours)h" }
let days = Int(round(Double(hours) / 24))
return "\(days)d"
}
/// Decode a health snapshot, tolerating stray log lines before/after the JSON blob.
func decodeHealthSnapshot(from data: Data) -> HealthSnapshot? {
let decoder = JSONDecoder()
if let snap = try? decoder.decode(HealthSnapshot.self, from: data) {
return snap
}
guard let text = String(data: data, encoding: .utf8) else { return nil }
guard let firstBrace = text.firstIndex(of: "{"), let lastBrace = text.lastIndex(of: "}") else {
return nil
}
let slice = text[firstBrace...lastBrace]
let cleaned = Data(slice.utf8)
return try? decoder.decode(HealthSnapshot.self, from: cleaned)
}