agentbridge-cli 0.1.12__tar.gz → 0.1.14__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.12 → agentbridge_cli-0.1.14}/.codex/skills/build-release/SKILL.md +13 -13
  2. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.codex/skills/build-release/scripts/release_build.py +4 -2
  3. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.github/workflows/release.yml +48 -54
  4. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/PKG-INFO +18 -11
  5. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/README.md +17 -10
  6. agentbridge_cli-0.1.14/agentbridge/_build_info.py +1 -0
  7. agentbridge_cli-0.1.14/design-qa/reference-inactive-menu-icons.png +0 -0
  8. agentbridge_cli-0.1.14/design-qa/reference-inactive-telegram-badge-normalized.png +0 -0
  9. agentbridge_cli-0.1.14/design-qa/reference-inactive-telegram-badge.png +0 -0
  10. agentbridge_cli-0.1.14/design-qa/reference-low-contrast-arrows-normalized.png +0 -0
  11. agentbridge_cli-0.1.14/design-qa/reference-low-contrast-arrows.png +0 -0
  12. agentbridge_cli-0.1.14/design-qa/reference-telegram-badge-normalized.png +0 -0
  13. agentbridge_cli-0.1.14/design-qa/reference-telegram-badge.png +0 -0
  14. agentbridge_cli-0.1.14/design-qa/status-item-active-workers.png +0 -0
  15. agentbridge_cli-0.1.14/design-qa/status-item-arrow-contrast-comparison.png +0 -0
  16. agentbridge_cli-0.1.14/design-qa/status-item-badge-comparison.png +0 -0
  17. agentbridge_cli-0.1.14/design-qa/status-item-inactive-comparison.png +0 -0
  18. agentbridge_cli-0.1.14/design-qa/status-item-no-workers.png +0 -0
  19. agentbridge_cli-0.1.14/design-qa.md +55 -0
  20. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/README.md +7 -3
  21. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/AgentBridgeMenuBarApp.swift +19 -14
  22. agentbridge_cli-0.1.14/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +135 -0
  23. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +1 -2
  24. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +74 -0
  25. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/pyproject.toml +1 -1
  26. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/scripts/build_macos_app.sh +9 -6
  27. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/uv.lock +1 -1
  28. agentbridge_cli-0.1.12/agentbridge/_build_info.py +0 -1
  29. agentbridge_cli-0.1.12/design-qa.md +0 -43
  30. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.codex/config.toml +0 -0
  31. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.codex/skills/build-release/agents/openai.yaml +0 -0
  32. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.env.example +0 -0
  33. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.github/dependabot.yml +0 -0
  34. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.github/workflows/ci.yml +0 -0
  35. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.github/workflows/dependency-review.yml +0 -0
  36. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/.gitignore +0 -0
  37. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/AGENTS.md +0 -0
  38. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/CLAUDE.md +0 -0
  39. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/LICENSE +0 -0
  40. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/Makefile +0 -0
  41. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/TODO.txt +0 -0
  42. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/__init__.py +0 -0
  43. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/config.py +0 -0
  44. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/dashboard.py +0 -0
  45. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/models.py +0 -0
  46. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/pool.py +0 -0
  47. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/server.py +0 -0
  48. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/android-chrome-192.png +0 -0
  49. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/android-chrome-512.png +0 -0
  50. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/apple-touch-icon.png +0 -0
  51. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/favicon-16.png +0 -0
  52. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/favicon-32.png +0 -0
  53. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/favicon-48.png +0 -0
  54. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/favicon.ico +0 -0
  55. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/favicon.svg +0 -0
  56. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/static/brand/site.webmanifest +0 -0
  57. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/base.html +0 -0
  58. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/chat.html +0 -0
  59. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/detail.html +0 -0
  60. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/page.html +0 -0
  61. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/pool.html +0 -0
  62. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/agentbridge/templates/dashboard/requests.html +0 -0
  63. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/architecture.png +0 -0
  64. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/agentbridge-popover-final.png +0 -0
  65. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/agentbridge-popover-normalized.png +0 -0
  66. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
  67. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/implementation-header-activity.png +0 -0
  68. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/reference-header-activity.png +0 -0
  69. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/design-qa/reference-panel.png +0 -0
  70. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/docs/plans/2026-02-14-dashboard-design.md +0 -0
  71. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
  72. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/hatch_build.py +0 -0
  73. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/apple-store/app-store-icon-1024.png +0 -0
  74. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/icon/icon-1024.png +0 -0
  75. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/logo/logo-1024.png +0 -0
  76. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/manifest.json +0 -0
  77. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/icon-source-keyed.png +0 -0
  78. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/icon-source.png +0 -0
  79. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/logo-source-keyed.png +0 -0
  80. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/logo-source.png +0 -0
  81. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/social-background-source.png +0 -0
  82. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/sources/social-source.png +0 -0
  83. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/android-chrome-192.png +0 -0
  84. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/android-chrome-512.png +0 -0
  85. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/apple-touch-icon.png +0 -0
  86. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/favicon/favicon-16.png +0 -0
  87. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/favicon/favicon-32.png +0 -0
  88. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/favicon/favicon-48.png +0 -0
  89. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/favicon/favicon.ico +0 -0
  90. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/favicon/favicon.svg +0 -0
  91. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/og-image-1200x630.png +0 -0
  92. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/image-assets/web-seo/site.webmanifest +0 -0
  93. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/logo.png +0 -0
  94. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Package.swift +0 -0
  95. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +0 -0
  96. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +0 -0
  97. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/ServerController.swift +0 -0
  98. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +0 -0
  99. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +0 -0
  100. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +0 -0
  101. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/scripts/dashboard_load_test.py +0 -0
  102. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/scripts/verify_macos_app.sh +0 -0
  103. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/fixtures/ocr_test_document.png +0 -0
  104. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_config.py +0 -0
  105. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_dashboard.py +0 -0
  106. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_dependency_security.py +0 -0
  107. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_image_utils.py +0 -0
  108. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_model_mapping.py +0 -0
  109. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_models.py +0 -0
  110. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_pool.py +0 -0
  111. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_server.py +0 -0
  112. {agentbridge_cli-0.1.12 → agentbridge_cli-0.1.14}/tests/test_session_logger.py +0 -0
