agentbridge-cli 0.1.15__tar.gz → 0.1.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/PKG-INFO +1 -1
  2. agentbridge_cli-0.1.17/agentbridge/_build_info.py +1 -0
  3. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/AgentBridgeMenuBarApp.swift +0 -1
  4. agentbridge_cli-0.1.17/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +78 -0
  5. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +45 -6
  6. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/pyproject.toml +2 -1
  7. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/uv.lock +5 -4
  8. agentbridge_cli-0.1.15/agentbridge/_build_info.py +0 -1
  9. agentbridge_cli-0.1.15/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +0 -135
  10. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/config.toml +0 -0
  11. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/SKILL.md +0 -0
  12. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/agents/openai.yaml +0 -0
  13. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/scripts/release_build.py +0 -0
  14. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.env.example +0 -0
  15. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/dependabot.yml +0 -0
  16. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/ci.yml +0 -0
  17. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/dependency-review.yml +0 -0
  18. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/release.yml +0 -0
  19. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.gitignore +0 -0
  20. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/AGENTS.md +0 -0
  21. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/CLAUDE.md +0 -0
  22. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/LICENSE +0 -0
  23. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/Makefile +0 -0
  24. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/README.md +0 -0
  25. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/TODO.txt +0 -0
  26. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/__init__.py +0 -0
  27. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/config.py +0 -0
  28. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/dashboard.py +0 -0
  29. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/models.py +0 -0
  30. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/pool.py +0 -0
  31. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/server.py +0 -0
  32. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-192.png +0 -0
  33. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-512.png +0 -0
  34. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/apple-touch-icon.png +0 -0
  35. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-16.png +0 -0
  36. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-32.png +0 -0
  37. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-48.png +0 -0
  38. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.ico +0 -0
  39. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.svg +0 -0
  40. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/site.webmanifest +0 -0
  41. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/base.html +0 -0
  42. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/chat.html +0 -0
  43. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/detail.html +0 -0
  44. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/page.html +0 -0
  45. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/pool.html +0 -0
  46. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/requests.html +0 -0
  47. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/architecture.png +0 -0
  48. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-final.png +0 -0
  49. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-normalized.png +0 -0
  50. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
  51. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/implementation-header-activity.png +0 -0
  52. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-header-activity.png +0 -0
  53. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-menu-icons.png +0 -0
  54. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge-normalized.png +0 -0
  55. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge.png +0 -0
  56. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows-normalized.png +0 -0
  57. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows.png +0 -0
  58. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-panel.png +0 -0
  59. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge-normalized.png +0 -0
  60. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge.png +0 -0
  61. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-active-workers.png +0 -0
  62. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-arrow-contrast-comparison.png +0 -0
  63. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-badge-comparison.png +0 -0
  64. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-inactive-comparison.png +0 -0
  65. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-no-workers.png +0 -0
  66. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa.md +0 -0
  67. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-design.md +0 -0
  68. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
  69. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/hatch_build.py +0 -0
  70. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/apple-store/app-store-icon-1024.png +0 -0
  71. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/icon/icon-1024.png +0 -0
  72. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/logo/logo-1024.png +0 -0
  73. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/manifest.json +0 -0
  74. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source-keyed.png +0 -0
  75. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source.png +0 -0
  76. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source-keyed.png +0 -0
  77. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source.png +0 -0
  78. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/social-background-source.png +0 -0
  79. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/social-source.png +0 -0
  80. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-192.png +0 -0
  81. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-512.png +0 -0
  82. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/apple-touch-icon.png +0 -0
  83. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-16.png +0 -0
  84. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-32.png +0 -0
  85. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-48.png +0 -0
  86. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.ico +0 -0
  87. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.svg +0 -0
  88. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/og-image-1200x630.png +0 -0
  89. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/site.webmanifest +0 -0
  90. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/logo.png +0 -0
  91. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Package.swift +0 -0
  92. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/README.md +0 -0
  93. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +0 -0
  94. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +0 -0
  95. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerController.swift +0 -0
  96. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +0 -0
  97. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +0 -0
  98. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +0 -0
  99. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +0 -0
  100. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/build_macos_app.sh +0 -0
  101. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/dashboard_load_test.py +0 -0
  102. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/verify_macos_app.sh +0 -0
  103. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/fixtures/ocr_test_document.png +0 -0
  104. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_config.py +0 -0
  105. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_dashboard.py +0 -0
  106. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_dependency_security.py +0 -0
  107. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_image_utils.py +0 -0
  108. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_model_mapping.py +0 -0
  109. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_models.py +0 -0
  110. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_pool.py +0 -0
  111. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_server.py +0 -0
  112. {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_session_logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentbridge-cli
3
- Version: 0.1.15
3
+ Version: 0.1.17
4
4
  Summary: Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter
5
5
  Project-URL: Homepage, https://github.com/tsilva/agentbridge
6
6
  Project-URL: Repository, https://github.com/tsilva/agentbridge
@@ -0,0 +1 @@
1
+ GIT_HASH = "6883ee1"
@@ -40,7 +40,6 @@ final class AgentBridgeAppDelegate: NSObject, NSApplicationDelegate {
40
40
  if let button = item.button {
41
41
  button.target = self
42
42
  button.action = #selector(togglePopover(_:))
43
- statusPresenter.install(on: button)
44
43
  statusPresenter.update(
45
44
  button: button,
46
45
  phase: controller.phase,
@@ -0,0 +1,78 @@
1
+ import AppKit
2
+
3
+ @MainActor
4
+ final class MenuBarStatusPresenter {
5
+ private weak var presentedButton: NSStatusBarButton?
6
+ private var displayedPhase: ServerPhase?
7
+ private(set) var displayedCount: Int?
8
+
9
+ func update(
10
+ button: NSStatusBarButton,
11
+ phase: ServerPhase,
12
+ activeWorkers: Int
13
+ ) {
14
+ let count = max(activeWorkers, 0)
15
+ let badgeCount = count > 0 ? count : nil
16
+ guard presentedButton !== button || displayedPhase != phase || displayedCount != badgeCount
17
+ else { return }
18
+
19
+ let label = Self.accessibilityLabel(for: phase, activeWorkers: count)
20
+ let symbol = NSImage(
21
+ systemSymbolName: phase.menuBarSymbol,
22
+ accessibilityDescription: label
23
+ )
24
+ let image = badgeCount.map { Self.badgedImage(symbol: symbol, count: $0) } ?? symbol
25
+ image?.isTemplate = true
26
+ button.image = image
27
+ button.toolTip = label
28
+ button.setAccessibilityLabel(label)
29
+ presentedButton = button
30
+ displayedPhase = phase
31
+ displayedCount = badgeCount
32
+ }
33
+
34
+ static func accessibilityLabel(for phase: ServerPhase, activeWorkers: Int) -> String {
35
+ guard activeWorkers > 0 else { return "AgentBridge: \(phase.label)" }
36
+ let noun = activeWorkers == 1 ? "worker" : "workers"
37
+ return "AgentBridge: \(phase.label), \(activeWorkers) active \(noun)"
38
+ }
39
+ private static func badgedImage(symbol: NSImage?, count: Int) -> NSImage {
40
+ let text = NSAttributedString(
41
+ string: String(count),
42
+ attributes: [
43
+ .font: NSFont.systemFont(ofSize: 7.5, weight: .semibold),
44
+ .foregroundColor: NSColor.black,
45
+ ]
46
+ )
47
+ let textSize = text.size()
48
+ let badgeWidth = max(11, ceil(textSize.width) + 1.5)
49
+ let size = NSSize(width: max(22, badgeWidth), height: 22)
50
+
51
+ // AppKit snapshots status items under different appearances. A layer-backed
52
+ // badge/text-field subview mutates during those callbacks and can schedule
53
+ // another snapshot indefinitely, even while hidden. Keep the entire icon
54
+ // in one template image so snapshots never update a custom view hierarchy.
55
+ return NSImage(size: size, flipped: false) { rect in
56
+ symbol?.draw(in: NSRect(x: (rect.width - 18) / 2, y: 3, width: 18, height: 18))
57
+ let badge = NSBezierPath(roundedRect: NSRect(
58
+ x: rect.width - badgeWidth, y: 0, width: badgeWidth, height: 11
59
+ ), xRadius: 5.5, yRadius: 5.5)
60
+ guard let context = NSGraphicsContext.current?.cgContext else { return false }
61
+ context.saveGState()
62
+ context.setBlendMode(.clear)
63
+ badge.fill()
64
+ context.setBlendMode(.normal)
65
+ NSColor.black.withAlphaComponent(0.48).setFill()
66
+ badge.fill()
67
+ // Cut the number out of the alpha mask; macOS supplies the contrasting
68
+ // foreground color for both light and dark menu bars.
69
+ context.setBlendMode(.destinationOut)
70
+ text.draw(at: NSPoint(
71
+ x: rect.width - badgeWidth + (badgeWidth - textSize.width) / 2,
72
+ y: (11 - textSize.height) / 2
73
+ ))
74
+ context.restoreGState()
75
+ return true
76
+ }
77
+ }
78
+ }
@@ -77,8 +77,8 @@ final class StatusModelsTests: XCTestCase {
77
77
  func testMenuBarBadgeIsHiddenWithoutActiveWorkers() throws {
78
78
  let (canvas, button, presenter) = makeMenuBarFixture(activeWorkers: 0)
79
79
 
80
- XCTAssertTrue(presenter.badgeView.isHidden)
81
- XCTAssertNil(presenter.badgeView.displayedCount)
80
+ XCTAssertTrue(button.subviews.isEmpty)
81
+ XCTAssertNil(presenter.displayedCount)
82
82
  XCTAssertEqual(button.toolTip, "AgentBridge: Running")
83
83
 
84
84
  try writeSnapshot(
@@ -87,14 +87,33 @@ final class StatusModelsTests: XCTestCase {
87
87
  )
88
88
  }
89
89
 
90
+ @MainActor
91
+ func testMenuBarIconUsesAdaptiveTemplateRendering() {
92
+ let (_, button, presenter) = makeMenuBarFixture(activeWorkers: 0)
93
+
94
+ XCTAssertEqual(
95
+ button.image?.isTemplate,
96
+ true,
97
+ "Menu-bar icons must be templates so macOS can maintain contrast"
98
+ )
99
+
100
+ presenter.update(
101
+ button: button,
102
+ phase: .runningManaged,
103
+ activeWorkers: 48
104
+ )
105
+ XCTAssertEqual(button.image?.isTemplate, true)
106
+ XCTAssertEqual(presenter.displayedCount, 48)
107
+ }
108
+
90
109
  @MainActor
91
110
  func testMenuBarBadgeShowsActiveWorkerCount() throws {
92
111
  let (canvas, button, presenter) = makeMenuBarFixture(activeWorkers: 48)
93
112
 
94
- XCTAssertFalse(presenter.badgeView.isHidden)
95
- XCTAssertEqual(presenter.badgeView.displayedCount, 48)
113
+ XCTAssertTrue(button.subviews.isEmpty)
114
+ XCTAssertEqual(presenter.displayedCount, 48)
96
115
  XCTAssertEqual(button.toolTip, "AgentBridge: Running, 48 active workers")
97
- XCTAssertEqual(button.image?.isTemplate, false)
116
+ XCTAssertEqual(button.image?.isTemplate, true)
98
117
 
99
118
  try writeSnapshot(
100
119
  of: canvas,
@@ -102,6 +121,27 @@ final class StatusModelsTests: XCTestCase {
102
121
  )
103
122
  }
104
123
 
124
+ @MainActor
125
+ func testUnchangedHealthDoesNotReplaceStatusImage() {
126
+ let (_, button, presenter) = makeMenuBarFixture(activeWorkers: 2)
127
+ let image = button.image
128
+
129
+ for _ in 0..<10 {
130
+ presenter.update(button: button, phase: .runningManaged, activeWorkers: 2)
131
+ }
132
+
133
+ XCTAssertTrue(button.image === image)
134
+ XCTAssertTrue(button.subviews.isEmpty)
135
+
136
+ presenter.update(button: button, phase: .runningManaged, activeWorkers: 0)
137
+ XCTAssertFalse(button.image === image)
138
+ XCTAssertNil(presenter.displayedCount)
139
+ XCTAssertEqual(button.toolTip, "AgentBridge: Running")
140
+
141
+ presenter.update(button: button, phase: .failed, activeWorkers: 0)
142
+ XCTAssertEqual(button.toolTip, "AgentBridge: Needs attention")
143
+ }
144
+
105
145
  @MainActor
106
146
  private func makeMenuBarFixture(
107
147
  activeWorkers: Int
@@ -120,7 +160,6 @@ final class StatusModelsTests: XCTestCase {
120
160
  button.isBordered = false
121
161
  canvas.addSubview(button)
122
162
  let presenter = MenuBarStatusPresenter()
123
- presenter.install(on: button)
124
163
  presenter.update(
125
164
  button: button,
126
165
  phase: .runningManaged,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentbridge-cli"
3
- version = "0.1.15"
3
+ version = "0.1.17"
4
4
  description = "Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -71,6 +71,7 @@ select = ["E", "F", "I"]
71
71
  required-version = "==0.11.13"
72
72
  exclude-newer = "7 days"
73
73
  constraint-dependencies = [
74
+ "anyio>=4.14.2",
74
75
  "click>=8.3.3",
75
76
  "cryptography>=50.0.0",
76
77
  "idna>=3.15",
@@ -22,6 +22,7 @@ gradlab = false
22
22
 
23
23
  [manifest]
24
24
  constraints = [
25
+ { name = "anyio", specifier = ">=4.14.2" },
25
26
  { name = "click", specifier = ">=8.3.3" },
26
27
  { name = "cryptography", specifier = ">=50.0.0" },
27
28
  { name = "guardrails-ai", specifier = "!=0.10.1" },
@@ -37,7 +38,7 @@ constraints = [
37
38
 
38
39
  [[package]]
39
40
  name = "agentbridge-cli"
40
- version = "0.1.15"
41
+ version = "0.1.17"
41
42
  source = { editable = "." }
42
43
  dependencies = [
43
44
  { name = "claude-agent-sdk" },
@@ -91,15 +92,15 @@ wheels = [
91
92
 
92
93
  [[package]]
93
94
  name = "anyio"
94
- version = "4.12.1"
95
+ version = "4.14.2"
95
96
  source = { registry = "https://pypi.org/simple" }
96
97
  dependencies = [
97
98
  { name = "idna" },
98
99
  { name = "typing-extensions", marker = "python_full_version < '3.13'" },
99
100
  ]
100
- sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
101
+ sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" }
101
102
  wheels = [
102
- { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
103
+ { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
103
104
  ]
104
105
 
105
106
  [[package]]
@@ -1 +0,0 @@
1
- GIT_HASH = "690c228"
@@ -1,135 +0,0 @@
1
- import AppKit
2
-
3
- @MainActor
4
- final class MenuBarStatusPresenter {
5
- let badgeView = MenuBarActivityBadgeView()
6
-
7
- func install(on button: NSStatusBarButton) {
8
- guard badgeView.superview !== button else { return }
9
-
10
- badgeView.translatesAutoresizingMaskIntoConstraints = false
11
- button.addSubview(badgeView)
12
- NSLayoutConstraint.activate([
13
- badgeView.trailingAnchor.constraint(equalTo: button.trailingAnchor),
14
- badgeView.bottomAnchor.constraint(equalTo: button.bottomAnchor, constant: 2),
15
- badgeView.heightAnchor.constraint(equalToConstant: 11),
16
- ])
17
- }
18
-
19
- func update(
20
- button: NSStatusBarButton,
21
- phase: ServerPhase,
22
- activeWorkers: Int
23
- ) {
24
- let count = max(activeWorkers, 0)
25
- let label = Self.accessibilityLabel(for: phase, activeWorkers: count)
26
- let baseImage = NSImage(
27
- systemSymbolName: phase.menuBarSymbol,
28
- accessibilityDescription: label
29
- )
30
- let appearance = button.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua])
31
- let symbolDetailColor = appearance == .darkAqua
32
- ? NSColor.black.withAlphaComponent(0.68)
33
- : NSColor.white.withAlphaComponent(0.88)
34
- let paletteColors: [NSColor]
35
- switch phase {
36
- case .runningManaged, .runningExternal, .conflict, .failed:
37
- paletteColors = [symbolDetailColor, .labelColor]
38
- case .starting, .stopping, .stopped:
39
- paletteColors = [.labelColor]
40
- }
41
- let colorConfiguration = NSImage.SymbolConfiguration(
42
- paletteColors: paletteColors
43
- )
44
- let image = baseImage?.withSymbolConfiguration(colorConfiguration) ?? baseImage
45
- image?.isTemplate = false
46
- button.image = image
47
- button.toolTip = label
48
- button.setAccessibilityLabel(label)
49
- badgeView.update(count: count)
50
- }
51
-
52
- static func accessibilityLabel(for phase: ServerPhase, activeWorkers: Int) -> String {
53
- guard activeWorkers > 0 else { return "AgentBridge: \(phase.label)" }
54
- let noun = activeWorkers == 1 ? "worker" : "workers"
55
- return "AgentBridge: \(phase.label), \(activeWorkers) active \(noun)"
56
- }
57
- }
58
-
59
- @MainActor
60
- final class MenuBarActivityBadgeView: NSView {
61
- private let countLabel = NSTextField(labelWithString: "")
62
-
63
- private(set) var displayedCount: Int?
64
-
65
- override init(frame frameRect: NSRect) {
66
- super.init(frame: frameRect)
67
- configureView()
68
- }
69
-
70
- required init?(coder: NSCoder) {
71
- super.init(coder: coder)
72
- configureView()
73
- }
74
-
75
- override var intrinsicContentSize: NSSize {
76
- let labelWidth = ceil(countLabel.intrinsicContentSize.width)
77
- return NSSize(width: max(11, labelWidth + 1.5), height: 11)
78
- }
79
-
80
- override func hitTest(_ point: NSPoint) -> NSView? {
81
- nil
82
- }
83
-
84
- override func viewDidChangeEffectiveAppearance() {
85
- super.viewDidChangeEffectiveAppearance()
86
- updateColors()
87
- }
88
-
89
- func update(count: Int) {
90
- guard count > 0 else {
91
- displayedCount = nil
92
- countLabel.stringValue = ""
93
- isHidden = true
94
- invalidateIntrinsicContentSize()
95
- return
96
- }
97
-
98
- displayedCount = count
99
- countLabel.stringValue = String(count)
100
- isHidden = false
101
- invalidateIntrinsicContentSize()
102
- }
103
-
104
- private func configureView() {
105
- wantsLayer = true
106
- layer?.cornerRadius = 5.5
107
- layer?.cornerCurve = .continuous
108
-
109
- countLabel.translatesAutoresizingMaskIntoConstraints = false
110
- countLabel.font = .systemFont(ofSize: 7.5, weight: .semibold)
111
- countLabel.alignment = .center
112
- countLabel.lineBreakMode = .byClipping
113
- countLabel.maximumNumberOfLines = 1
114
- addSubview(countLabel)
115
-
116
- NSLayoutConstraint.activate([
117
- countLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.75),
118
- countLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -0.75),
119
- countLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
120
- ])
121
-
122
- setAccessibilityElement(false)
123
- isHidden = true
124
- updateColors()
125
- }
126
-
127
- private func updateColors() {
128
- let match = effectiveAppearance.bestMatch(from: [.darkAqua, .aqua])
129
- let usesDarkMenuBar = match == .darkAqua
130
- layer?.backgroundColor = NSColor.labelColor.withAlphaComponent(0.48).cgColor
131
- countLabel.textColor = usesDarkMenuBar
132
- ? NSColor.black.withAlphaComponent(0.78)
133
- : NSColor.white.withAlphaComponent(0.94)
134
- }
135
- }