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.
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/PKG-INFO +1 -1
- agentbridge_cli-0.1.17/agentbridge/_build_info.py +1 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/AgentBridgeMenuBarApp.swift +0 -1
- agentbridge_cli-0.1.17/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +78 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +45 -6
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/pyproject.toml +2 -1
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/uv.lock +5 -4
- agentbridge_cli-0.1.15/agentbridge/_build_info.py +0 -1
- agentbridge_cli-0.1.15/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +0 -135
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/config.toml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/SKILL.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/agents/openai.yaml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/scripts/release_build.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.env.example +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/dependabot.yml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/ci.yml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/dependency-review.yml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.github/workflows/release.yml +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.gitignore +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/AGENTS.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/CLAUDE.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/LICENSE +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/Makefile +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/README.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/TODO.txt +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/__init__.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/config.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/dashboard.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/models.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/pool.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/server.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-192.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-512.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/apple-touch-icon.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-16.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-32.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon-48.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.ico +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/favicon.svg +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/site.webmanifest +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/base.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/chat.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/detail.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/page.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/pool.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/requests.html +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/architecture.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-final.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-normalized.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/implementation-header-activity.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-header-activity.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-menu-icons.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge-normalized.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows-normalized.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-panel.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge-normalized.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-active-workers.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-arrow-contrast-comparison.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-badge-comparison.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-inactive-comparison.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-no-workers.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-design.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/hatch_build.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/apple-store/app-store-icon-1024.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/icon/icon-1024.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/logo/logo-1024.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/manifest.json +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source-keyed.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source-keyed.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/social-background-source.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/social-source.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-192.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-512.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/apple-touch-icon.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-16.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-32.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-48.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.ico +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon.svg +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/og-image-1200x630.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/site.webmanifest +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/logo.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Package.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/README.md +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerController.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/build_macos_app.sh +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/dashboard_load_test.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/scripts/verify_macos_app.sh +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/fixtures/ocr_test_document.png +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_config.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_dashboard.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_dependency_security.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_image_utils.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_model_mapping.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_models.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_pool.py +0 -0
- {agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/tests/test_server.py +0 -0
- {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.
|
|
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(
|
|
81
|
-
XCTAssertNil(presenter.
|
|
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
|
-
|
|
95
|
-
XCTAssertEqual(presenter.
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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/
|
|
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/
|
|
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
|
-
}
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/.codex/skills/build-release/agents/openai.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-192.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/android-chrome-512.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/static/brand/apple-touch-icon.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/detail.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/agentbridge/templates/dashboard/requests.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/agentbridge-popover-normalized.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/implementation-header-activity.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-menu-icons.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-inactive-telegram-badge.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-low-contrast-arrows.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/reference-telegram-badge-normalized.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-badge-comparison.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/design-qa/status-item-inactive-comparison.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/docs/plans/2026-02-14-dashboard-implementation.md
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/apple-store/app-store-icon-1024.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/icon-source-keyed.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/logo-source-keyed.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/sources/social-background-source.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-192.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/android-chrome-512.png
RENAMED
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-16.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-32.png
RENAMED
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/favicon/favicon-48.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/image-assets/web-seo/og-image-1200x630.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentbridge_cli-0.1.15 → agentbridge_cli-0.1.17}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|