@@ -9,8 +9,7 @@ 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
- publishes `agentbridge-cli`, and, when macOS publishing is enabled, attaches
13
- signed and notarized arm64 and x86_64 DMGs.
12
+ publishes `agentbridge-cli`, and attaches an ad-hoc-signed arm64 DMG.
14
13
 
15
14
  Use the next unused patch version unless the user requests another valid,
16
15
  unused semantic version. Treat an untagged version absent from PyPI as pending.
@@ -29,12 +28,8 @@ git log --oneline HEAD..origin/main
29
28
  Stop on unrelated changes, unpublished commits, divergence, or another branch.
30
29
  Do not clean, pull, commit unrelated files, or switch branches.
31
30
 
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.
31
+ The macOS artifacts use an ad-hoc signature and are not notarized. They do not
32
+ require Apple Developer credentials or repository secrets.
38
33
 
39
34
  2. Select the release version from the repository root:
40
35
 
@@ -59,8 +54,8 @@ The preflight requires macOS. It checks consistent project and lock metadata, an
59
54
  unused PyPI version and tag, clean patch formatting, a frozen lock, Python 3.12
60
55
  and 3.13 tests, Ruff, Swift tests, a self-contained app/DMG build for the current
61
56
  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.
57
+ sdist audits, and a wheel installation smoke test. CI builds the arm64 macOS
58
+ artifact with an ad-hoc signature. Stop at the exact failed gate.
64
59
 
65
60
  4. Review and publish the release commit:
66
61
 
@@ -97,14 +92,19 @@ python3 .codex/skills/build-release/scripts/release_build.py wait-pypi --version
97
92
  gh release view v<version> --json url,tagName,assets
