agentbridge-cli 0.1.11__tar.gz → 0.1.12__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 (116) hide show
  1. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.codex/skills/build-release/SKILL.md +26 -11
  2. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.codex/skills/build-release/scripts/release_build.py +41 -1
  3. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.github/dependabot.yml +19 -0
  4. agentbridge_cli-0.1.12/.github/workflows/ci.yml +52 -0
  5. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.github/workflows/release.yml +131 -16
  6. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.gitignore +2 -0
  7. agentbridge_cli-0.1.11/README.md → agentbridge_cli-0.1.12/PKG-INFO +70 -5
  8. agentbridge_cli-0.1.11/PKG-INFO → agentbridge_cli-0.1.12/README.md +38 -35
  9. agentbridge_cli-0.1.12/agentbridge/_build_info.py +1 -0
  10. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/dashboard.py +46 -0
  11. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/pool.py +1 -0
  12. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/server.py +55 -16
  13. agentbridge_cli-0.1.12/agentbridge/static/brand/android-chrome-192.png +0 -0
  14. agentbridge_cli-0.1.12/agentbridge/static/brand/android-chrome-512.png +0 -0
  15. agentbridge_cli-0.1.12/agentbridge/static/brand/apple-touch-icon.png +0 -0
  16. agentbridge_cli-0.1.12/agentbridge/static/brand/favicon-16.png +0 -0
  17. agentbridge_cli-0.1.12/agentbridge/static/brand/favicon-32.png +0 -0
  18. agentbridge_cli-0.1.12/agentbridge/static/brand/favicon-48.png +0 -0
  19. agentbridge_cli-0.1.12/agentbridge/static/brand/favicon.ico +0 -0
  20. agentbridge_cli-0.1.12/agentbridge/static/brand/favicon.svg +11 -0
  21. {agentbridge_cli-0.1.11/image-assets/web-seo → agentbridge_cli-0.1.12/agentbridge/static/brand}/site.webmanifest +4 -4
  22. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/base.html +28 -21
  23. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/chat.html +1 -1
  24. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/page.html +1 -1
  25. agentbridge_cli-0.1.12/design-qa/agentbridge-popover-final.png +0 -0
  26. agentbridge_cli-0.1.12/design-qa/agentbridge-popover-normalized.png +0 -0
  27. agentbridge_cli-0.1.12/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
  28. agentbridge_cli-0.1.12/design-qa/implementation-header-activity.png +0 -0
  29. agentbridge_cli-0.1.12/design-qa/reference-header-activity.png +0 -0
  30. agentbridge_cli-0.1.12/design-qa/reference-panel.png +0 -0
  31. agentbridge_cli-0.1.12/design-qa.md +43 -0
  32. agentbridge_cli-0.1.12/image-assets/apple-store/app-store-icon-1024.png +0 -0
  33. agentbridge_cli-0.1.12/image-assets/icon/icon-1024.png +0 -0
  34. agentbridge_cli-0.1.12/image-assets/logo/logo-1024.png +0 -0
  35. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/image-assets/manifest.json +14 -2
  36. agentbridge_cli-0.1.12/image-assets/sources/icon-source-keyed.png +0 -0
  37. agentbridge_cli-0.1.12/image-assets/sources/icon-source.png +0 -0
  38. agentbridge_cli-0.1.12/image-assets/sources/logo-source-keyed.png +0 -0
  39. agentbridge_cli-0.1.12/image-assets/sources/logo-source.png +0 -0
  40. agentbridge_cli-0.1.12/image-assets/sources/social-background-source.png +0 -0
  41. agentbridge_cli-0.1.12/image-assets/sources/social-source.png +0 -0
  42. agentbridge_cli-0.1.12/image-assets/web-seo/android-chrome-192.png +0 -0
  43. agentbridge_cli-0.1.12/image-assets/web-seo/android-chrome-512.png +0 -0
  44. agentbridge_cli-0.1.12/image-assets/web-seo/apple-touch-icon.png +0 -0
  45. agentbridge_cli-0.1.12/image-assets/web-seo/favicon/favicon-16.png +0 -0
  46. agentbridge_cli-0.1.12/image-assets/web-seo/favicon/favicon-32.png +0 -0
  47. agentbridge_cli-0.1.12/image-assets/web-seo/favicon/favicon-48.png +0 -0
  48. agentbridge_cli-0.1.12/image-assets/web-seo/favicon/favicon.ico +0 -0
  49. agentbridge_cli-0.1.12/image-assets/web-seo/favicon/favicon.svg +11 -0
  50. agentbridge_cli-0.1.12/image-assets/web-seo/og-image-1200x630.png +0 -0
  51. agentbridge_cli-0.1.12/image-assets/web-seo/site.webmanifest +21 -0
  52. agentbridge_cli-0.1.12/logo.png +0 -0
  53. agentbridge_cli-0.1.12/macos/Package.swift +21 -0
  54. agentbridge_cli-0.1.12/macos/README.md +46 -0
  55. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/AgentBridgeMenuBarApp.swift +172 -0
  56. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +40 -0
  57. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +67 -0
  58. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/ServerController.swift +266 -0
  59. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +116 -0
  60. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +225 -0
  61. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +131 -0
  62. agentbridge_cli-0.1.12/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +284 -0
  63. agentbridge_cli-0.1.12/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +74 -0
  64. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/pyproject.toml +26 -7
  65. agentbridge_cli-0.1.12/scripts/build_macos_app.sh +156 -0
  66. agentbridge_cli-0.1.12/scripts/verify_macos_app.sh +25 -0
  67. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_dashboard.py +50 -2
  68. agentbridge_cli-0.1.12/tests/test_dependency_security.py +74 -0
  69. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_pool.py +5 -0
  70. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_server.py +28 -0
  71. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/uv.lock +553 -99
  72. agentbridge_cli-0.1.11/.github/workflows/ci.yml +0 -36
  73. agentbridge_cli-0.1.11/agentbridge/_build_info.py +0 -1
  74. agentbridge_cli-0.1.11/image-assets/icon/icon-1024.png +0 -0
  75. agentbridge_cli-0.1.11/image-assets/logo/logo-1024.png +0 -0
  76. agentbridge_cli-0.1.11/image-assets/sources/icon-source-keyed.png +0 -0
  77. agentbridge_cli-0.1.11/image-assets/sources/icon-source.png +0 -0
  78. agentbridge_cli-0.1.11/image-assets/sources/logo-source-keyed.png +0 -0
  79. agentbridge_cli-0.1.11/image-assets/sources/logo-source.png +0 -0
  80. agentbridge_cli-0.1.11/image-assets/sources/social-background-source.png +0 -0
  81. agentbridge_cli-0.1.11/image-assets/sources/social-source.png +0 -0
  82. agentbridge_cli-0.1.11/image-assets/web-seo/android-chrome-192.png +0 -0
  83. agentbridge_cli-0.1.11/image-assets/web-seo/android-chrome-512.png +0 -0
  84. agentbridge_cli-0.1.11/image-assets/web-seo/apple-touch-icon.png +0 -0
  85. agentbridge_cli-0.1.11/image-assets/web-seo/favicon/favicon-16.png +0 -0
  86. agentbridge_cli-0.1.11/image-assets/web-seo/favicon/favicon-32.png +0 -0
  87. agentbridge_cli-0.1.11/image-assets/web-seo/favicon/favicon-48.png +0 -0
  88. agentbridge_cli-0.1.11/image-assets/web-seo/favicon/favicon.ico +0 -0
  89. agentbridge_cli-0.1.11/image-assets/web-seo/og-image-1200x630.png +0 -0
  90. agentbridge_cli-0.1.11/logo.png +0 -0
  91. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.codex/config.toml +0 -0
  92. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.codex/skills/build-release/agents/openai.yaml +0 -0
  93. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.env.example +0 -0
  94. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/.github/workflows/dependency-review.yml +0 -0
  95. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/AGENTS.md +0 -0
  96. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/CLAUDE.md +0 -0
  97. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/LICENSE +0 -0
  98. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/Makefile +0 -0
  99. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/TODO.txt +0 -0
  100. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/__init__.py +0 -0
  101. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/config.py +0 -0
  102. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/models.py +0 -0
  103. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/detail.html +0 -0
  104. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/pool.html +0 -0
  105. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/agentbridge/templates/dashboard/requests.html +0 -0
  106. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/architecture.png +0 -0
  107. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/docs/plans/2026-02-14-dashboard-design.md +0 -0
  108. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
  109. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/hatch_build.py +0 -0
  110. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/scripts/dashboard_load_test.py +0 -0
  111. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/fixtures/ocr_test_document.png +0 -0
  112. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_config.py +0 -0
  113. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_image_utils.py +0 -0
  114. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_model_mapping.py +0 -0
  115. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_models.py +0 -0
  116. {agentbridge_cli-0.1.11 → agentbridge_cli-0.1.12}/tests/test_session_logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: build-release
