diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json index da4526cbd82..b3c8861cf01 100644 --- a/apps/.i18n/native-source.json +++ b/apps/.i18n/native-source.json @@ -1843,7 +1843,7 @@ }, { "kind": "ui-named-argument", - "line": 1133, + "line": 1122, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup Gateway", "surface": "android", @@ -1851,7 +1851,7 @@ }, { "kind": "ui-named-argument", - "line": 1139, + "line": 1128, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Start your Gateway.", "surface": "android", @@ -1859,7 +1859,7 @@ }, { "kind": "ui-named-argument", - "line": 1145, + "line": 1134, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Generate a QR code.", "surface": "android", @@ -1867,7 +1867,7 @@ }, { "kind": "ui-named-argument", - "line": 1166, + "line": 1155, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Choose from gallery", "surface": "android", @@ -1875,7 +1875,7 @@ }, { "kind": "ui-named-argument", - "line": 1220, + "line": 1209, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "QR code not accepted", "surface": "android", @@ -1883,7 +1883,7 @@ }, { "kind": "ui-named-argument", - "line": 1235, + "line": 1224, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Choose another image", "surface": "android", @@ -1891,7 +1891,7 @@ }, { "kind": "ui-named-argument", - "line": 1288, + "line": 1277, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Scan QR code", "surface": "android", @@ -1899,7 +1899,7 @@ }, { "kind": "ui-named-argument", - "line": 1290, + "line": 1279, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Open the camera and frame the code from openclaw qr.", "surface": "android", @@ -1907,7 +1907,7 @@ }, { "kind": "ui-named-argument", - "line": 1324, + "line": 1313, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Align the QR code inside the square.", "surface": "android", @@ -1915,7 +1915,7 @@ }, { "kind": "ui-named-argument", - "line": 1342, + "line": 1331, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Camera access is needed to scan the setup QR.", "surface": "android", @@ -1923,7 +1923,7 @@ }, { "kind": "ui-named-argument", - "line": 1347, + "line": 1336, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Allow camera", "surface": "android", @@ -1931,7 +1931,7 @@ }, { "kind": "ui-named-argument", - "line": 1368, + "line": 1357, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Close scanner", "surface": "android", @@ -1939,7 +1939,7 @@ }, { "kind": "ui-named-argument", - "line": 1530, + "line": 1519, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Enter setup code", "surface": "android", @@ -1947,7 +1947,7 @@ }, { "kind": "ui-named-argument", - "line": 1531, + "line": 1520, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup code", "surface": "android", @@ -1955,7 +1955,7 @@ }, { "kind": "ui-named-argument", - "line": 1535, + "line": 1524, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste setup code", "surface": "android", @@ -1963,7 +1963,7 @@ }, { "kind": "ui-named-argument", - "line": 1539, + "line": 1528, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Setup code was not accepted", "surface": "android", @@ -1971,7 +1971,7 @@ }, { "kind": "ui-named-argument", - "line": 1543, + "line": 1532, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use setup code", "surface": "android", @@ -1979,7 +1979,7 @@ }, { "kind": "ui-named-argument", - "line": 1574, + "line": 1563, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Manual setup", "surface": "android", @@ -1987,7 +1987,7 @@ }, { "kind": "ui-named-argument", - "line": 1577, + "line": 1566, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway URL", "surface": "android", @@ -1995,7 +1995,7 @@ }, { "kind": "ui-named-argument", - "line": 1579, + "line": 1568, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Host", "surface": "android", @@ -2003,7 +2003,7 @@ }, { "kind": "ui-named-argument", - "line": 1580, + "line": 1569, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Port", "surface": "android", @@ -2011,7 +2011,7 @@ }, { "kind": "ui-named-argument", - "line": 1583, + "line": 1572, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use the Gateway computer's LAN address or secure remote hostname.", "surface": "android", @@ -2019,7 +2019,7 @@ }, { "kind": "ui-named-argument", - "line": 1590, + "line": 1579, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Token", "surface": "android", @@ -2027,7 +2027,7 @@ }, { "kind": "ui-named-argument", - "line": 1591, + "line": 1580, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste token", "surface": "android", @@ -2035,7 +2035,7 @@ }, { "kind": "ui-named-argument", - "line": 1593, + "line": 1582, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Paste a shared Gateway token or operator-issued token.", "surface": "android", @@ -2043,7 +2043,7 @@ }, { "kind": "ui-named-argument", - "line": 1600, + "line": 1589, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Password", "surface": "android", @@ -2051,7 +2051,7 @@ }, { "kind": "ui-named-argument", - "line": 1601, + "line": 1590, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Password optional", "surface": "android", @@ -2059,7 +2059,7 @@ }, { "kind": "ui-named-argument", - "line": 1605, + "line": 1594, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connection type", "surface": "android", @@ -2067,7 +2067,7 @@ }, { "kind": "ui-named-argument", - "line": 1607, + "line": 1596, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Local network", "surface": "android", @@ -2075,7 +2075,7 @@ }, { "kind": "ui-named-argument", - "line": 1608, + "line": 1597, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Secure remote", "surface": "android", @@ -2083,7 +2083,7 @@ }, { "kind": "ui-named-argument", - "line": 1611, + "line": 1600, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Local works for LAN or emulator hosts. Secure remote is for wss:// or Tailscale Serve/Funnel.", "surface": "android", @@ -2091,7 +2091,7 @@ }, { "kind": "ui-named-argument", - "line": 1619, + "line": 1608, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Could not test connection", "surface": "android", @@ -2099,7 +2099,7 @@ }, { "kind": "ui-named-argument", - "line": 1624, + "line": 1613, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Test connection", "surface": "android", @@ -2107,7 +2107,7 @@ }, { "kind": "ui-call", - "line": 1802, + "line": 1791, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "View details", "surface": "android", @@ -2115,7 +2115,7 @@ }, { "kind": "ui-call", - "line": 1835, + "line": 1824, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Connection details", "surface": "android", @@ -2123,7 +2123,7 @@ }, { "kind": "ui-call", - "line": 1847, + "line": 1836, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Copy", "surface": "android", @@ -2131,7 +2131,7 @@ }, { "kind": "ui-call", - "line": 1852, + "line": 1841, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Close", "surface": "android", @@ -2139,7 +2139,7 @@ }, { "kind": "ui-toast", - "line": 1864, + "line": 1853, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Details copied", "surface": "android", @@ -2147,7 +2147,7 @@ }, { "kind": "ui-named-argument", - "line": 1949, + "line": 1938, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approve node access", "surface": "android", @@ -2155,7 +2155,7 @@ }, { "kind": "ui-named-argument", - "line": 1956, + "line": 1945, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway pairing is complete. Approve this phone as a node so OpenClaw can use the device capabilities you enable.", "surface": "android", @@ -2163,7 +2163,7 @@ }, { "kind": "ui-named-argument", - "line": 1964, + "line": 1953, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "On the Gateway computer, run:", "surface": "android", @@ -2171,7 +2171,7 @@ }, { "kind": "ui-named-argument", - "line": 1973, + "line": 1962, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Use the requestId from the pending command in the approve command.", "surface": "android", @@ -2179,7 +2179,7 @@ }, { "kind": "ui-named-argument", - "line": 1984, + "line": 1973, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "I have approved", "surface": "android", @@ -2187,7 +2187,7 @@ }, { "kind": "ui-named-argument", - "line": 1997, + "line": 1986, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Still waiting for approval", "surface": "android", @@ -2195,7 +2195,7 @@ }, { "kind": "ui-named-argument", - "line": 2000, + "line": 1989, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Run the approve command on the Gateway computer, then check again.", "surface": "android", @@ -2203,7 +2203,7 @@ }, { "kind": "ui-named-argument", - "line": 2007, + "line": 1996, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "OK", "surface": "android", @@ -2211,7 +2211,7 @@ }, { "kind": "ui-named-argument", - "line": 2157, + "line": 2146, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Copy approval command", "surface": "android", @@ -2219,7 +2219,7 @@ }, { "kind": "ui-named-argument", - "line": 2183, + "line": 2172, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Only enable access you are comfortable letting OpenClaw use while this phone is connected. You can change these later in Android Settings.", "surface": "android", @@ -2227,7 +2227,7 @@ }, { "kind": "ui-named-argument", - "line": 2195, + "line": 2184, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Continue", "surface": "android", @@ -2235,7 +2235,7 @@ }, { "kind": "ui-named-argument", - "line": 2222, + "line": 2211, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Back", "surface": "android", @@ -2243,7 +2243,7 @@ }, { "kind": "ui-named-argument", - "line": 2269, + "line": 2258, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Permissions", "surface": "android", @@ -2251,7 +2251,7 @@ }, { "kind": "conditional-branch", - "line": 2594, + "line": 2583, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "The code may have expired or been generated for another Gateway.", "surface": "android", @@ -2259,7 +2259,7 @@ }, { "kind": "conditional-branch", - "line": 2598, + "line": 2587, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway password is required. Enter it again or edit this connection.", "surface": "android", @@ -2267,7 +2267,7 @@ }, { "kind": "conditional-branch", - "line": 2599, + "line": 2588, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway password is invalid. Re-enter it or reset this gateway connection.", "surface": "android", @@ -2275,7 +2275,7 @@ }, { "kind": "conditional-branch", - "line": 2600, + "line": 2589, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway token is required. Enter it again or edit this connection.", "surface": "android", @@ -2283,7 +2283,7 @@ }, { "kind": "conditional-branch", - "line": 2602, + "line": 2591, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway requires this device identity. Re-authenticate or reset this gateway connection.", "surface": "android", @@ -2291,7 +2291,7 @@ }, { "kind": "conditional-branch", - "line": 2606, + "line": 2595, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Saved authentication is invalid. Re-authenticate or reset this gateway connection.", "surface": "android", @@ -2299,7 +2299,7 @@ }, { "kind": "conditional-branch", - "line": 2607, + "line": 2596, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway authentication is not configured. Edit this connection and try again.", "surface": "android", @@ -2307,7 +2307,7 @@ }, { "kind": "conditional-branch", - "line": 2608, + "line": 2597, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Gateway authentication needs review. Check gateway settings, then retry.", "surface": "android", @@ -2315,7 +2315,7 @@ }, { "kind": "conditional-branch", - "line": 2625, + "line": 2614, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "$summary $it", "surface": "android", @@ -2323,7 +2323,7 @@ }, { "kind": "ui-toast", - "line": 2768, + "line": 2757, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Approval command copied", "surface": "android", @@ -2331,7 +2331,7 @@ }, { "kind": "conditional-branch", - "line": 2830, + "line": 2819, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Granted", "surface": "android", @@ -2339,7 +2339,7 @@ }, { "kind": "conditional-branch", - "line": 2830, + "line": 2819, "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt", "source": "Not granted", "surface": "android", diff --git a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt index 6f882ca276b..ca851e02cfe 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt @@ -3502,11 +3502,6 @@ class NodeRuntime private constructor( private fun skillMissingCount(missing: JsonObject?): Int = listOf("bins", "env", "config", "os").sumOf { key -> (missing?.get(key) as? JsonArray)?.size ?: 0 } - private fun parseGatewayNodes(nodes: JsonArray?): List = - nodes - ?.mapNotNull(::parseGatewayNodeSummary) - .orEmpty() - private fun parsePendingDevices(devices: JsonArray?): List = devices ?.mapNotNull { item -> diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt index 2c214207698..684397b67ec 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt @@ -1096,17 +1096,6 @@ private fun GatewayPrerequisiteRow( } } -@Composable -private fun GatewayCommand( - label: String, - command: String, -) { - Column(verticalArrangement = Arrangement.spacedBy(3.dp)) { - Text(text = label, style = ClawTheme.type.caption, color = ClawTheme.colors.textMuted) - Text(text = command, style = ClawTheme.type.mono.copy(fontSize = 16.sp, lineHeight = 22.sp), color = ClawTheme.colors.text) - } -} - @Composable private fun SetupCodeInstructionsScreen( scannerActive: Boolean, diff --git a/apps/macos/Sources/OpenClaw/AboutSettings.swift b/apps/macos/Sources/OpenClaw/AboutSettings.swift index b2f62e066cc..9688885352c 100644 --- a/apps/macos/Sources/OpenClaw/AboutSettings.swift +++ b/apps/macos/Sources/OpenClaw/AboutSettings.swift @@ -176,22 +176,6 @@ private struct AboutLinkRow: View { } } -private struct AboutMetaRow: View { - let label: String - let value: String - - var body: some View { - HStack { - Text(self.label) - .foregroundStyle(.secondary) - Spacer() - Text(self.value) - .font(.caption.monospaced()) - .foregroundStyle(.primary) - } - } -} - #if DEBUG struct AboutSettings_Previews: PreviewProvider { private static let updater = DisabledUpdaterController() diff --git a/apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift index 166589cccee..641784b1f5b 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift @@ -236,20 +236,6 @@ private struct SelectedConnectAuth { let suppressedDeviceTokenRetry: Bool } -private enum GatewayConnectErrorCodes { - static let authTokenMismatch = GatewayConnectAuthDetailCode.authTokenMismatch.rawValue - static let authDeviceTokenMismatch = GatewayConnectAuthDetailCode.authDeviceTokenMismatch.rawValue - static let authTokenMissing = GatewayConnectAuthDetailCode.authTokenMissing.rawValue - static let authTokenNotConfigured = GatewayConnectAuthDetailCode.authTokenNotConfigured.rawValue - static let authPasswordMissing = GatewayConnectAuthDetailCode.authPasswordMissing.rawValue - static let authPasswordMismatch = GatewayConnectAuthDetailCode.authPasswordMismatch.rawValue - static let authPasswordNotConfigured = GatewayConnectAuthDetailCode.authPasswordNotConfigured.rawValue - static let authRateLimited = GatewayConnectAuthDetailCode.authRateLimited.rawValue - static let pairingRequired = GatewayConnectAuthDetailCode.pairingRequired.rawValue - static let controlUiDeviceIdentityRequired = GatewayConnectAuthDetailCode.controlUiDeviceIdentityRequired.rawValue - static let deviceIdentityRequired = GatewayConnectAuthDetailCode.deviceIdentityRequired.rawValue -} - public actor GatewayChannelActor { nonisolated static func resolveRequestTimeoutMs(_ timeoutMs: Double?, defaultMs: Double) -> Double? { timeoutMs == 0 ? nil : (timeoutMs ?? defaultMs) diff --git a/apps/swabble/Sources/SwabbleCore/Support/TranscriptsStore.swift b/apps/swabble/Sources/SwabbleCore/Support/TranscriptsStore.swift index 4f91d052e6a..514a477f0c5 100644 --- a/apps/swabble/Sources/SwabbleCore/Support/TranscriptsStore.swift +++ b/apps/swabble/Sources/SwabbleCore/Support/TranscriptsStore.swift @@ -29,17 +29,3 @@ public actor TranscriptsStore { public func latest() -> [String] { entries } } - -extension String { - private func appendLine(to url: URL) throws { - let data = (self + "\n").data(using: .utf8) ?? Data() - if FileManager.default.fileExists(atPath: url.path) { - let handle = try FileHandle(forWritingTo: url) - try handle.seekToEnd() - try handle.write(contentsOf: data) - try handle.close() - } else { - try data.write(to: url) - } - } -} diff --git a/extensions/logbook/src/store.ts b/extensions/logbook/src/store.ts index 95703362019..e880454bbcb 100644 --- a/extensions/logbook/src/store.ts +++ b/extensions/logbook/src/store.ts @@ -96,6 +96,17 @@ type FrameRow = { idle: number; }; +type BatchRow = { + id: number; + day: string; + start_ms: number; + end_ms: number; + status: LogbookBatchStatus; + error: string | null; + frame_count: number; + model: string | null; +}; + type CardRow = { id: number; day: string; @@ -125,6 +136,19 @@ function toFrame(row: FrameRow): LogbookFrame { }; } +function toBatch(row: BatchRow): LogbookBatch { + return { + id: row.id, + day: row.day, + startMs: row.start_ms, + endMs: row.end_ms, + status: row.status, + error: row.error ?? undefined, + frameCount: row.frame_count, + model: row.model ?? undefined, + }; +} + function parseDistractions(raw: string): LogbookDistraction[] { try { const parsed = JSON.parse(raw) as unknown; @@ -312,31 +336,8 @@ export class LogbookStore { `SELECT id, day, start_ms, end_ms, status, error, frame_count, model FROM batches ORDER BY id DESC LIMIT 1`, ) - .get() as - | { - id: number; - day: string; - start_ms: number; - end_ms: number; - status: LogbookBatchStatus; - error: string | null; - frame_count: number; - model: string | null; - } - | undefined; - if (!row) { - return null; - } - return { - id: row.id, - day: row.day, - startMs: row.start_ms, - endMs: row.end_ms, - status: row.status, - error: row.error ?? undefined, - frameCount: row.frame_count, - model: row.model ?? undefined, - }; + .get() as BatchRow | undefined; + return row ? toBatch(row) : null; } /** Requeues batches stuck in `running` after a crash so frames are not orphaned. */ @@ -362,31 +363,8 @@ export class LogbookStore { `SELECT id, day, start_ms, end_ms, status, error, frame_count, model FROM batches WHERE status = 'pending' ORDER BY start_ms ASC LIMIT 1`, ) - .get() as - | { - id: number; - day: string; - start_ms: number; - end_ms: number; - status: LogbookBatchStatus; - error: string | null; - frame_count: number; - model: string | null; - } - | undefined; - if (!row) { - return null; - } - return { - id: row.id, - day: row.day, - startMs: row.start_ms, - endMs: row.end_ms, - status: row.status, - error: row.error ?? undefined, - frameCount: row.frame_count, - model: row.model ?? undefined, - }; + .get() as BatchRow | undefined; + return row ? toBatch(row) : null; } batchFrames(batchId: number): LogbookFrame[] { diff --git a/extensions/memory-core/src/memory/qmd-runtime-cache.ts b/extensions/memory-core/src/memory/qmd-runtime-cache.ts index 9732d4a690f..c04f1b3d347 100644 --- a/extensions/memory-core/src/memory/qmd-runtime-cache.ts +++ b/extensions/memory-core/src/memory/qmd-runtime-cache.ts @@ -113,10 +113,10 @@ function buildCollectionConfigHash(collections: readonly QmdRuntimeManagedCollec return hashText(normalized); } -function buildCollectionValidationCacheContextInput( - params: QmdRuntimeCollectionValidationCacheContext, -): string { - return JSON.stringify({ +function buildRuntimeCacheContextRecord( + params: QmdRuntimeCacheContextBase & { sources: readonly string[] }, +) { + return { agentId: normalizeText(params.agentId), commandHash: hashText(normalizeText(params.qmdCommand)), environmentHash: normalizeText(params.qmdEnvironmentHash ?? ""), @@ -124,6 +124,14 @@ function buildCollectionValidationCacheContextInput( qmdVersion: normalizeText(params.qmdVersion ?? ""), searchMode: params.searchMode, sourceSet: sortedUnique(params.sources), + }; +} + +function buildCollectionValidationCacheContextInput( + params: QmdRuntimeCollectionValidationCacheContext, +): string { + return JSON.stringify({ + ...buildRuntimeCacheContextRecord(params), collectionConfigHash: buildCollectionConfigHash(params.collections), }); } @@ -131,39 +139,19 @@ function buildCollectionValidationCacheContextInput( function buildMultiCollectionProbeCacheContextInput( params: QmdRuntimeMultiCollectionProbeCacheContext, ): string { - return JSON.stringify({ - agentId: normalizeText(params.agentId), - commandHash: hashText(normalizeText(params.qmdCommand)), - environmentHash: normalizeText(params.qmdEnvironmentHash ?? ""), - indexPathHash: normalizePathIdentity(params.qmdIndexPath), - qmdVersion: normalizeText(params.qmdVersion ?? ""), - searchMode: params.searchMode, - sourceSet: sortedUnique(params.sources), - }); -} - -function buildCollectionValidationCacheHash( - params: QmdRuntimeCollectionValidationCacheContext, -): string { - return hashText(buildCollectionValidationCacheContextInput(params)); -} - -function buildMultiCollectionProbeCacheHash( - params: QmdRuntimeMultiCollectionProbeCacheContext, -): string { - return hashText(buildMultiCollectionProbeCacheContextInput(params)); + return JSON.stringify(buildRuntimeCacheContextRecord(params)); } export function buildQmdCollectionValidationCacheContextHash( params: QmdRuntimeCollectionValidationCacheContext, ): string { - return buildCollectionValidationCacheHash(params); + return hashText(buildCollectionValidationCacheContextInput(params)); } export function buildQmdMultiCollectionProbeCacheContextHash( params: QmdRuntimeMultiCollectionProbeCacheContext, ): string { - return buildMultiCollectionProbeCacheHash(params); + return hashText(buildMultiCollectionProbeCacheContextInput(params)); } function collectionValidationStore(): PluginStateKeyedStore { @@ -183,14 +171,14 @@ function multiCollectionProbeStore(): PluginStateKeyedStore { try { const key = collectionValidationEntryKey(params); - const keyHash = buildCollectionValidationCacheHash(params); + const keyHash = buildQmdCollectionValidationCacheContextHash(params); const collectionConfigHash = buildCollectionConfigHash(params.collections); const createdAtMs = Math.max(0, Math.floor(nowMs)); const ttlMs = QMD_RUNTIME_CACHE_COLLECTION_VALIDATION_TTL_MS; @@ -379,7 +367,7 @@ export async function readQmdMultiCollectionProbeCache( try { const store = multiCollectionProbeStore(); const key = multiCollectionProbeEntryKey(params); - const expectedKeyHash = buildMultiCollectionProbeCacheHash(params); + const expectedKeyHash = buildQmdMultiCollectionProbeCacheContextHash(params); const raw = await store.lookup(key); if (!raw) { return { state: "miss" }; @@ -398,7 +386,7 @@ export async function writeQmdMultiCollectionProbeCache( ): Promise { try { const key = multiCollectionProbeEntryKey(params); - const keyHash = buildMultiCollectionProbeCacheHash(params); + const keyHash = buildQmdMultiCollectionProbeCacheContextHash(params); const createdAtMs = Math.max(0, Math.floor(nowMs)); const ttlMs = QMD_RUNTIME_CACHE_MULTI_COLLECTION_PROBE_TTL_MS; const store = multiCollectionProbeStore(); diff --git a/extensions/memory-core/src/short-term-promotion.ts b/extensions/memory-core/src/short-term-promotion.ts index 736abde4068..29b0a88b227 100644 --- a/extensions/memory-core/src/short-term-promotion.ts +++ b/extensions/memory-core/src/short-term-promotion.ts @@ -2849,55 +2849,43 @@ export async function removeGroundedShortTermCandidates(params: { return { removed, storePath }; } +async function writeRawShortTermStoreForTest( + workspaceDir: string, + raw: unknown, + namespace: string, + metaKey: "recall" | "phase", +): Promise { + const record = asRecord(raw); + const entries = asRecord(record?.entries); + await Promise.all([ + writeMemoryCoreWorkspaceEntries({ + namespace, + workspaceDir, + entries: entries ? Object.entries(entries).map(([key, value]) => ({ key, value })) : [], + }), + writeMemoryCoreWorkspaceEntry({ + namespace: SHORT_TERM_META_NAMESPACE, + workspaceDir, + key: metaKey, + value: { + updatedAt: + typeof record?.updatedAt === "string" && record.updatedAt.trim() + ? record.updatedAt + : new Date().toISOString(), + }, + }), + ]); +} + export const testing = { parseLockOwnerPid, isProcessLikelyAlive, readRecallStore: readStore, readPhaseSignalStore, - writeRawRecallStore: async (workspaceDir: string, raw: unknown) => { - const record = asRecord(raw); - const entries = asRecord(record?.entries); - await Promise.all([ - writeMemoryCoreWorkspaceEntries({ - namespace: SHORT_TERM_RECALL_NAMESPACE, - workspaceDir, - entries: entries ? Object.entries(entries).map(([key, value]) => ({ key, value })) : [], - }), - writeMemoryCoreWorkspaceEntry({ - namespace: SHORT_TERM_META_NAMESPACE, - workspaceDir, - key: "recall", - value: { - updatedAt: - typeof record?.updatedAt === "string" && record.updatedAt.trim() - ? record.updatedAt - : new Date().toISOString(), - }, - }), - ]); - }, - writeRawPhaseSignalStore: async (workspaceDir: string, raw: unknown) => { - const record = asRecord(raw); - const entries = asRecord(record?.entries); - await Promise.all([ - writeMemoryCoreWorkspaceEntries({ - namespace: SHORT_TERM_PHASE_SIGNAL_NAMESPACE, - workspaceDir, - entries: entries ? Object.entries(entries).map(([key, value]) => ({ key, value })) : [], - }), - writeMemoryCoreWorkspaceEntry({ - namespace: SHORT_TERM_META_NAMESPACE, - workspaceDir, - key: "phase", - value: { - updatedAt: - typeof record?.updatedAt === "string" && record.updatedAt.trim() - ? record.updatedAt - : new Date().toISOString(), - }, - }), - ]); - }, + writeRawRecallStore: (workspaceDir: string, raw: unknown) => + writeRawShortTermStoreForTest(workspaceDir, raw, SHORT_TERM_RECALL_NAMESPACE, "recall"), + writeRawPhaseSignalStore: (workspaceDir: string, raw: unknown) => + writeRawShortTermStoreForTest(workspaceDir, raw, SHORT_TERM_PHASE_SIGNAL_NAMESPACE, "phase"), writeShortTermLock: async (workspaceDir: string, entry: ShortTermLockEntry) => { await openMemoryCoreStateStore({ namespace: SHORT_TERM_LOCK_NAMESPACE, diff --git a/scripts/lib/local-heavy-check-runtime.mjs b/scripts/lib/local-heavy-check-runtime.mjs index 7a1d1a60d1a..78302dfadc0 100644 --- a/scripts/lib/local-heavy-check-runtime.mjs +++ b/scripts/lib/local-heavy-check-runtime.mjs @@ -42,6 +42,17 @@ function hasFlag(args, name) { return args.some((arg) => arg === name || arg.startsWith(`${name}=`)); } +function hasOxlintFormatArg(args) { + return args.some( + (arg) => + arg === "--format" || + arg.startsWith("--format=") || + arg === "-f" || + arg.startsWith("-f=") || + (arg.startsWith("-f") && arg.length > 2), + ); +} + /** Apply local tsgo defaults for declaration skipping, caching, throttling, and profiling. */ export function applyLocalTsgoPolicy(args, env, hostResources) { const nextEnv = { ...env }; @@ -96,6 +107,9 @@ export function applyLocalOxlintPolicy(args, env, hostResources) { ) { insertBeforeSeparator(nextArgs, "--report-unused-disable-directives-severity", "error"); } + if (nextEnv.GITHUB_ACTIONS === "true" && !hasOxlintFormatArg(nextArgs)) { + insertBeforeSeparator(nextArgs, "--format", "stylish"); + } if (shouldThrottleLocalHeavyChecks(nextEnv, hostResources)) { if (!hasFlag(nextArgs, "--threads")) { diff --git a/scripts/lib/run-extension-oxlint.mjs b/scripts/lib/run-extension-oxlint.mjs index b87f71fb669..635f5778973 100644 --- a/scripts/lib/run-extension-oxlint.mjs +++ b/scripts/lib/run-extension-oxlint.mjs @@ -9,23 +9,6 @@ import { } from "./local-heavy-check-runtime.mjs"; import { createManagedCommandInvocation } from "./managed-child-process.mjs"; -function hasOxlintFormatArg(args) { - return args.some( - (arg) => - arg === "--format" || - arg.startsWith("--format=") || - arg === "-f" || - arg.startsWith("-f=") || - (arg.startsWith("-f") && arg.length > 2), - ); -} - -function addOxlintFormatArg(args, value) { - const separatorIndex = args.indexOf("--"); - const insertIndex = separatorIndex === -1 ? args.length : separatorIndex; - args.splice(insertIndex, 0, "--format", value); -} - /** * Runs focused extension oxlint with a temp config and local heavy-check lock. */ @@ -61,9 +44,6 @@ export function runExtensionOxlint(params) { const baseArgs = ["-c", tempConfigPath, ...process.argv.slice(2), ...extensionFiles]; const { args: finalArgs, env } = applyLocalOxlintPolicy(baseArgs, process.env); - if (env.GITHUB_ACTIONS === "true" && !hasOxlintFormatArg(finalArgs)) { - addOxlintFormatArg(finalArgs, "stylish"); - } const oxlint = createManagedCommandInvocation({ args: finalArgs, bin: oxlintPath, diff --git a/scripts/run-oxlint.mjs b/scripts/run-oxlint.mjs index 45109ec46eb..3c285449ee4 100644 --- a/scripts/run-oxlint.mjs +++ b/scripts/run-oxlint.mjs @@ -40,23 +40,6 @@ const OXLINT_VALUE_FLAGS = new Set([ "--warn", ]); -function hasOxlintFormatArg(args) { - return args.some( - (arg) => - arg === "--format" || - arg.startsWith("--format=") || - arg === "-f" || - arg.startsWith("-f=") || - (arg.startsWith("-f") && arg.length > 2), - ); -} - -function addOxlintFormatArg(args, value) { - const separatorIndex = args.indexOf("--"); - const insertIndex = separatorIndex === -1 ? args.length : separatorIndex; - args.splice(insertIndex, 0, "--format", value); -} - /** * Returns whether oxlint args need package-boundary declaration artifacts first. */ @@ -229,9 +212,6 @@ export async function main(argv = process.argv.slice(2), runtimeEnv = process.en ); const sparseTargets = filterSparseMissingOxlintTargets(policyArgs); const finalArgs = sparseTargets.args; - if (env.GITHUB_ACTIONS === "true" && !hasOxlintFormatArg(finalArgs)) { - addOxlintFormatArg(finalArgs, "stylish"); - } if (sparseTargets.skippedTargets.length > 0) { console.error( `[oxlint] sparse checkout is missing tracked target(s); skipping ${sparseTargets.skippedTargets.join(", ")}`, diff --git a/src/auto-reply/reply/commands-diagnostics.ts b/src/auto-reply/reply/commands-diagnostics.ts index b14d5c1f472..f40cd4d6c33 100644 --- a/src/auto-reply/reply/commands-diagnostics.ts +++ b/src/auto-reply/reply/commands-diagnostics.ts @@ -116,14 +116,7 @@ async function handleDiagnosticsCommandWithDeps( } if (params.isGroup) { - const targets = await deps.resolvePrivateDiagnosticsTargets(params); - if (targets.length === 0) { - return { - shouldContinue: false, - reply: { text: DIAGNOSTICS_PRIVATE_ROUTE_UNAVAILABLE }, - }; - } - const privateTarget = targets[0]; + const privateTarget = (await deps.resolvePrivateDiagnosticsTargets(params))[0]; if (!privateTarget) { return { shouldContinue: false, @@ -140,17 +133,7 @@ async function handleDiagnosticsCommandWithDeps( reply: { text: DIAGNOSTICS_PRIVATE_ROUTE_ACK }, }; } - const delivered = await deps.deliverPrivateDiagnosticsReply({ - commandParams: params, - targets: [privateTarget], - reply: privateReply, - }); - return { - shouldContinue: false, - reply: { - text: delivered ? DIAGNOSTICS_PRIVATE_ROUTE_ACK : DIAGNOSTICS_PRIVATE_ROUTE_UNAVAILABLE, - }, - }; + return await deliverGroupDiagnosticsReplyPrivately(deps, params, privateReply, privateTarget); } const reply = await buildDiagnosticsReply(deps, params, args); @@ -183,16 +166,10 @@ async function deliverGroupDiagnosticsReplyPrivately( deps: DiagnosticsCommandDeps, params: HandleCommandsParams, reply: ReplyPayload, + privateTarget?: PrivateCommandRouteTarget, ) { - const targets = await deps.resolvePrivateDiagnosticsTargets(params); - if (targets.length === 0) { - return { - shouldContinue: false, - reply: { text: DIAGNOSTICS_PRIVATE_ROUTE_UNAVAILABLE }, - }; - } - const privateTarget = targets[0]; - if (!privateTarget) { + const target = privateTarget ?? (await deps.resolvePrivateDiagnosticsTargets(params))[0]; + if (!target) { return { shouldContinue: false, reply: { text: DIAGNOSTICS_PRIVATE_ROUTE_UNAVAILABLE }, @@ -200,7 +177,7 @@ async function deliverGroupDiagnosticsReplyPrivately( } const delivered = await deps.deliverPrivateDiagnosticsReply({ commandParams: params, - targets: [privateTarget], + targets: [target], reply, }); return { diff --git a/src/commands/doctor-auth.ts b/src/commands/doctor-auth.ts index 4dc5a02ff1f..8d96a6b184c 100644 --- a/src/commands/doctor-auth.ts +++ b/src/commands/doctor-auth.ts @@ -11,6 +11,7 @@ import { buildAuthHealthSummary, DEFAULT_OAUTH_WARN_MS, formatRemainingShort, + type AuthHealthSummary, } from "../agents/auth-health.js"; import { type AuthCredentialReasonCode, @@ -337,6 +338,16 @@ function authProfileCooldownToHealthFinding(params: { }; } +function isAuthProfileHealthIssue(profile: AuthHealthSummary["profiles"][number]): boolean { + if (profile.type === "api_key") { + return profile.status === "missing"; + } + return ( + (profile.type === "oauth" || profile.type === "token") && + (profile.status === "expired" || profile.status === "expiring" || profile.status === "missing") + ); +} + async function collectAuthProfileHealthFindingsForTarget(params: { cfg: OpenClawConfig; allowKeychainPrompt: boolean; @@ -382,17 +393,7 @@ async function collectAuthProfileHealthFindingsForTarget(params: { warnAfterMs: DEFAULT_OAUTH_WARN_MS, allowKeychainPrompt: params.allowKeychainPrompt, }); - const issues = summary.profiles.filter((profile) => { - if (profile.type === "api_key") { - return profile.status === "missing"; - } - return ( - (profile.type === "oauth" || profile.type === "token") && - (profile.status === "expired" || - profile.status === "expiring" || - profile.status === "missing") - ); - }); + const issues = summary.profiles.filter(isAuthProfileHealthIssue); for (const issue of issues) { const authIssue: AuthIssue = { profileId: issue.profileId, @@ -495,18 +496,7 @@ async function noteAuthProfileHealthForTarget(params: { allowKeychainPrompt: params.allowKeychainPrompt, }); - const findIssues = () => - summary.profiles.filter((profile) => { - if (profile.type === "api_key") { - return profile.status === "missing"; - } - return ( - (profile.type === "oauth" || profile.type === "token") && - (profile.status === "expired" || - profile.status === "expiring" || - profile.status === "missing") - ); - }); + const findIssues = () => summary.profiles.filter(isAuthProfileHealthIssue); let issues = findIssues(); if (issues.length === 0) { diff --git a/src/flows/search-setup.ts b/src/flows/search-setup.ts index 770c29f4226..b49a0c5477b 100644 --- a/src/flows/search-setup.ts +++ b/src/flows/search-setup.ts @@ -559,6 +559,15 @@ export async function runSearchSetupFlow( if (!entry) { return config; } + const finalizeSelection = (nextConfig: OpenClawConfig) => + finalizeSearchProviderSetup({ + originalConfig: config, + nextConfig, + entry, + runtime, + prompter, + opts, + }); const credentialLabel = resolveSearchProviderCredentialLabel(entry); const existingKey = resolveExistingKey(config, choice); const keyConfigured = hasExistingKey(config, choice); @@ -582,14 +591,7 @@ export async function runSearchSetupFlow( const result = existingKey ? applySearchKey(config, choice, existingKey) : applySearchProviderSelection(config, choice); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: result, - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(result); } if (!needsCredential) { @@ -601,14 +603,7 @@ export async function runSearchSetupFlow( ].join("\n"), "Web search", ); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchProviderSelection(config, choice), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchProviderSelection(config, choice)); } if (entry.credentialNote) { @@ -625,14 +620,7 @@ export async function runSearchSetupFlow( ].join("\n"), "Web search", ); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchProviderSelection(config, choice), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchProviderSelection(config, choice)); } if (providerAuthProfileAvailable && authProviderId) { @@ -645,27 +633,13 @@ export async function runSearchSetupFlow( ].join("\n"), "Web search", ); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchProviderSelection(config, choice), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchProviderSelection(config, choice)); } const useSecretRefMode = opts?.secretInputMode === "ref"; // pragma: allowlist secret if (useSecretRefMode) { if (keyConfigured) { - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchProviderSelection(config, choice), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchProviderSelection(config, choice)); } const ref = buildSearchEnvRef(config, choice); await prompter.note( @@ -677,14 +651,7 @@ export async function runSearchSetupFlow( ].join("\n"), "Web search", ); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchKey(config, choice, ref), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchKey(config, choice, ref)); } const keyInput = await prompter.text({ @@ -700,36 +667,15 @@ export async function runSearchSetupFlow( const key = normalizeOptionalString(keyInput) ?? ""; if (key) { const secretInput = resolveSearchSecretInput(config, choice, key, opts?.secretInputMode); - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchKey(config, choice, secretInput), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchKey(config, choice, secretInput)); } if (existingKey) { - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchKey(config, choice, existingKey), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchKey(config, choice, existingKey)); } if (keyConfigured || envAvailable) { - return await finalizeSearchProviderSetup({ - originalConfig: config, - nextConfig: applySearchProviderSelection(config, choice), - entry, - runtime, - prompter, - opts, - }); + return await finalizeSelection(applySearchProviderSelection(config, choice)); } await prompter.note( diff --git a/test/scripts/local-heavy-check-runtime.test.ts b/test/scripts/local-heavy-check-runtime.test.ts index a7123b9d417..5639cca21dc 100644 --- a/test/scripts/local-heavy-check-runtime.test.ts +++ b/test/scripts/local-heavy-check-runtime.test.ts @@ -33,6 +33,9 @@ function makeEnv(overrides: Record = {}) { if (!Object.hasOwn(overrides, "OPENCLAW_LOCAL_CHECK_MODE")) { delete env.OPENCLAW_LOCAL_CHECK_MODE; } + if (!Object.hasOwn(overrides, "GITHUB_ACTIONS")) { + delete env.GITHUB_ACTIONS; + } return env; } @@ -296,6 +299,35 @@ describe("local-heavy-check-runtime", () => { expect(env.GOMEMLIMIT).toBeUndefined(); }); + it("uses stylish oxlint output in GitHub Actions before the command separator", () => { + const { args } = applyLocalOxlintPolicy( + ["--", "src/example.ts"], + makeEnv({ + GITHUB_ACTIONS: "true", + OPENCLAW_LOCAL_CHECK_MODE: "full", + }), + ROOMY_HOST, + ); + + expect(args.slice(-4)).toEqual(["--format", "stylish", "--", "src/example.ts"]); + }); + + it.each(["--format", "--format=json", "-f", "-f=json", "-fjson"])( + "preserves an explicit oxlint format argument: %s", + (formatArg) => { + const { args } = applyLocalOxlintPolicy( + [formatArg], + makeEnv({ + GITHUB_ACTIONS: "true", + OPENCLAW_LOCAL_CHECK_MODE: "full", + }), + ROOMY_HOST, + ); + + expect(args).not.toContain("stylish"); + }, + ); + it("skips the heavy-check lock for explicit oxlint file targets", () => { const cwd = createTempDir("openclaw-oxlint-lock-skip-"); const target = path.join(cwd, "sample.ts");