98
93
  ```
99
94
 
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
95
+ Require `AgentBridge-<version>-macos-arm64.dmg` and its `.sha256` file in the
103
96
  release assets. Do not report success until PyPI returns exact-version files and
104
97
  all required GitHub assets exist. If the workflow fails, inspect
105
98
  `gh run view <run-id> --log-failed` and report the failed gate before considering
106
99
  recovery.
107
100
 
101
+ If an existing release is missing only its macOS assets, attach them without
102
+ republishing Python distributions:
103
+
104
+ ```bash
105
+ gh workflow run release.yml --ref main -f attach_macos=true
106
+ ```
107
+
108
108
  ## Final Response
109
109
 
110
110
  Lead with the exact PyPI version URL. Report the tag, release workflow URL and
@@ -313,8 +313,10 @@ def preflight_macos_app(version: str) -> dict[str, object]:
313
313
  raise SystemExit("the AgentBridge release preflight requires macOS for app validation")
314
314
 
315
315
  architecture = platform.machine()
316
- if architecture not in {"arm64", "x86_64"}:
317
- raise SystemExit(f"unsupported macOS release architecture: {architecture}")
316
+ if architecture != "arm64":
317
+ raise SystemExit(
318
+ f"unsupported macOS release architecture: {architecture}; AgentBridge requires arm64"
319
+ )
318
320
 
319
321
  run(["swift", "test", "--package-path", "macos"])
320
322
  run(["scripts/build_macos_app.sh"])
@@ -8,6 +8,11 @@ on:
8
8
  required: false
9
9
  default: false
10
10
  type: boolean
11
+ attach_macos:
12
+ description: Build and attach macOS DMGs to the current version's existing release
13
+ required: false
14
+ default: false
15
+ type: boolean
11
16
  push:
12
17
  branches: [main]
13
18
  paths:
@@ -200,16 +205,15 @@ jobs:
200
205
  macos-app:
201
206
  needs: [build]
202
207
  if: >-
203
- needs.build.outputs.publish == 'true' &&
204
- vars.MACOS_RELEASE_ENABLED == 'true'
208
+ always() &&
209
+ (needs.build.outputs.publish == 'true' ||
210
+ (github.event_name == 'workflow_dispatch' && inputs.attach_macos == true))
205
211
  strategy:
206
212
  fail-fast: false
207
213
  matrix:
208
214
  include:
209
215
  - runner: macos-15
210
216
  architecture: arm64
211
- - runner: macos-15-intel
212
- architecture: x86_64
213
217
  runs-on: ${{ matrix.runner }}
214
218
  timeout-minutes: 30
215
219
  permissions:
@@ -225,57 +229,10 @@ jobs:
225
229
  cache-dependency-glob: "uv.lock"
226
230
  - name: Install Python 3.12
227
231
  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
232
+ - name: Build ad-hoc-signed application
259
233
  run: scripts/build_macos_app.sh
260
234
  - name: Verify embedded application
261
235
  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
236
  - name: Store macOS artifacts
280
237
  uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
281
238
  with:
@@ -292,7 +249,7 @@ jobs:
292
249
  always() &&
293
250
  needs.build.outputs.publish == 'true' &&
294
251
  needs.publish.result == 'success' &&
295
- (needs.macos-app.result == 'success' || needs.macos-app.result == 'skipped')
252
+ needs.macos-app.result == 'success'
296
253
  runs-on: ubuntu-latest
297
254
  timeout-minutes: 10
298
255
  permissions:
@@ -304,7 +261,6 @@ jobs:
304
261
  name: python-package-${{ github.sha }}
305
262
  path: dist/
306
263
  - name: Download macOS artifacts
307
- if: needs.macos-app.result == 'success'
308
264
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
309
265
  with:
310
266
  pattern: macos-app-*-${{ github.sha }}
@@ -317,6 +273,44 @@ jobs:
317
273
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
318
274
  TAG: ${{ needs.build.outputs.tag }}
319
275
 
276
+ attach-macos:
277
+ needs: [macos-app]
278
+ if: >-
279
+ always() &&
280
+ github.event_name == 'workflow_dispatch' &&
281
+ inputs.attach_macos == true &&
282
+ needs.macos-app.result == 'success'
283
+ runs-on: ubuntu-latest
284
+ timeout-minutes: 10
285
+ permissions:
286
+ contents: write
287
+ steps:
288
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
289
+ with:
290
+ persist-credentials: false
291
+ - name: Download macOS artifacts
292
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
293
+ with:
294
+ pattern: macos-app-*-${{ github.sha }}
295
+ path: dist/
296
+ merge-multiple: true
297
+ - name: Attach DMGs to the existing release
298
+ shell: bash
299
+ run: |
300
+ version="$(python - <<'PY'
301
+ import tomllib
302
+
303
+ with open("pyproject.toml", "rb") as pyproject_file:
304
+ print(tomllib.load(pyproject_file)["project"]["version"])
305
+ PY
306
+ )"
307
+ tag="v${version}"
308
+ gh release view "$tag" >/dev/null
309
+ gh release upload "$tag" dist/* --clobber
310
+ env:
311
+ GH_REPO: ${{ github.repository }}
312
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
313
+
320
314
  publish:
321
315
  needs: [build]
322
316
  if: needs.build.outputs.publish == 'true'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentbridge-cli
3
- Version: 0.1.12
3
+ Version: 0.1.14
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
@@ -46,9 +46,14 @@ It supports streaming and non-streaming responses, image and PDF inputs where th
46
46
 
47
47
  ### macOS menu-bar app
48
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:
49
+ On an Apple silicon Mac, download the arm64 DMG from the GitHub Release, drag
50
+ `AgentBridge.app` to Applications, and open it. The app is ad-hoc signed rather
51
+ than Apple-notarized, so on first launch macOS may require you to Control-click
52
+ the app, choose **Open**, and confirm. Intel Macs are not supported.
53
+
54
+ You can also build the app locally on macOS 13 or later. This requires
55
+ [uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but not an
56
+ Apple Developer account:
52
57
 
53
58
  ```bash