3
- description: Build, publish, and verify AgentBridge releases. Use when the user invokes /build-release or asks to cut, launch, tag, publish, monitor, or verify an agentbridge-cli PyPI or GitHub release.
3
+ description: Build, publish, and verify AgentBridge releases. Use when the user invokes /build-release or asks to cut, launch, tag, publish, monitor, or verify the agentbridge-cli PyPI package or macOS app.
4
4
  ---
5
5
 
6
6
  # Build Release
@@ -9,7 +9,8 @@ Use the repository-owned GitHub Actions workflow and PyPI Trusted Publishing.
9
9
  Do not create a local tag or upload with local credentials: pushing a new
10
10
  `pyproject.toml` version to `main` triggers `.github/workflows/release.yml`,
11
11
  which tests, scans, builds, creates `v<version>`, creates the GitHub Release,
12
- and publishes `agentbridge-cli`.
12
+ publishes `agentbridge-cli`, and, when macOS publishing is enabled, attaches
13
+ signed and notarized arm64 and x86_64 DMGs.
13
14
 
14
15
  Use the next unused patch version unless the user requests another valid,
15
16
  unused semantic version. Treat an untagged version absent from PyPI as pending.
@@ -28,6 +29,13 @@ git log --oneline HEAD..origin/main
28
29
  Stop on unrelated changes, unpublished commits, divergence, or another branch.
