agentbridge-cli 0.1.16__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.16 → 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.16 → 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.16 → agentbridge_cli-0.1.17}/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +26 -6
  6. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/pyproject.toml +2 -1
  7. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/uv.lock +5 -4
  8. agentbridge_cli-0.1.16/agentbridge/_build_info.py +0 -1
  9. agentbridge_cli-0.1.16/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +0 -120
  10. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.codex/config.toml +0 -0
  11. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.codex/skills/build-release/SKILL.md +0 -0
  12. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.codex/skills/build-release/agents/openai.yaml +0 -0
  13. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.codex/skills/build-release/scripts/release_build.py +0 -0
  14. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.env.example +0 -0
  15. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.github/dependabot.yml +0 -0
  16. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.github/workflows/ci.yml +0 -0
  17. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.github/workflows/dependency-review.yml +0 -0
  18. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.github/workflows/release.yml +0 -0
  19. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/.gitignore +0 -0
  20. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/AGENTS.md +0 -0
  21. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/CLAUDE.md +0 -0
  22. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/LICENSE +0 -0
  23. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/Makefile +0 -0
  24. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/README.md +0 -0
  25. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/TODO.txt +0 -0
  26. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/__init__.py +0 -0
  27. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/config.py +0 -0
  28. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/dashboard.py +0 -0
  29. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/models.py +0 -0
  30. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/pool.py +0 -0
  31. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/server.py +0 -0
  32. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-192.png +0 -0
  33. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-512.png +0 -0
  34. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/apple-touch-icon.png +0 -0
  35. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-16.png +0 -0
  36. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-32.png +0 -0
  37. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-48.png +0 -0
  38. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.ico +0 -0
  39. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.svg +0 -0
  40. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/static/brand/site.webmanifest +0 -0
  41. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/base.html +0 -0
  42. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/chat.html +0 -0
  43. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/detail.html +0 -0
  44. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/page.html +0 -0
  45. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/pool.html +0 -0
  46. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/requests.html +0 -0
  47. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/architecture.png +0 -0
  48. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-final.png +0 -0
  49. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-normalized.png +0 -0
  50. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
  51. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/implementation-header-activity.png +0 -0
  52. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-header-activity.png +0 -0
  53. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-menu-icons.png +0 -0
  54. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge-normalized.png +0 -0
  55. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge.png +0 -0
  56. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows-normalized.png +0 -0
  57. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows.png +0 -0
  58. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-panel.png +0 -0
  59. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge-normalized.png +0 -0
  60. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge.png +0 -0
  61. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/status-item-active-workers.png +0 -0
  62. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/status-item-arrow-contrast-comparison.png +0 -0
  63. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/status-item-badge-comparison.png +0 -0
  64. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/status-item-inactive-comparison.png +0 -0
  65. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa/status-item-no-workers.png +0 -0
  66. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/design-qa.md +0 -0
  67. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-design.md +0 -0
  68. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
  69. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/hatch_build.py +0 -0
  70. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/apple-store/app-store-icon-1024.png +0 -0
  71. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/icon/icon-1024.png +0 -0
  72. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/logo/logo-1024.png +0 -0
  73. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/manifest.json +0 -0
  74. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source-keyed.png +0 -0
  75. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source.png +0 -0
  76. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source-keyed.png +0 -0
  77. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source.png +0 -0
  78. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/social-background-source.png +0 -0
  79. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/sources/social-source.png +0 -0
  80. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-192.png +0 -0
  81. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-512.png +0 -0
  82. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/apple-touch-icon.png +0 -0
  83. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-16.png +0 -0
  84. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-32.png +0 -0
  85. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-48.png +0 -0
  86. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.ico +0 -0
  87. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.svg +0 -0
  88. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/og-image-1200x630.png +0 -0
  89. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/image-assets/web-seo/site.webmanifest +0 -0
  90. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/logo.png +0 -0
  91. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Package.swift +0 -0
  92. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/README.md +0 -0
  93. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +0 -0
  94. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +0 -0
  95. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerController.swift +0 -0
  96. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +0 -0
  97. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +0 -0
  98. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +0 -0
  99. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +0 -0
  100. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/scripts/build_macos_app.sh +0 -0
  101. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/scripts/dashboard_load_test.py +0 -0
  102. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/scripts/verify_macos_app.sh +0 -0
  103. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/fixtures/ocr_test_document.png +0 -0
  104. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_config.py +0 -0
  105. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_dashboard.py +0 -0
  106. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_dependency_security.py +0 -0
  107. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_image_utils.py +0 -0
  108. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_model_mapping.py +0 -0
  109. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_models.py +0 -0
  110. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_pool.py +0 -0
  111. {agentbridge_cli-0.1.16 → agentbridge_cli-0.1.17}/tests/test_server.py +0 -0
  112. {agentbridge_cli-0.1.16 → 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.16
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(
@@ -103,15 +103,15 @@ final class StatusModelsTests: XCTestCase {
103
103
  activeWorkers: 48
104
104
  )
105
105
  XCTAssertEqual(button.image?.isTemplate, true)
106
- XCTAssertFalse(presenter.badgeView.isHidden)
106
+ XCTAssertEqual(presenter.displayedCount, 48)
107
107
  }
108
108
 
109
109
  @MainActor
110
110
  func testMenuBarBadgeShowsActiveWorkerCount() throws {
111
111
  let (canvas, button, presenter) = makeMenuBarFixture(activeWorkers: 48)
112
112
 
113
- XCTAssertFalse(presenter.badgeView.isHidden)
114
- XCTAssertEqual(presenter.badgeView.displayedCount, 48)
113
+ XCTAssertTrue(button.subviews.isEmpty)
114
+ XCTAssertEqual(presenter.displayedCount, 48)
115
115
  XCTAssertEqual(button.toolTip, "AgentBridge: Running, 48 active workers")
116
116
  XCTAssertEqual(button.image?.isTemplate, true)
117
117
 
@@ -121,6 +121,27 @@ final class StatusModelsTests: XCTestCase {
121
121
  )
122
122
  }
123
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
+
124
145
  @MainActor
125
146
  private func makeMenuBarFixture(
126
147
  activeWorkers: Int
@@ -139,7 +160,6 @@ final class StatusModelsTests: XCTestCase {
139
160
  button.isBordered = false
140
161
  canvas.addSubview(button)
141
162
  let presenter = MenuBarStatusPresenter()
142
- presenter.install(on: button)
143
163
  presenter.update(
144
164
  button: button,
145
165
  phase: .runningManaged,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentbridge-cli"
3
- version = "0.1.16"
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.16"
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 = "4d5ec6b"
@@ -1,120 +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 image = NSImage(
27
- systemSymbolName: phase.menuBarSymbol,
28
- accessibilityDescription: label
29
- )
30
- image?.isTemplate = true
31
- button.image = image
32
- button.toolTip = label
33
- button.setAccessibilityLabel(label)
34
- badgeView.update(count: count)
35
- }
36
-
37
- static func accessibilityLabel(for phase: ServerPhase, activeWorkers: Int) -> String {
38
- guard activeWorkers > 0 else { return "AgentBridge: \(phase.label)" }
39
- let noun = activeWorkers == 1 ? "worker" : "workers"
40
- return "AgentBridge: \(phase.label), \(activeWorkers) active \(noun)"
41
- }
42
- }
43
-
44
- @MainActor
45
- final class MenuBarActivityBadgeView: NSView {
46
- private let countLabel = NSTextField(labelWithString: "")
47
-
48
- private(set) var displayedCount: Int?
49
-
50
- override init(frame frameRect: NSRect) {
51
- super.init(frame: frameRect)
52
- configureView()
53
- }
54
-
55
- required init?(coder: NSCoder) {
56
- super.init(coder: coder)
57
- configureView()
58
- }
59
-
60
- override var intrinsicContentSize: NSSize {
61
- let labelWidth = ceil(countLabel.intrinsicContentSize.width)
62
- return NSSize(width: max(11, labelWidth + 1.5), height: 11)
63
- }
64
-
65
- override func hitTest(_ point: NSPoint) -> NSView? {
66
- nil
67
- }
68
-
69
- override func viewDidChangeEffectiveAppearance() {
70
- super.viewDidChangeEffectiveAppearance()
71
- updateColors()
72
- }
73
-
74
- func update(count: Int) {
75
- guard count > 0 else {
76
- displayedCount = nil
77
- countLabel.stringValue = ""
78
- isHidden = true
79
- invalidateIntrinsicContentSize()
80
- return
81
- }
82
-
83
- displayedCount = count
84
- countLabel.stringValue = String(count)
85
- isHidden = false
86
- invalidateIntrinsicContentSize()
87
- }
88
-
89
- private func configureView() {
90
- wantsLayer = true
91
- layer?.cornerRadius = 5.5
92
- layer?.cornerCurve = .continuous
93
-
94
- countLabel.translatesAutoresizingMaskIntoConstraints = false
95
- countLabel.font = .systemFont(ofSize: 7.5, weight: .semibold)
96
- countLabel.alignment = .center
97
- countLabel.lineBreakMode = .byClipping
98
- countLabel.maximumNumberOfLines = 1
99
- addSubview(countLabel)
100
-
101
- NSLayoutConstraint.activate([
102
- countLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.75),
103
- countLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -0.75),
104
- countLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
105
- ])
106
-
107
- setAccessibilityElement(false)
108
- isHidden = true
109
- updateColors()
110
- }
111
-
112
- private func updateColors() {
113
- let match = effectiveAppearance.bestMatch(from: [.darkAqua, .aqua])
114
- let usesDarkMenuBar = match == .darkAqua
115
- layer?.backgroundColor = NSColor.labelColor.withAlphaComponent(0.48).cgColor
116
- countLabel.textColor = usesDarkMenuBar
117
- ? NSColor.black.withAlphaComponent(0.78)
118
- : NSColor.white.withAlphaComponent(0.94)
119
- }
120
- }