macOS/onboarding: fix prep follow-ups for openclaw#47263, thanks @ImLukeF
This commit is contained in:
parent
49c4ff67d4
commit
09d972c1dd
@ -39,6 +39,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugins/Chutes: add a bundled Chutes provider with plugin-owned OAuth/API-key auth, dynamic model discovery, and default-on extension wiring. (#41416) Thanks @Veightor.
|
||||
- Plugins/binding: add `onConversationBindingResolved(...)` so plugins can react immediately after bind approvals or denies without blocking channel interaction acknowledgements. (#48678) Thanks @huntharo.
|
||||
- CLI/config: expand `config set` with SecretRef and provider builder modes, JSON/batch assignment support, and `--dry-run` validation with structured JSON output. (#49296) Thanks @joshavant.
|
||||
- macOS/onboarding: refresh the local setup flow, keep existing configured local installs connected across onboarding-version bumps, and update OpenAI/GitHub Copilot onboarding defaults to GPT-5.4. (#47263) Thanks @ImLukeF.
|
||||
|
||||
### Breaking
|
||||
|
||||
|
||||
@ -14,10 +14,6 @@ enum CronCustomSessionTarget: Codable, Equatable {
|
||||
case predefined(CronSessionTarget)
|
||||
case session(id: String)
|
||||
|
||||
static let main: CronCustomSessionTarget = .predefined(.main)
|
||||
static let isolated: CronCustomSessionTarget = .predefined(.isolated)
|
||||
static let current: CronCustomSessionTarget = .predefined(.current)
|
||||
|
||||
var rawValue: String {
|
||||
switch self {
|
||||
case .predefined(let target):
|
||||
|
||||
@ -42,9 +42,11 @@ final class MacNodeModeCoordinator {
|
||||
continue
|
||||
}
|
||||
|
||||
let root = OpenClawConfigFile.loadDict()
|
||||
let onboardingComplete = Self.shouldConnectNodeMode(
|
||||
onboardingSeen: defaults.bool(forKey: onboardingSeenKey),
|
||||
onboardingVersion: defaults.integer(forKey: onboardingVersionKey))
|
||||
onboardingVersion: defaults.integer(forKey: onboardingVersionKey),
|
||||
root: root)
|
||||
if !onboardingComplete {
|
||||
if !lastBlockedOnOnboarding {
|
||||
self.logger.info("mac node waiting for onboarding completion")
|
||||
@ -131,8 +133,18 @@ final class MacNodeModeCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
static func shouldConnectNodeMode(onboardingSeen: Bool, onboardingVersion: Int) -> Bool {
|
||||
onboardingSeen && onboardingVersion >= currentOnboardingVersion
|
||||
static func shouldConnectNodeMode(
|
||||
onboardingSeen: Bool,
|
||||
onboardingVersion: Int,
|
||||
root: [String: Any]
|
||||
) -> Bool {
|
||||
if onboardingSeen && onboardingVersion >= currentOnboardingVersion {
|
||||
return true
|
||||
}
|
||||
|
||||
// Preserve runtime connectivity for existing local installs when a newer
|
||||
// app build refreshes onboarding copy or flow.
|
||||
return OnboardingWizardModel.hasExistingLocalSetup(root: root)
|
||||
}
|
||||
|
||||
private func currentCaps() -> [String] {
|
||||
|
||||
@ -196,12 +196,35 @@ final class OnboardingWizardModel {
|
||||
return Self.shouldSkipWizard(root: root)
|
||||
}
|
||||
|
||||
static func shouldSkipWizard(root: [String: Any]) -> Bool {
|
||||
static func hasExistingLocalSetup(root: [String: Any]) -> Bool {
|
||||
if let wizard = root["wizard"] as? [String: Any], !wizard.isEmpty {
|
||||
return true
|
||||
}
|
||||
if let gateway = root["gateway"] as? [String: Any],
|
||||
let auth = gateway["auth"] as? [String: Any]
|
||||
{
|
||||
if let mode = auth["mode"] as? String,
|
||||
!mode.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
{
|
||||
return true
|
||||
}
|
||||
if let token = auth["token"] as? String,
|
||||
!token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
{
|
||||
return true
|
||||
}
|
||||
if let password = auth["password"] as? String,
|
||||
!password.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static func shouldSkipWizard(root: [String: Any]) -> Bool {
|
||||
Self.hasExistingLocalSetup(root: root)
|
||||
}
|
||||
}
|
||||
|
||||
struct OnboardingWizardStepView: View {
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct OnboardingWizardModelTests {
|
||||
@Test func `skip wizard for legacy gateway auth config`() {
|
||||
let root: [String: Any] = [
|
||||
"gateway": [
|
||||
"auth": [
|
||||
"token": "legacy-token",
|
||||
],
|
||||
],
|
||||
]
|
||||
|
||||
#expect(OnboardingWizardModel.shouldSkipWizard(root: root))
|
||||
}
|
||||
|
||||
@Test func `do not skip wizard for empty config`() {
|
||||
#expect(OnboardingWizardModel.shouldSkipWizard(root: [:]) == false)
|
||||
}
|
||||
|
||||
@Test func `node mode keeps connecting for configured installs after onboarding refresh`() {
|
||||
let root: [String: Any] = [
|
||||
"gateway": [
|
||||
"auth": [
|
||||
"token": "legacy-token",
|
||||
],
|
||||
],
|
||||
]
|
||||
|
||||
#expect(
|
||||
MacNodeModeCoordinator.shouldConnectNodeMode(
|
||||
onboardingSeen: true,
|
||||
onboardingVersion: currentOnboardingVersion - 1,
|
||||
root: root))
|
||||
#expect(
|
||||
MacNodeModeCoordinator.shouldConnectNodeMode(
|
||||
onboardingSeen: false,
|
||||
onboardingVersion: 0,
|
||||
root: root))
|
||||
}
|
||||
|
||||
@Test func `node mode blocks truly unconfigured installs until onboarding is current`() {
|
||||
#expect(
|
||||
MacNodeModeCoordinator.shouldConnectNodeMode(
|
||||
onboardingSeen: false,
|
||||
onboardingVersion: 0,
|
||||
root: [:]) == false)
|
||||
#expect(
|
||||
MacNodeModeCoordinator.shouldConnectNodeMode(
|
||||
onboardingSeen: true,
|
||||
onboardingVersion: currentOnboardingVersion,
|
||||
root: [:]))
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,7 @@ async function runGitHubCopilotAuth(ctx: ProviderAuthContext) {
|
||||
credential,
|
||||
},
|
||||
],
|
||||
defaultModel: "github-copilot/gpt-4o",
|
||||
defaultModel: "github-copilot/gpt-5.4",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1060,7 +1060,7 @@ describe("applyAuthChoice", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultModel: "github-copilot/gpt-4o",
|
||||
defaultModel: "github-copilot/gpt-5.4",
|
||||
})),
|
||||
},
|
||||
],
|
||||
@ -1089,7 +1089,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
expect(resolveAgentModelPrimaryValue(result.config.agents?.defaults?.model)).toBe(
|
||||
"github-copilot/gpt-4o",
|
||||
"github-copilot/gpt-5.4",
|
||||
);
|
||||
} finally {
|
||||
if (previousIsTTYDescriptor) {
|
||||
|
||||
@ -112,7 +112,7 @@ describe("applyDefaultModelChoice", () => {
|
||||
});
|
||||
|
||||
it("uses applyDefaultConfig path when setDefaultModel is true", async () => {
|
||||
const defaultModel = "openai/gpt-5.1-codex";
|
||||
const defaultModel = "openai/gpt-5.4";
|
||||
const applied = await applyDefaultModelChoice({
|
||||
config: {},
|
||||
setDefaultModel: true,
|
||||
|
||||
@ -238,7 +238,7 @@ describe("provider auth contract", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultModel: "github-copilot/gpt-4o",
|
||||
defaultModel: "github-copilot/gpt-5.4",
|
||||
});
|
||||
} finally {
|
||||
if (previousIsTTYDescriptor) {
|
||||
|
||||
@ -3,7 +3,7 @@ import { ensureModelAllowlistEntry } from "./provider-model-allowlist.js";
|
||||
import { applyAgentDefaultPrimaryModel } from "./provider-model-primary.js";
|
||||
|
||||
export const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3.1-pro-preview";
|
||||
export const OPENAI_DEFAULT_MODEL = "openai/gpt-5.1-codex";
|
||||
export const OPENAI_DEFAULT_MODEL = "openai/gpt-5.4";
|
||||
export const OPENCODE_GO_DEFAULT_MODEL_REF = "opencode-go/kimi-k2.5";
|
||||
export const OPENCODE_ZEN_DEFAULT_MODEL = "opencode/claude-opus-4-6";
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user