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
239 lines
6.6 KiB
Swift
239 lines
6.6 KiB
Swift
import Foundation
|
|
|
|
enum ConfigPathSegment: Hashable {
|
|
case key(String)
|
|
case index(Int)
|
|
}
|
|
|
|
typealias ConfigPath = [ConfigPathSegment]
|
|
|
|
struct ConfigUiHint {
|
|
let label: String?
|
|
let help: String?
|
|
let order: Double?
|
|
let advanced: Bool?
|
|
let sensitive: Bool?
|
|
let placeholder: String?
|
|
|
|
init(raw: [String: Any]) {
|
|
self.label = raw["label"] as? String
|
|
self.help = raw["help"] as? String
|
|
if let order = raw["order"] as? Double {
|
|
self.order = order
|
|
} else if let orderInt = raw["order"] as? Int {
|
|
self.order = Double(orderInt)
|
|
} else {
|
|
self.order = nil
|
|
}
|
|
self.advanced = raw["advanced"] as? Bool
|
|
self.sensitive = raw["sensitive"] as? Bool
|
|
self.placeholder = raw["placeholder"] as? String
|
|
}
|
|
}
|
|
|
|
struct ConfigSchemaNode {
|
|
let raw: [String: Any]
|
|
|
|
init?(raw: Any) {
|
|
guard let dict = raw as? [String: Any] else { return nil }
|
|
self.raw = dict
|
|
}
|
|
|
|
var title: String? {
|
|
self.raw["title"] as? String
|
|
}
|
|
|
|
var description: String? {
|
|
self.raw["description"] as? String
|
|
}
|
|
|
|
var enumValues: [Any]? {
|
|
self.raw["enum"] as? [Any]
|
|
}
|
|
|
|
var constValue: Any? {
|
|
self.raw["const"]
|
|
}
|
|
|
|
var explicitDefault: Any? {
|
|
self.raw["default"]
|
|
}
|
|
|
|
var requiredKeys: Set<String> {
|
|
Set((self.raw["required"] as? [String]) ?? [])
|
|
}
|
|
|
|
var typeList: [String] {
|
|
if let type = self.raw["type"] as? String { return [type] }
|
|
if let types = self.raw["type"] as? [String] { return types }
|
|
return []
|
|
}
|
|
|
|
var schemaType: String? {
|
|
let filtered = self.typeList.filter { $0 != "null" }
|
|
if let first = filtered.first { return first }
|
|
return self.typeList.first
|
|
}
|
|
|
|
var isNullSchema: Bool {
|
|
let types = self.typeList
|
|
return types.count == 1 && types.first == "null"
|
|
}
|
|
|
|
var properties: [String: ConfigSchemaNode] {
|
|
guard let props = self.raw["properties"] as? [String: Any] else { return [:] }
|
|
return props.compactMapValues { ConfigSchemaNode(raw: $0) }
|
|
}
|
|
|
|
var anyOf: [ConfigSchemaNode] {
|
|
guard let raw = self.raw["anyOf"] as? [Any] else { return [] }
|
|
return raw.compactMap { ConfigSchemaNode(raw: $0) }
|
|
}
|
|
|
|
var oneOf: [ConfigSchemaNode] {
|
|
guard let raw = self.raw["oneOf"] as? [Any] else { return [] }
|
|
return raw.compactMap { ConfigSchemaNode(raw: $0) }
|
|
}
|
|
|
|
var literalValue: Any? {
|
|
if let constValue { return constValue }
|
|
if let enumValues, enumValues.count == 1 { return enumValues[0] }
|
|
return nil
|
|
}
|
|
|
|
var items: ConfigSchemaNode? {
|
|
if let items = self.raw["items"] as? [Any], let first = items.first {
|
|
return ConfigSchemaNode(raw: first)
|
|
}
|
|
if let items = self.raw["items"] {
|
|
return ConfigSchemaNode(raw: items)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var additionalProperties: ConfigSchemaNode? {
|
|
if let additional = self.raw["additionalProperties"] as? [String: Any] {
|
|
return ConfigSchemaNode(raw: additional)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var allowsAdditionalProperties: Bool {
|
|
if let allow = self.raw["additionalProperties"] as? Bool { return allow }
|
|
return self.additionalProperties != nil
|
|
}
|
|
|
|
var defaultValue: Any {
|
|
if let value = self.raw["default"] { return value }
|
|
switch self.schemaType {
|
|
case "object":
|
|
return [String: Any]()
|
|
case "array":
|
|
return [Any]()
|
|
case "boolean":
|
|
return false
|
|
case "integer":
|
|
return 0
|
|
case "number":
|
|
return 0.0
|
|
case "string":
|
|
return ""
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func node(at path: ConfigPath) -> ConfigSchemaNode? {
|
|
var current: ConfigSchemaNode? = self
|
|
for segment in path {
|
|
guard let node = current else { return nil }
|
|
switch segment {
|
|
case let .key(key):
|
|
if node.schemaType == "object" {
|
|
if let next = node.properties[key] {
|
|
current = next
|
|
continue
|
|
}
|
|
if let additional = node.additionalProperties {
|
|
current = additional
|
|
continue
|
|
}
|
|
return nil
|
|
}
|
|
return nil
|
|
case .index:
|
|
guard node.schemaType == "array" else { return nil }
|
|
current = node.items
|
|
}
|
|
}
|
|
return current
|
|
}
|
|
}
|
|
|
|
func decodeUiHints(_ raw: [String: Any]) -> [String: ConfigUiHint] {
|
|
raw.reduce(into: [:]) { result, entry in
|
|
if let hint = entry.value as? [String: Any] {
|
|
result[entry.key] = ConfigUiHint(raw: hint)
|
|
}
|
|
}
|
|
}
|
|
|
|
func hintForPath(_ path: ConfigPath, hints: [String: ConfigUiHint]) -> ConfigUiHint? {
|
|
let key = pathKey(path)
|
|
if let direct = hints[key] { return direct }
|
|
let segments = key.split(separator: ".").map(String.init)
|
|
for (hintKey, hint) in hints {
|
|
guard hintKey.contains("*") else { continue }
|
|
let hintSegments = hintKey.split(separator: ".").map(String.init)
|
|
guard hintSegments.count == segments.count else { continue }
|
|
var match = true
|
|
for (index, seg) in segments.enumerated() {
|
|
let hintSegment = hintSegments[index]
|
|
if hintSegment != "*", hintSegment != seg {
|
|
match = false
|
|
break
|
|
}
|
|
}
|
|
if match { return hint }
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func isSensitivePath(_ path: ConfigPath) -> Bool {
|
|
let key = pathKey(path).lowercased()
|
|
return key.contains("token")
|
|
|| key.contains("password")
|
|
|| key.contains("secret")
|
|
|| key.contains("apikey")
|
|
|| key.hasSuffix("key")
|
|
}
|
|
|
|
func labelForConfigPath(_ path: ConfigPath) -> String? {
|
|
for segment in path.reversed() {
|
|
if case let .key(key) = segment {
|
|
return humanizeConfigKey(key)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func humanizeConfigKey(_ key: String) -> String {
|
|
key.replacingOccurrences(of: "_", with: " ")
|
|
.replacingOccurrences(of: "-", with: " ")
|
|
.replacingOccurrences(
|
|
of: "([a-z0-9])([A-Z])",
|
|
with: "$1 $2",
|
|
options: .regularExpression)
|
|
.capitalized
|
|
}
|
|
|
|
func pathKey(_ path: ConfigPath) -> String {
|
|
path.compactMap { segment -> String? in
|
|
switch segment {
|
|
case let .key(key): return key
|
|
case .index: return nil
|
|
}
|
|
}
|
|
.joined(separator: ".")
|
|
}
|