54
59
  git clone https://github.com/tsilva/agentbridge.git
@@ -57,10 +62,10 @@ scripts/build_macos_app.sh
57
62
  open "build/macos/$(uname -m)/AgentBridge-"*.dmg
58
63
  ```
59
64
 
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.
65
+ The menu-bar window shows live server health and activity, starts and stops the
66
+ local server, opens the dashboard, and provides settings for the port, worker
67
+ count, and launch at login. See [`macos/README.md`](macos/README.md) for
68
+ development instructions.
64
69
 
65
70
  The app contains its own Python 3.12 runtime and AgentBridge dependencies. It
66
71
  does not bundle the Claude Code or Codex executables: installed provider tools
@@ -179,9 +184,11 @@ uv build # build wheel and source d
179
184
  Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing
180
185
  for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`,
181
186
  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.
187
+ PyPI API token is required. GitHub Releases contain the Python distributions
188
+ plus an ad-hoc-signed arm64 macOS DMG and SHA-256 checksum. The DMG is not
189
+ Apple-notarized and requires no Apple Developer credentials. Releases
190
+ through `0.1.10` remain available under the previous `agentbridge-py`
191
+ distribution name.
185
192
 
186
193
  ## Architecture
187
194
 
@@ -14,9 +14,14 @@ It supports streaming and non-streaming responses, image and PDF inputs where th
14
14
 
15
15
  ### macOS menu-bar app
16
16
 