29
30
  Do not clean, pull, commit unrelated files, or switch branches.
30
31
 
32
+ Require the repository variable `MACOS_RELEASE_ENABLED` to be `true` and verify
33
+ that these Actions secrets are configured before a release expected to contain
34
+ the macOS app: `APPLE_CERTIFICATE_BASE64`, `APPLE_CERTIFICATE_PASSWORD`,
35
+ `APPLE_KEYCHAIN_PASSWORD`, `APPLE_NOTARY_APPLE_ID`, `APPLE_NOTARY_PASSWORD`, and
36
+ `APPLE_TEAM_ID`. Secret names may be inspected with `gh secret list`; never read
37
+ or print secret values.
38
+
31
39
  2. Select the release version from the repository root:
32
40
 
33
41
  ```bash
@@ -47,10 +55,12 @@ uv lock
47
55
  python3 .codex/skills/build-release/scripts/release_build.py preflight --version <version>
48
56
  ```
49
57
 
50
- The preflight requires consistent project and lock metadata, an unused PyPI
51
- version and tag, clean patch formatting, a frozen lock, passing tests on Python
52
- 3.12 and 3.13, Ruff, a successful wheel and sdist build, artifact audits, and a
53
- wheel installation smoke test. Stop at the exact failed gate.
58
+ The preflight requires macOS. It checks consistent project and lock metadata, an
59
+ unused PyPI version and tag, clean patch formatting, a frozen lock, Python 3.12
60
+ and 3.13 tests, Ruff, Swift tests, a self-contained app/DMG build for the current
61
+ Mac architecture, app signature and embedded-runtime smoke tests, wheel and
62
+ sdist audits, and a wheel installation smoke test. CI builds and notarizes both
63
+ macOS architectures. Stop at the exact failed gate.
54
64
 
55
65
  4. Review and publish the release commit:
56
66
 
@@ -87,12 +97,17 @@ python3 .codex/skills/build-release/scripts/release_build.py wait-pypi --version
87
97
  gh release view v<version> --json url,tagName,assets
