惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
U
Unit 42
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
T
Tailwind CSS Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
腾讯CDC
I
InfoQ
GbyAI
GbyAI
博客园_首页

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix: improve mac menu status errors · openclaw/openclaw@f...
steipete · 2026-05-17 · via Recent Commits to openclaw:main

@@ -65,28 +65,28 @@ final class MenuSessionsInjector: NSObject, NSMenuDelegate {

6565

self.inject(into: menu)

6666

self.injectNodes(into: menu)

676768-

// Refresh in background for the next open; keep width stable while open.

68+

// Refresh in the background for the next open. Rebuilding custom menu

69+

// rows while AppKit is tracking the menu causes visible flicker.

6970

self.loadTask?.cancel()

70-

let forceRefresh = self.cachedSnapshot == nil || self.cachedErrorText != nil

71-

self.loadTask = Task { [weak self] in

71+

let shouldRepaintAfterRefresh = self.cachedSnapshot == nil || self.cachedErrorText != nil

72+

self.loadTask = Task { [weak self, weak menu] in

7273

guard let self else { return }

74+

let forceRefresh = shouldRepaintAfterRefresh

7375

await self.refreshCache(force: forceRefresh)

7476

await self.refreshUsageCache(force: forceRefresh)

7577

await self.refreshCostUsageCache(force: forceRefresh)

76-

await MainActor.run {

77-

guard self.isMenuOpen else { return }

78-

self.inject(into: menu)

79-

self.injectNodes(into: menu)

78+

if shouldRepaintAfterRefresh {

79+

await self.repaintOpenMenu(menu)

8080

}

8181

}

82828383

self.nodesLoadTask?.cancel()

84-

self.nodesLoadTask = Task { [weak self] in

84+

let shouldRepaintNodesAfterRefresh = self.shouldRepaintNodesAfterRefresh()

85+

self.nodesLoadTask = Task { [weak self, weak menu] in

8586

guard let self else { return }

8687

await self.nodesStore.refresh()

87-

await MainActor.run {

88-

guard self.isMenuOpen else { return }

89-

self.injectNodes(into: menu)

88+

if !shouldRepaintAfterRefresh, shouldRepaintNodesAfterRefresh {

89+

await self.repaintOpenMenuNodes(menu)

9090

}

9191

}

9292

}

@@ -95,8 +95,6 @@ final class MenuSessionsInjector: NSObject, NSMenuDelegate {

9595

self.originalDelegate?.menuDidClose?(menu)

9696

self.isMenuOpen = false

9797

self.menuOpenWidth = nil

98-

self.loadTask?.cancel()

99-

self.nodesLoadTask?.cancel()

10098

self.cancelPreviewTasks()

10199

}

102100

@@ -122,25 +120,18 @@ final class MenuSessionsInjector: NSObject, NSMenuDelegate {

122120

guard self.isMenuOpen, let menu = self.statusItem?.menu else { return }

123121

self.loadTask?.cancel()

124122

self.loadTask = Task { [weak self, weak menu] in

125-

guard let self, let menu else { return }

123+

guard let self else { return }

126124

await self.refreshCache(force: true)

127125

await self.refreshUsageCache(force: true)

128126

await self.refreshCostUsageCache(force: true)

129-

await MainActor.run {

130-

guard self.isMenuOpen else { return }

131-

self.inject(into: menu)

132-

self.injectNodes(into: menu)

133-

}

127+

await self.repaintOpenMenu(menu)

134128

}

135129136130

self.nodesLoadTask?.cancel()

137131

self.nodesLoadTask = Task { [weak self, weak menu] in

138-

guard let self, let menu else { return }

132+

guard let self else { return }

139133

await self.nodesStore.refresh()

140-

await MainActor.run {

141-

guard self.isMenuOpen else { return }

142-

self.injectNodes(into: menu)

143-

}

134+

await self.repaintOpenMenuNodes(menu)

144135

}

145136

}

146137

@@ -278,6 +269,28 @@ extension MenuSessionsInjector {

278269

_ = cursor

279270

}

280271272+

private func repaintOpenMenu(_ menu: NSMenu?) async {

273+

await MainActor.run {

274+

guard self.isMenuOpen, let menu else { return }

275+

self.inject(into: menu)

276+

self.injectNodes(into: menu)

277+

}

278+

}

279+280+

private func repaintOpenMenuNodes(_ menu: NSMenu?) async {

281+

await MainActor.run {

282+

guard self.isMenuOpen, let menu else { return }

283+

self.injectNodes(into: menu)

284+

}

285+

}

286+287+

private func shouldRepaintNodesAfterRefresh() -> Bool {

288+

guard self.isControlChannelConnected else { return false }

289+

return self.sortedNodeEntries().isEmpty

290+

|| self.nodesStore.lastError?.nonEmpty != nil

291+

|| self.nodesStore.statusMessage?.nonEmpty != nil

292+

}

293+281294

private func buildContextSubmenu(

282295

width: CGFloat,

283296

isConnected: Bool,

@@ -374,7 +387,7 @@ extension MenuSessionsInjector {

374387

return self.cachedErrorText ?? "Loading…"

375388

}

376389377-

return self.controlChannelStatusText(for: channelState)

390+

return Self.menuStatusText(self.controlChannelStatusText(for: channelState))

378391

}

379392380393

private func activeRows(from snapshot: SessionStoreSnapshot) -> [SessionRow] {

@@ -527,7 +540,7 @@ extension MenuSessionsInjector {

527540

case .connecting:

528541

"Connecting…"

529542

case let .degraded(message):

530-

message.nonEmpty ?? "Gateway disconnected"

543+

Self.menuStatusText(message.nonEmpty ?? "Gateway disconnected")

531544

case .disconnected:

532545

"Gateway disconnected"

533546

}

@@ -684,7 +697,7 @@ extension MenuSessionsInjector {

684697

self.previewTasks.removeAll()

685698

}

686699687-

private func makeMessageItem(text: String, symbolName: String, width: CGFloat, maxLines: Int? = 2) -> NSMenuItem {

700+

private func makeMessageItem(text: String, symbolName: String, width: CGFloat, maxLines: Int? = 3) -> NSMenuItem {

688701

let view = AnyView(

689702

HStack(alignment: .top, spacing: 8) {

690703

Image(systemName: symbolName)

@@ -810,6 +823,19 @@ extension MenuSessionsInjector {

810823

}

811824

return "Sessions unavailable"

812825

}

826+827+

private static func menuStatusText(_ text: String) -> String {

828+

let lines = text

829+

.trimmingCharacters(in: .whitespacesAndNewlines)

830+

.split(whereSeparator: \.isNewline)

831+

.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }

832+

.filter { !$0.isEmpty }

833+834+

let singleLine = (lines.isEmpty ? text : lines.joined(separator: " "))

835+

.trimmingCharacters(in: .whitespacesAndNewlines)

836+

guard singleLine.count > 180 else { return singleLine }

837+

return "\(singleLine.prefix(177))"

838+

}

813839

}

814840815841

extension MenuSessionsInjector {

@@ -1283,6 +1309,14 @@ extension MenuSessionsInjector {

12831309

self.inject(into: menu)

12841310

}

128513111312+

func testingControlChannelStatusText(for state: ControlChannel.ConnectionState) -> String {

1313+

self.controlChannelStatusText(for: state)

1314+

}

1315+1316+

func testingMenuStatusText(_ text: String) -> String {

1317+

Self.menuStatusText(text)

1318+

}

1319+12861320

func testingFindInsertIndex(in menu: NSMenu) -> Int? {

12871321

self.findInsertIndex(in: menu)

12881322

}