17
- Build the app locally on macOS 13 or later. This requires
18
- [uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but it does
19
- not require an Apple Developer account:
17
+ On an Apple silicon Mac, download the arm64 DMG from the GitHub Release, drag
18
+ `AgentBridge.app` to Applications, and open it. The app is ad-hoc signed rather
19
+ than Apple-notarized, so on first launch macOS may require you to Control-click
20
+ the app, choose **Open**, and confirm. Intel Macs are not supported.
21
+
22
+ You can also build the app locally on macOS 13 or later. This requires
23
+ [uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but not an
24
+ Apple Developer account:
20
25
 
21
26
  ```bash
22
27
  git clone https://github.com/tsilva/agentbridge.git
@@ -25,10 +30,10 @@ scripts/build_macos_app.sh
25
30
  open "build/macos/$(uname -m)/AgentBridge-"*.dmg
26
31
  ```
27
32
 
28
- Drag `AgentBridge.app` to Applications and open it. The menu-bar window shows
29
- live server health and activity, starts and stops the local server, opens the
30
- dashboard, and provides settings for the port, worker count, and launch at
31
- login. See [`macos/README.md`](macos/README.md) for development instructions.
33
+ The menu-bar window shows live server health and activity, starts and stops the
34
+ local server, opens the dashboard, and provides settings for the port, worker
35
+ count, and launch at login. See [`macos/README.md`](macos/README.md) for
36
+ development instructions.
32
37
 
33
38
  The app contains its own Python 3.12 runtime and AgentBridge dependencies. It
34
39
  does not bundle the Claude Code or Codex executables: installed provider tools
@@ -147,9 +152,11 @@ uv build # build wheel and source d
147
152
  Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing
148
153
  for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`,
149
154
  repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no
150
- PyPI API token is required. GitHub Releases contain the Python distributions;
151
- the macOS app is tested in CI and built locally from source. Releases through
152
- `0.1.10` remain available under the previous `agentbridge-py` distribution name.
155
+ PyPI API token is required. GitHub Releases contain the Python distributions
156
+ plus an ad-hoc-signed arm64 macOS DMG and SHA-256 checksum. The DMG is not
157
+ Apple-notarized and requires no Apple Developer credentials. Releases
158
+ through `0.1.10` remain available under the previous `agentbridge-py`
159
+ distribution name.
153
160
 
154
161
  ## Architecture
155
162
 
@@ -0,0 +1 @@
1
+ GIT_HASH = "0980cbb"
@@ -0,0 +1,55 @@
1
+ # Design QA
2
+
3
+ **Comparison target**
4
+
5
+ - Source visual truth: `/var/folders/wz/x29jb7_x5rdc_5dcjr4qnhg00000gn/T/codex-clipboard-5d0ece7b-8e7b-489f-8d94-28b6877699ba.png`
6
+ - Implementation screenshot: `/tmp/agentbridge-popover-neutral-20260829.png`
7
+ - Combined comparison: `/tmp/agentbridge-popover-comparison-20260829.png`
8
+ - State: connected, zero active requests, one worker, dark appearance.
9
+ - Viewport: native macOS status popover at its fixed 350-point content width.
10
+ - Source pixels: 818 × 404. Implementation pixels: 752 × 444. Both are native high-density captures; no density normalization was applied because this change is limited to the visible control colors rather than geometry.
11
+
12
+ **Full-view comparison evidence**
13
+
14
+ - The source shows the gear and Open Dashboard control inheriting the green brand tint.
15
+ - The implementation shows both controls in the same neutral secondary-label palette used by the refresh row and supporting text.
16
+ - The native screenshot API renders the vibrancy material with a pink capture artifact; this does not affect the visible verification that the two controls no longer use the green tint.
17
+
18
+ **Focused region comparison evidence**
19
+
20
+ - A separate crop was not needed: the settings icon and dashboard button are large and clearly readable in the combined full-view comparison.
21
+
22
+ **Required fidelity surfaces**
23
+
24
+ - Fonts and typography: unchanged.
25
+ - Spacing and layout rhythm: unchanged.
26
+ - Colors and visual tokens: the popover-wide control tint now uses the native secondary-label color. The logo, connected indicator, and activity fill retain their intentional brand/status colors.
27
+ - Image quality and asset fidelity: unchanged; the existing native brand mark and SF Symbols remain in use.
28
+ - Copy and content: unchanged.
29
+
30
+ **Findings**
31
+
32
+ - No actionable P0, P1, or P2 mismatches remain for the requested control-color change.
33
+
34
+ **Open Questions**
35
+
36
+ - None.
37
+
38
+ **Implementation Checklist**
39
+
40
+ - [x] Remove the green tint from popover controls.
41
+ - [x] Preserve brand and semantic status colors.
42
+ - [x] Build and run the native test suite.
43
+ - [x] Capture and compare the rendered popover.
44
+
45
+ **Comparison History**
46
+
47
+ - Initial source finding: the settings icon and dashboard button inherited the green popover-wide tint.
48
+ - Fix: changed the popover tint to the native secondary-label color.
49
+ - Post-fix evidence: the combined comparison shows both controls rendered in neutral gray, with the brand and status colors preserved.
50
+
51
+ **Follow-up Polish**
52
+
53
+ - None.
54
+
55
+ final result: passed
@@ -32,12 +32,16 @@ scripts/build_macos_app.sh
32
32
 
33
33
  The script builds the Swift executable, embeds a uv-managed Python 3.12 runtime
34
34
  and the locked AgentBridge dependencies, applies an ad-hoc signature for local
35
- use, and creates a DMG for the current Mac architecture under
36
- `build/macos/<architecture>/`. Building and running this local app does not
37
- require an Apple Developer account.
35
+ use, and creates an arm64 DMG under `build/macos/arm64/`. Building and running
36
+ this local app requires an Apple silicon Mac but does not require an Apple
37
+ Developer account.
38
38
 
39
39
  Open the generated DMG and drag `AgentBridge.app` to Applications.
40
40
 
41
+ GitHub Releases provide the same ad-hoc-signed DMG for Apple silicon Macs. It is
42
+ not Apple-notarized, so macOS may require you to Control-click the app, choose
43
+ **Open**, and confirm on first launch. Intel Macs are not supported.
44
+
41
45
  Mutable data stays outside the application bundle:
42
46
 
43
47
  ```text
@@ -26,8 +26,9 @@ struct AgentBridgeMenuBarApp: App {
26
26
  final class AgentBridgeAppDelegate: NSObject, NSApplicationDelegate {
27
27
  private let controller = ServerController()
28
28
  private let popover = NSPopover()
29
+ private let statusPresenter = MenuBarStatusPresenter()
29
30
  private var statusItem: NSStatusItem?
30
- private var phaseObservation: AnyCancellable?
31
+ private var statusObservation: AnyCancellable?
31
32
  #if DEBUG
32
33
  private var debugAnchorWindow: NSWindow?
33
34
  #endif
@@ -39,18 +40,26 @@ final class AgentBridgeAppDelegate: NSObject, NSApplicationDelegate {
39
40
  if let button = item.button {
40
41
  button.target = self
41
42
  button.action = #selector(togglePopover(_:))
43
+ statusPresenter.install(on: button)
44
+ statusPresenter.update(
45
+ button: button,
46
+ phase: controller.phase,
47
+ activeWorkers: controller.activeRequests
48
+ )
42
49
  }
43
- updateStatusItem(for: controller.phase)
44
50
 
45
51
  let host = NSHostingController(rootView: StatusPopover(controller: controller))
46
52
  popover.contentViewController = host
47
53
  popover.behavior = .transient
48
54
  popover.animates = true
49
55
 
50
- phaseObservation = controller.$phase
56
+ statusObservation = Publishers.CombineLatest(controller.$phase, controller.$health)
51
57
  .receive(on: RunLoop.main)
52
- .sink { [weak self] phase in
53
- self?.updateStatusItem(for: phase)
58
+ .sink { [weak self] phase, health in
59
+ self?.updateStatusItem(
60
+ for: phase,
61
+ activeWorkers: health?.activeRequests ?? 0
62
+ )
54
63
  }
55
64
 
56
65
  controller.begin()
@@ -84,17 +93,13 @@ final class AgentBridgeAppDelegate: NSObject, NSApplicationDelegate {
84
93
  }
85
94
  }
86
95
 
87
- private func updateStatusItem(for phase: ServerPhase) {
96
+ private func updateStatusItem(for phase: ServerPhase, activeWorkers: Int) {
88
97
  guard let button = statusItem?.button else { return }
89
- let label = "AgentBridge: \(phase.label)"
90
- let image = NSImage(
91
- systemSymbolName: phase.menuBarSymbol,
92
- accessibilityDescription: label
98
+ statusPresenter.update(
99
+ button: button,
100
+ phase: phase,
101
+ activeWorkers: activeWorkers
93
102
  )
94
- image?.isTemplate = true
95
- button.image = image
96
- button.toolTip = label
97
- button.setAccessibilityLabel(label)
98
103
  }
99
104
 
100
105
  #if DEBUG
@@ -0,0 +1,135 @@
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
+ }
@@ -32,12 +32,11 @@ struct StatusPopover: View {
32
32
  .padding(.bottom, 16)
33
33
  .frame(width: 350)
34
34
  .fixedSize(horizontal: false, vertical: true)
35
- .tint(AgentBridgeBrand.fir)
35
+ .tint(secondaryTextColor)
36
36
  }
37
37
 
38
38
  private var header: some View {
39
39
  HStack(spacing: 8) {
40
- AgentBridgeBrandMark(size: 24)
41
40
  Text("AgentBridge")
42
41
  .font(.system(size: 17, weight: .bold))
43
42
  Spacer()
@@ -1,3 +1,4 @@
1
+ import AppKit
1
2
  import Foundation
2
3
  import XCTest
3
4
  @testable import AgentBridgeMenuBar
@@ -71,4 +72,77 @@ final class StatusModelsTests: XCTestCase {
71
72
  XCTAssertTrue(paths.contains("/Users/example/.local/bin"))
72
73
  XCTAssertTrue(paths.contains("/Users/example/.npm-global/bin"))
73
74
  }
75
+
76
+ @MainActor
77
+ func testMenuBarBadgeIsHiddenWithoutActiveWorkers() throws {
78
+ let (canvas, button, presenter) = makeMenuBarFixture(activeWorkers: 0)
79
+
80
+ XCTAssertTrue(presenter.badgeView.isHidden)
81
+ XCTAssertNil(presenter.badgeView.displayedCount)
82
+ XCTAssertEqual(button.toolTip, "AgentBridge: Running")
83
+
84
+ try writeSnapshot(
85
+ of: canvas,
86
+ requestedBy: "AGENTBRIDGE_STATUS_ITEM_ZERO_SNAPSHOT_PATH"
87
+ )
88
+ }
89
+
90
+ @MainActor
91
+ func testMenuBarBadgeShowsActiveWorkerCount() throws {
92
+ let (canvas, button, presenter) = makeMenuBarFixture(activeWorkers: 48)
93
+
94
+ XCTAssertFalse(presenter.badgeView.isHidden)
95
+ XCTAssertEqual(presenter.badgeView.displayedCount, 48)
96
+ XCTAssertEqual(button.toolTip, "AgentBridge: Running, 48 active workers")
97
+ XCTAssertEqual(button.image?.isTemplate, false)
98
+
99
+ try writeSnapshot(
100
+ of: canvas,
101
+ requestedBy: "AGENTBRIDGE_STATUS_ITEM_SNAPSHOT_PATH"
102
+ )
103
+ }
104
+
105
+ @MainActor
106
+ private func makeMenuBarFixture(
107
+ activeWorkers: Int
108
+ ) -> (NSView, NSStatusBarButton, MenuBarStatusPresenter) {
109
+ let canvas = NSView(frame: NSRect(x: 0, y: 0, width: 48, height: 31))
110
+ canvas.appearance = NSAppearance(named: .darkAqua)
111
+ canvas.wantsLayer = true
112
+ canvas.layer?.backgroundColor = NSColor(
113
+ calibratedRed: 0.01,
114
+ green: 0.22,
115
+ blue: 0.19,
116
+ alpha: 1
117
+ ).cgColor
118
+
119
+ let button = NSStatusBarButton(frame: NSRect(x: 8, y: 4, width: 32, height: 22))
120
+ button.isBordered = false
121
+ canvas.addSubview(button)
122
+ let presenter = MenuBarStatusPresenter()
123
+ presenter.install(on: button)
124
+ presenter.update(
125
+ button: button,
126
+ phase: .runningManaged,
127
+ activeWorkers: activeWorkers
128
+ )
129
+ return (canvas, button, presenter)
130
+ }
131
+
132
+ @MainActor
133
+ private func writeSnapshot(of view: NSView, requestedBy environmentKey: String) throws {
134
+ guard let snapshotPath = ProcessInfo.processInfo.environment[environmentKey] else {
135
+ return
136
+ }
137
+
138
+ view.layoutSubtreeIfNeeded()
139
+ let representation = try XCTUnwrap(
140
+ view.bitmapImageRepForCachingDisplay(in: view.bounds)
141
+ )
142
+ view.cacheDisplay(in: view.bounds, to: representation)
143
+ let data = try XCTUnwrap(
144
+ representation.representation(using: .png, properties: [:])
145
+ )
146
+ try data.write(to: URL(fileURLWithPath: snapshotPath), options: .atomic)
147
+ }
74
148
  }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentbridge-cli"
3
- version = "0.1.12"
3
+ version = "0.1.14"
4
4
  description = "Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -23,11 +23,11 @@ with Path("pyproject.toml").open("rb") as file:
23
23
  PY
24
24
  )"
25
25
 
26
- case "${architecture}" in
27
- arm64) artifact_architecture="arm64" ;;
28
- x86_64) artifact_architecture="x86_64" ;;
29
- *) echo "Unsupported macOS architecture: ${architecture}" >&2; exit 1 ;;
30
- esac
26
+ if [[ "${architecture}" != "arm64" ]]; then
27
+ echo "Unsupported macOS architecture: ${architecture}; AgentBridge requires arm64" >&2
28
+ exit 1
29
+ fi
30
+ artifact_architecture="arm64"
31
31
 
32
32
  if [[ "${output_root}" != "${repository_root}"/build/macos/* ]]; then
33
33
  echo "Refusing to replace unexpected build directory: ${output_root}" >&2
@@ -150,7 +150,10 @@ hdiutil create \
150
150
  -ov \
151
151
  "${dmg_path}" >/dev/null
152
152
 
153
- shasum -a 256 "${dmg_path}" > "${dmg_path}.sha256"
153
+ (
154
+ cd "$(dirname "${dmg_path}")"
155
+ shasum -a 256 "$(basename "${dmg_path}")" > "$(basename "${dmg_path}").sha256"
156
+ )
154
157
 
155
158
  echo "Application: ${app_path}"
156
159
  echo "Disk image: ${dmg_path}"
@@ -37,7 +37,7 @@ constraints = [
37
37
 
38
38
  [[package]]
39
39
  name = "agentbridge-cli"
40
- version = "0.1.12"
40
+ version = "0.1.14"
41
41
  source = { editable = "." }
42
42
  dependencies = [
43
43
  { name = "claude-agent-sdk" },
@@ -1 +0,0 @@
1
- GIT_HASH = "738d069"
@@ -1,43 +0,0 @@
1
- # AgentBridge refresh-footer design QA
2
-
3
- ## Evidence
4
-
5
- - Source visual truth: right-hand footer in `/var/folders/wz/x29jb7_x5rdc_5dcjr4qnhg00000gn/T/codex-clipboard-7372d7c5-9ea8-42d9-9f84-41b99c9c9e24.png`
6
- - Source pixels: 1540 × 388 at Retina density
7
- - Implementation: `/Applications/AgentBridge.app`
8
- - Implementation screenshot: pending user-provided capture
9
- - Viewport: native macOS status popover, 350-point content width, Retina display
10
- - State to capture: running server with footer showing `Updated now`
11
-
12
- ## Findings
13
-
14
- - [Blocked] The revised app is built, installed, and running, but post-fix visual evidence is pending because the user requested that Computer Use not be used and will provide screenshots directly.
15
- - Functional structure: the icon and update label are now one plain clickable refresh control with an accessible combined label.
16
- - Fonts and typography: the update label now uses 13-point medium system text to match the reference's optical weight.
17
- - Spacing and layout rhythm: icon-to-label spacing is reduced from 12 to 9 points and the symbol is constrained to a 16-point slot, matching the compact reference grouping.
18
- - Colors and visual tokens: icon and label share the same semantic secondary-label color.
19
- - Image quality and assets: the refresh mark uses the native `arrow.clockwise` SF Symbol at 15-point regular weight; no custom-drawn asset is used.
20
- - Copy and content: relative update copy is unchanged and continues to show `Updated now` immediately after refresh.
21
-
22
- ## Implementation Checklist
23
-
24
- - [x] Match the reference refresh symbol family.
25
- - [x] Match icon size and regular stroke weight.
26
- - [x] Tighten icon-to-label spacing.
27
- - [x] Increase label optical weight to medium.
28
- - [x] Apply one muted semantic color to the icon and copy.
29
- - [x] Preserve refresh interaction and improve its accessibility label.
30
- - [x] Run Swift tests and patch-format validation.
31
- - [x] Build, sign, verify, install, and launch the updated app.
32
- - [ ] Compare a user-provided post-fix screenshot against the right-hand reference.
33
-
34
- ## Comparison History
35
-
36
- 1. Source evidence showed the implementation label lighter than the target and the icon-to-label gap materially wider; the refresh icon also read smaller and less balanced.
37
- 2. The implementation now uses a 15-point regular symbol in a 16-point slot, 9-point spacing, and 13-point medium text in one aligned control. Automated tests and bundle verification pass; visual comparison awaits the user capture.
38
-
39
- ## Follow-up Polish
40
-
41
- - None classified until the post-fix screenshot is available.
42
-
43
- final result: blocked