88
98
  ```
89
99
 
90
- Do not report success until PyPI returns files for the exact version. If the
91
- workflow fails, inspect `gh run view <run-id> --log-failed` and report the
92
- failed gate before considering recovery.
100
+ When macOS publishing is enabled, require both
101
+ `AgentBridge-<version>-macos-arm64.dmg` and
102
+ `AgentBridge-<version>-macos-x86_64.dmg` plus their `.sha256` files in the
103
+ release assets. Do not report success until PyPI returns exact-version files and
104
+ all required GitHub assets exist. If the workflow fails, inspect
105
+ `gh run view <run-id> --log-failed` and report the failed gate before considering
106
+ recovery.
93
107
 
94
108
  ## Final Response
95
109
 
96
110
  Lead with the exact PyPI version URL. Report the tag, release workflow URL and
97
- conclusion, GitHub Release URL, pushed commit, and every distribution filename.
98
- On failure, report the exact command or job and the next safe recovery action.
111
+ conclusion, GitHub Release URL, pushed commit, every Python distribution, and
112
+ every macOS DMG/checksum filename. On failure, report the exact command or job
113
+ and the next safe recovery action.
@@ -7,6 +7,7 @@ import argparse
7
7
  import email.parser
8
8
  import hashlib
9
9
  import json
10
+ import platform
10
11
  import re
11
12
  import subprocess
12
13
  import sys
@@ -307,6 +308,40 @@ def smoke_wheel(wheel: Path, version: str) -> None:
307
308
  run([str(installed_python), "-c", code])
308
309
 
309
310
 
311
+ def preflight_macos_app(version: str) -> dict[str, object]:
312
+ if sys.platform != "darwin":
313
+ raise SystemExit("the AgentBridge release preflight requires macOS for app validation")
314
+
315
+ architecture = platform.machine()
316
+ if architecture not in {"arm64", "x86_64"}:
317
+ raise SystemExit(f"unsupported macOS release architecture: {architecture}")
318
+
319
+ run(["swift", "test", "--package-path", "macos"])
320
+ run(["scripts/build_macos_app.sh"])
321
+
322
+ output = REPO_ROOT / "build" / "macos" / architecture
323
+ app = output / "AgentBridge.app"
324
+ dmg = output / f"AgentBridge-{version}-macos-{architecture}.dmg"
325
+ checksum = Path(f"{dmg}.sha256")
326
+ run(["scripts/verify_macos_app.sh", str(app)])
327
+
328
+ if not dmg.is_file() or not checksum.is_file():
329
+ raise SystemExit(f"macOS release artifacts are missing under {output}")
330
+ recorded_hash = checksum.read_text(encoding="utf-8").split(maxsplit=1)[0]
331
+ actual_hash = sha256(dmg)
332
+ if recorded_hash != actual_hash:
333
+ raise SystemExit(f"macOS DMG checksum mismatch: {dmg.name}")
334
+
335
+ result = {
336
+ "file": dmg.name,
337
+ "sha256": actual_hash,
338
+ "architecture": architecture,
339
+ "signing": "local preflight signature",
340
+ }
341
+ print(json.dumps({"macos_app": result}, indent=2))
342
+ return result
343
+
344
+
310
345
  def preflight(args: argparse.Namespace) -> None:
311
346
  version = args.version
312
347
  check_version(version)
@@ -342,6 +377,7 @@ def preflight(args: argparse.Namespace) -> None:
342
377
  ".codex/skills/build-release/scripts/release_build.py",
343
378
  ]
344
379
  )
380
+ macos_result = preflight_macos_app(version)
345
381
  with tempfile.TemporaryDirectory(prefix="agentbridge-release-") as directory:
346
382
  output = Path(directory) / "dist"
347
383
  run(["uv", "build", "--out-dir", str(output)])
@@ -356,7 +392,11 @@ def preflight(args: argparse.Namespace) -> None:
356
392
  smoke_wheel(wheels[0], version)
357
393
  print(
358
394
  json.dumps(
359
- {"package": PACKAGE_NAME, "version": version, "artifacts": results},
395
+ {
396
+ "package": PACKAGE_NAME,
397
+ "version": version,
398
+ "artifacts": results + [macos_result],
399
+ },
360
400
  indent=2,
361
401
  )
362
402
  )
@@ -10,6 +10,18 @@ updates:
10
10
  cooldown:
11
11
  default-days: 7
12
12
  open-pull-requests-limit: 5
13
+ groups:
14
+ security-updates:
15
+ applies-to: security-updates
16
+ patterns:
17
+ - "*"
18
+ minor-and-patch:
19
+ applies-to: version-updates
20
+ update-types:
21
+ - minor
22
+ - patch
23
+ patterns:
24
+ - "*"
13
25
 
14
26
  - package-ecosystem: github-actions
15
27
  directory: /
@@ -21,3 +33,10 @@ updates:
21
33
  cooldown:
22
34
  default-days: 7
23
35
  open-pull-requests-limit: 5
36
+ groups:
37
+ minor-and-patch:
38
+ update-types:
39
+ - minor
40
+ - patch
41
+ patterns:
42
+ - "*"
@@ -0,0 +1,52 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ merge_group:
9
+ types:
10
+ - checks_requested
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ test:
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ matrix:
20
+ python-version: ["3.12", "3.13"]
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
28
+ with:
29
+ enable-cache: true
30
+ cache-dependency-glob: "uv.lock"
31
+
32
+ - name: Set up Python ${{ matrix.python-version }}
33
+ run: uv python install ${{ matrix.python-version }}
34
+
35
+ - name: Install dependencies
36
+ run: uv sync --frozen --extra test --python ${{ matrix.python-version }}
37
+
38
+ - name: Audit dependencies
39
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} pip-audit
40
+
41
+ - name: Lint
42
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} ruff check agentbridge tests
43
+
44
+ - name: Run tests
45
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} pytest -q
46
+
47
+ - name: Smoke test CLI
48
+ run: uv run --frozen --python ${{ matrix.python-version }} agentbridge --help
49
+
50
+ - name: Build package
51
+ if: matrix.python-version == '3.12'
52
+ run: uv build
@@ -28,7 +28,7 @@ jobs:
28
28
  outputs:
29
29
  should-publish: ${{ steps.publish.outputs.should-publish }}
30
30
  steps:
31
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
32
  with:
33
33
  fetch-depth: 0
34
34
  persist-credentials: false
@@ -52,36 +52,51 @@ jobs:
52
52
  matrix:
53
53
  python-version: ["3.12", "3.13"]
54
54
  steps:
55
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
55
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
56
56
  with:
57
57
  persist-credentials: false
58
58
  - name: Install uv
59
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
59
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
60
60
  with:
61
61
  enable-cache: true
62
62
  cache-dependency-glob: "uv.lock"
63
63
  - name: Set up Python ${{ matrix.python-version }}
64
64
  run: uv python install ${{ matrix.python-version }}
65
65
  - name: Install dependencies
66
- run: uv sync --all-extras --python ${{ matrix.python-version }}
66
+ run: uv sync --frozen --extra test --python ${{ matrix.python-version }}
67
+ - name: Audit dependencies
68
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} pip-audit
69
+ - name: Lint
70
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} ruff check agentbridge tests
67
71
  - name: Run tests
68
- run: uv run --python ${{ matrix.python-version }} pytest tests/ -v --tb=short
72
+ run: uv run --frozen --extra test --python ${{ matrix.python-version }} pytest -q
69
73
 
70
74
  pii-scan:
71
75
  runs-on: ubuntu-latest
72
76
  permissions:
73
77
  contents: read
74
78
  steps:
75
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
79
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
76
80
  with:
77
81
  persist-credentials: false
78
82
  - name: Run gitleaks
79
- uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2
83
+ uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0
80
84
  env:
81
85
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82
86
 
87
+ macos-test:
88
+ runs-on: macos-15
89
+ permissions:
90
+ contents: read
91
+ steps:
92
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
93
+ with:
94
+ persist-credentials: false
95
+ - name: Test menu-bar app
96
+ run: swift test --package-path macos
97
+
83
98
  build:
84
- needs: [changes, test, pii-scan]
99
+ needs: [changes, test, pii-scan, macos-test]
85
100
  if: needs.changes.outputs.should-publish == 'true'
86
101
  runs-on: ubuntu-latest
87
102
  timeout-minutes: 15
@@ -91,7 +106,7 @@ jobs:
91
106
  publish: ${{ steps.check-version.outputs.tag_exists == 'false' }}
92
107
  tag: ${{ steps.check-version.outputs.tag }}
93
108
  steps:
94
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
109
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
95
110
  with:
96
111
  fetch-depth: 0
97
112
  persist-credentials: false
@@ -122,7 +137,7 @@ jobs:
122
137
  echo "Version ${version} maps to ${tag}; tag_exists=${tag_exists}"
123
138
  - name: Setup uv
124
139
  if: steps.check-version.outputs.tag_exists == 'false'
125
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
140
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
126
141
  with:
127
142
  enable-cache: true
128
143
  cache-dependency-glob: "uv.lock"
@@ -175,26 +190,126 @@ jobs:
175
190
  PY
176
191
  - name: Store package artifacts
177
192
  if: steps.check-version.outputs.tag_exists == 'false'
178
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
193
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
179
194
  with:
180
195
  name: python-package-${{ github.sha }}
181
196
  path: dist/
182
197
  if-no-files-found: error
183
198
  retention-days: 1
184
199
 
200
+ macos-app:
201
+ needs: [build]
202
+ if: >-
203
+ needs.build.outputs.publish == 'true' &&
204
+ vars.MACOS_RELEASE_ENABLED == 'true'
205
+ strategy:
206
+ fail-fast: false
207
+ matrix:
208
+ include:
209
+ - runner: macos-15
210
+ architecture: arm64
211
+ - runner: macos-15-intel
212
+ architecture: x86_64
213
+ runs-on: ${{ matrix.runner }}
214
+ timeout-minutes: 30
215
+ permissions:
216
+ contents: read
217
+ steps:
218
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
219
+ with:
220
+ persist-credentials: false
221
+ - name: Install uv
222
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
223
+ with:
224
+ enable-cache: true
225
+ cache-dependency-glob: "uv.lock"
226
+ - name: Install Python 3.12
227
+ run: uv python install 3.12
228
+ - name: Import Developer ID certificate
229
+ env:
230
+ APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
231
+ APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
232
+ KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
233
+ shell: bash
234
+ run: |
235
+ certificate_path="$RUNNER_TEMP/developer-id.p12"
236
+ keychain_path="$RUNNER_TEMP/agentbridge-signing.keychain-db"
237
+ echo "$APPLE_CERTIFICATE_BASE64" | base64 -D > "$certificate_path"
238
+ security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
239
+ security set-keychain-settings -lut 21600 "$keychain_path"
240
+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
241
+ security import "$certificate_path" \
242
+ -P "$APPLE_CERTIFICATE_PASSWORD" \
243
+ -A \
244
+ -t cert \
245
+ -f pkcs12 \
246
+ -k "$keychain_path"
247
+ security list-keychain -d user -s "$keychain_path"
248
+ security set-key-partition-list \
249
+ -S apple-tool:,apple: \
250
+ -s \
251
+ -k "$KEYCHAIN_PASSWORD" \
252
+ "$keychain_path"
253
+ identity="$(security find-identity -v -p codesigning "$keychain_path" \
254
+ | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' \
255
+ | head -1)"
256
+ test -n "$identity"
257
+ echo "CODE_SIGN_IDENTITY=$identity" >> "$GITHUB_ENV"
258
+ - name: Build signed application
259
+ run: scripts/build_macos_app.sh
260
+ - name: Verify embedded application
261
+ run: scripts/verify_macos_app.sh "build/macos/${{ matrix.architecture }}/AgentBridge.app"
262
+ - name: Notarize and staple disk image
263
+ env:
264
+ APPLE_ID: ${{ secrets.APPLE_NOTARY_APPLE_ID }}
265
+ APPLE_APP_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }}
266
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
267
+ shell: bash
268
+ run: |
269
+ dmg="$(find "build/macos/${{ matrix.architecture }}" -maxdepth 1 -name '*.dmg' -print -quit)"
270
+ test -n "$dmg"
271
+ xcrun notarytool submit "$dmg" \
272
+ --apple-id "$APPLE_ID" \
273
+ --password "$APPLE_APP_PASSWORD" \
274
+ --team-id "$APPLE_TEAM_ID" \
275
+ --wait
276
+ xcrun stapler staple "$dmg"
277
+ xcrun stapler validate "$dmg"
278
+ shasum -a 256 "$dmg" > "$dmg.sha256"
279
+ - name: Store macOS artifacts
280
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
281
+ with:
282
+ name: macos-app-${{ matrix.architecture }}-${{ github.sha }}
283
+ path: |
284
+ build/macos/${{ matrix.architecture }}/*.dmg
285
+ build/macos/${{ matrix.architecture }}/*.dmg.sha256
286
+ if-no-files-found: error
287
+ retention-days: 1
288
+
185
289
  release:
186
- needs: [build, publish]
187
- if: needs.build.outputs.publish == 'true'
290
+ needs: [build, publish, macos-app]
291
+ if: >-
292
+ always() &&
293
+ needs.build.outputs.publish == 'true' &&
294
+ needs.publish.result == 'success' &&
295
+ (needs.macos-app.result == 'success' || needs.macos-app.result == 'skipped')
188
296
  runs-on: ubuntu-latest
189
297
  timeout-minutes: 10
190
298
  permissions:
191
299
  contents: write
192
300
  steps:
193
301
  - name: Download package artifacts
194
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
302
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
195
303
  with:
196
304
  name: python-package-${{ github.sha }}
197
305
  path: dist/
306
+ - name: Download macOS artifacts
307
+ if: needs.macos-app.result == 'success'
308
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
309
+ with:
310
+ pattern: macos-app-*-${{ github.sha }}
311
+ path: dist/
312
+ merge-multiple: true
198
313
  - name: Create GitHub release
199
314
  run: gh release create "$TAG" --title "$TAG" --generate-notes dist/*
200
315
  env:
@@ -215,9 +330,9 @@ jobs:
215
330
  id-token: write
216
331
  steps:
217
332
  - name: Setup uv
218
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
333
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
219
334
  - name: Download package artifacts
220
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
335
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
221
336
  with:
222
337
  name: python-package-${{ github.sha }}
223
338
  path: dist/
@@ -54,4 +54,6 @@ logs/
54
54
  *$py.class
55
55
  .claude/settings.local.json
56
56
  .eggs/
57
+ .build/
58
+ .swiftpm/
57
59
  _build_info.py
@@ -1,10 +1,42 @@
1
+ Metadata-Version: 2.5
2
+ Name: agentbridge-cli
3
+ Version: 0.1.12
4
+ Summary: Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter
5
+ Project-URL: Homepage, https://github.com/tsilva/agentbridge
6
+ Project-URL: Repository, https://github.com/tsilva/agentbridge
7
+ Project-URL: Issues, https://github.com/tsilva/agentbridge/issues
8
+ Author: tsilva
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: anthropic,api,bridge,claude,claude-code,codex,fastapi,llm,openai,streaming
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: FastAPI
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: claude-agent-sdk>=0.2.132
21
+ Requires-Dist: fastapi>=0.141.1
22
+ Requires-Dist: jinja2>=3.1.0
23
+ Requires-Dist: openrouter==1.1.31
24
+ Requires-Dist: pillow>=12.3.0
25
+ Requires-Dist: uvicorn[standard]>=0.32.0
26
+ Provides-Extra: test
27
+ Requires-Dist: pip-audit>=2.9.0; extra == 'test'
28
+ Requires-Dist: pytest-asyncio>=1.4.0; extra == 'test'
29
+ Requires-Dist: pytest>=9.1.1; extra == 'test'
30
+ Requires-Dist: ruff>=0.15.0; extra == 'test'
31
+ Description-Content-Type: text/markdown
32
+
1
33
  <div align="center">
2
- <img src="./logo.png" alt="agentbridge" width="512" />
34
+ <img src="./logo.png" alt="AgentBridge" width="512" />
3
35
 
4
- **🌉 Bridge OpenAI tools to Claude Code SDK, Codex CLI, or OpenRouter — use your subscriptions anywhere 🔌**
36
+ **OpenAI-compatible routing for Claude Code, Codex, and OpenRouter — use your subscriptions anywhere.**
5
37
  </div>
6
38
 
7
- agentbridge is a local API bridge for developers who want to connect OpenAI-compatible apps to Claude Code, Codex, or OpenRouter. Run one server, choose a backend with a namespaced model ID, and point existing Chat Completions clients at `http://localhost:8082/api/v1`.
39
+ AgentBridge is a local API bridge for developers who want to connect OpenAI-compatible apps to Claude Code, Codex, or OpenRouter. Run one server, choose a backend with a namespaced model ID, and point existing Chat Completions clients at `http://localhost:8082/api/v1`.
8
40
 
9
41
  It supports streaming and non-streaming responses, image and PDF inputs where the backend accepts them, native Codex image editing, strict JSON Schema output, OpenAI-style tool calls, a live dashboard, and local JSON session logs.
10
42
 
@@ -12,6 +44,31 @@ It supports streaming and non-streaming responses, image and PDF inputs where th
12
44
 
13
45
  ## Install
14
46
 
47
+ ### macOS menu-bar app
48
+
49
+ Build the app locally on macOS 13 or later. This requires
50
+ [uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but it does
51
+ not require an Apple Developer account:
52
+
53
+ ```bash
54
+ git clone https://github.com/tsilva/agentbridge.git
55
+ cd agentbridge
56
+ scripts/build_macos_app.sh
57
+ open "build/macos/$(uname -m)/AgentBridge-"*.dmg
58
+ ```
59
+
60
+ Drag `AgentBridge.app` to Applications and open it. The menu-bar window shows
61
+ live server health and activity, starts and stops the local server, opens the
62
+ dashboard, and provides settings for the port, worker count, and launch at
63
+ login. See [`macos/README.md`](macos/README.md) for development instructions.
64
+
65
+ The app contains its own Python 3.12 runtime and AgentBridge dependencies. It
66
+ does not bundle the Claude Code or Codex executables: installed provider tools
67
+ and their existing authentication state remain in the user account. Mutable
68
+ configuration and logs continue to live under `~/.config/agentbridge/`.
69
+
70
+ ### Command line
71
+
15
72
  ```bash
16
73
  uv tool install agentbridge-cli
17
74
  agentbridge
@@ -97,14 +154,17 @@ agentbridge --workers 3 # set Claude pool and Code
97
154
  agentbridge --version # print package and git version
98
155
  uv run --frozen --extra test pytest -q # run tests
99
156
  uv run --frozen --extra test ruff check agentbridge tests # lint Python
157
+ swift test --package-path macos # test the macOS app
158
+ scripts/build_macos_app.sh # build a local signed app and DMG
100
159
  uv lock --check # verify the lockfile
101
160
  uv build # build wheel and source distribution
102
161
  ```
103
162
 
104
163
  ## Notes
105
164
 
106
- - Python 3.12+ and at least one authenticated backend are required.
165
+ - The CLI requires Python 3.12+; the macOS app bundles Python. At least one authenticated backend is required for provider requests.
107
166
  - Public routes include `POST /api/v1/chat/completions`, `POST /api/v1/images`, `GET /api/v1/models`, `GET /api/v1/capabilities`, `GET /health`, `/dashboard`, and `/dashboard/chat`.
167
+ - `GET /health` includes safe operator status used by the menu-bar app: version, start time, uptime, configured workers, active requests, and pool state when initialized.
108
168
  - `PORT`, `POOL_SIZE`, `CLAUDE_TIMEOUT`, `CODEX_TIMEOUT`, `CODEX_IMAGE_TIMEOUT`, and `OPENROUTER_TIMEOUT` control the server port, pool size, and provider timeouts. `--workers` overrides `POOL_SIZE`; Codex chat and native image generation default to 600-second timeouts, while Claude and OpenRouter default to 120 seconds.
109
169
  - `MAX_IMAGE_INPUT_BYTES`, `MAX_IMAGE_OUTPUT_BYTES`, and `MAX_IMAGE_PIXELS` bound native image requests. Defaults are 64 MiB input, 32 MiB output, and 40 million pixels.
110
170
  - `AGENTBRIDGE_CONFIG_DIR` moves the user configuration directory. `LOG_DIR` moves session logs, and `MAX_LOG_FILES` limits retained JSON logs.
@@ -116,7 +176,12 @@ uv build # build wheel and source d
116
176
 
117
177
  ## Publishing
118
178
 
119
- Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`, repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no PyPI API token is required. Releases through `0.1.10` remain available under the previous `agentbridge-py` distribution name.
179
+ Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing
180
+ for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`,
181
+ repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no
182
+ PyPI API token is required. GitHub Releases contain the Python distributions;
183
+ the macOS app is tested in CI and built locally from source. Releases through
184
+ `0.1.10` remain available under the previous `agentbridge-py` distribution name.
120
185
 
121
186
  ## Architecture
122
187